refactor(테이블타입): backend INSERT/UPDATE 8개 validate 백스톱

- TableManagementService.normalizeInputType(value, context) 오버로드 — user-insert/user-update-type 만 8개 검증, user-update-other/system-normalize 는 skip
- TableManagementService.updateColumnSettings: payload 의 input_type 키 존재 여부로 context 분기 (input_type 자체 변경 vs 다른 속성 변경)
- DdlService.addColumn / saveColumnMetadata: convertToInputType 결과를 USER_SELECTABLE_INPUT_TYPES (8개) 와 대조, 외이면 IllegalArgumentException

mapper XML 5곳 (categoryTree / entityJoin / tableCategoryValue / screenManagement / tableManagement / entityReference) 무변경 — READ 경로 12개 그대로.

spec: .omc/specs/deep-dive-table-type-storage-ui-separation.md (v3.2 §6.3)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-13 14:43:41 +09:00
parent 8f92fb2368
commit 574319811c
2 changed files with 49 additions and 4 deletions
@@ -39,6 +39,12 @@ public class DdlService extends BaseService {
"id", "created_date", "updated_date", "company_code"
);
/** 사용자가 신규 추가하는 컬럼에 허용되는 INPUT_TYPE 8종 (백엔드 백스톱) */
private static final Set<String> USER_SELECTABLE_INPUT_TYPES = Set.of(
"text", "number", "date", "code", "entity",
"numbering", "file", "image"
);
public DdlService(JdbcTemplate jdbcTemplate, PlatformTransactionManager transactionManager) {
this.jdbcTemplate = jdbcTemplate;
this.transactionTemplate = new TransactionTemplate(transactionManager);
@@ -140,6 +146,12 @@ public class DdlService extends BaseService {
transactionTemplate.execute(status -> {
jdbcTemplate.execute(ddlQuery);
String inputType = convertToInputType(column);
if (!USER_SELECTABLE_INPUT_TYPES.contains(inputType)) {
throw new IllegalArgumentException(
"INPUT_TYPE 은 다음 8개 중 하나여야 합니다: " + USER_SELECTABLE_INPUT_TYPES
+ " (받은 값: " + inputType + ")"
);
}
String detailSettings = column.containsKey("detail_settings")
? column.get("detail_settings").toString() : "{}";
Integer maxOrder = jdbcTemplate.queryForObject(
@@ -408,10 +420,17 @@ public class DdlService extends BaseService {
// 사용자 정의 컬럼
for (int i = 0; i < columns.size(); i++) {
Map<String, Object> col = columns.get(i);
String inputType = convertToInputType(col);
if (!USER_SELECTABLE_INPUT_TYPES.contains(inputType)) {
throw new IllegalArgumentException(
"INPUT_TYPE 은 다음 8개 중 하나여야 합니다: " + USER_SELECTABLE_INPUT_TYPES
+ " (받은 값: " + inputType + ")"
);
}
String detailSettings = col.containsKey("detail_settings")
? col.get("detail_settings").toString() : "{}";
saveColumnMeta(tableName, (String) col.get("name"), companyCode,
convertToInputType(col), detailSettings, i);
inputType, detailSettings, i);
}
}
@@ -26,6 +26,12 @@ public class TableManagementService extends BaseService {
private static final String NS = "tableManagement.";
/** 사용자가 직접 선택 가능한 INPUT_TYPE 8종 (INSERT/UPDATE-type 검증용) */
private static final Set<String> USER_SELECTABLE_INPUT_TYPES = Set.of(
"text", "number", "date", "code", "entity",
"numbering", "file", "image"
);
// ──────────────────────────────────────────────────
// 테이블 목록
// ──────────────────────────────────────────────────
@@ -145,7 +151,9 @@ public class TableManagementService extends BaseService {
Map<String, Object> settings, String companyCode) {
ensureTableInLabels(tableName);
String inputType = normalizeInputType((String) settings.get("input_type"));
boolean inputTypeChanged = settings.containsKey("input_type");
String ctx = inputTypeChanged ? "user-update-type" : "user-update-other";
String inputType = normalizeInputType((String) settings.get("input_type"), ctx);
Map<String, Object> params = new HashMap<>();
params.put("table_name", tableName);
params.put("column_name", columnName);
@@ -202,7 +210,7 @@ public class TableManagementService extends BaseService {
public void updateColumnInputType(String tableName, String columnName,
String inputType, String companyCode,
Map<String, Object> detailSettings) {
String finalType = normalizeInputType(inputType);
String finalType = normalizeInputType(inputType, "user-update-type");
Map<String, Object> params = new HashMap<>();
params.put("table_name", tableName);
params.put("column_name", columnName);
@@ -853,7 +861,7 @@ public class TableManagementService extends BaseService {
return name.replaceAll("[^a-zA-Z0-9_]", "");
}
/** "direct" / "auto" → "text" 변환 */
/** "direct" / "auto" → "text" 변환 (legacy 호출처 보호 — system-normalize 동작) */
private String normalizeInputType(String inputType) {
if ("direct".equals(inputType) || "auto".equals(inputType)) {
log.warn("잘못된 inputType 값 감지: {} → 'text'로 변환", inputType);
@@ -862,6 +870,24 @@ public class TableManagementService extends BaseService {
return inputType != null ? inputType : "text";
}
/**
* context 에 따라 INPUT_TYPE 정규화 및 검증.
* @param context "user-insert" | "user-update-type" | "user-update-other" | "system-normalize"
*/
private String normalizeInputType(String value, String context) {
if ("user-insert".equals(context) || "user-update-type".equals(context)) {
if (value == null || !USER_SELECTABLE_INPUT_TYPES.contains(value)) {
throw new IllegalArgumentException(
"INPUT_TYPE 은 다음 8개 중 하나여야 합니다: " + USER_SELECTABLE_INPUT_TYPES
+ " (받은 값: " + value + ")"
);
}
return value;
}
// user-update-other / system-normalize: 기존 동작 그대로
return normalizeInputType(value);
}
private String toJsonString(Object obj) {
if (obj == null) return "{}";
if (obj instanceof String s) return s.isBlank() ? "{}" : s;