From 50ee165c377decaebabef5598f529b0466d9436d Mon Sep 17 00:00:00 2001 From: DDD1542 Date: Mon, 2 Feb 2026 12:07:37 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=9E=85=EB=A0=A5=20=ED=83=80=EC=9E=85?= =?UTF-8?q?=20=EC=B2=98=EB=A6=AC=20=EA=B0=9C=EC=84=A0=20=EB=B0=8F=20?= =?UTF-8?q?=EB=B3=80=ED=99=98=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 입력 타입이 "direct" 또는 "auto"일 경우, 이를 "text"로 변환하는 로직을 추가하여 데이터베이스에 잘못된 값이 저장되지 않도록 하였습니다. - 관련된 경고 로그를 추가하여 잘못된 입력 타입 감지를 강화하였습니다. - 웹 타입 변환 시에도 동일한 로직을 적용하여 일관성을 유지하였습니다. - 프론트엔드에서 입력 타입 변경 시 로컬 상태만 업데이트하도록 수정하여 데이터베이스에 저장하지 않도록 하였습니다. --- .../controllers/tableManagementController.ts | 24 ++++++++-- .../src/services/tableManagementService.ts | 45 +++++++++++++++---- .../components/screen/TableTypeSelector.tsx | 28 ++---------- frontend/lib/api/screen.ts | 2 - 4 files changed, 62 insertions(+), 37 deletions(-) diff --git a/backend-node/src/controllers/tableManagementController.ts b/backend-node/src/controllers/tableManagementController.ts index e38e2cc5..7f79d998 100644 --- a/backend-node/src/controllers/tableManagementController.ts +++ b/backend-node/src/controllers/tableManagementController.ts @@ -557,7 +557,16 @@ export async function updateColumnInputType( ): Promise { try { const { tableName, columnName } = req.params; - const { inputType, detailSettings } = req.body; + let { inputType, detailSettings } = req.body; + + // 🔥 "direct" 또는 "auto"는 프론트엔드의 입력 방식 구분값이므로 + // DB의 input_type(웹타입)으로 저장하면 안 됨 - "text"로 변환 + if (inputType === "direct" || inputType === "auto") { + logger.warn( + `잘못된 inputType 값 감지: ${inputType} → 'text'로 변환 (${tableName}.${columnName})` + ); + inputType = "text"; + } // 🔥 회사 코드 추출 (JWT에서 또는 DB에서 조회) let companyCode = req.user?.companyCode; @@ -1357,8 +1366,17 @@ export async function updateColumnWebType( `레거시 API 사용: updateColumnWebType → updateColumnInputType 사용 권장` ); - // webType을 inputType으로 변환 - const convertedInputType = inputType || webType || "text"; + // 🔥 inputType이 "direct" 또는 "auto"이면 무시하고 webType 사용 + // "direct"/"auto"는 프론트엔드의 입력 방식(직접입력/자동입력) 구분값이지 + // DB에 저장할 웹 타입(text, number, date 등)이 아님 + let convertedInputType = webType || "text"; + if (inputType && inputType !== "direct" && inputType !== "auto") { + convertedInputType = inputType; + } + + logger.info( + `웹타입 변환: webType=${webType}, inputType=${inputType} → ${convertedInputType}` + ); // 새로운 메서드 호출 req.body = { inputType: convertedInputType, detailSettings }; diff --git a/backend-node/src/services/tableManagementService.ts b/backend-node/src/services/tableManagementService.ts index c8196235..cbe5e57e 100644 --- a/backend-node/src/services/tableManagementService.ts +++ b/backend-node/src/services/tableManagementService.ts @@ -456,6 +456,15 @@ export class TableManagementService { `컬럼 설정 업데이트 시작: ${tableName}.${columnName}, company: ${companyCode}` ); + // 🔥 "direct" 또는 "auto"는 프론트엔드의 입력 방식 구분값이므로 + // DB의 input_type(웹타입)으로 저장하면 안 됨 - "text"로 변환 + if (settings.inputType === "direct" || settings.inputType === "auto") { + logger.warn( + `잘못된 inputType 값 감지: ${settings.inputType} → 'text'로 변환 (${tableName}.${columnName})` + ); + settings.inputType = "text"; + } + // 테이블이 table_labels에 없으면 자동 추가 await this.insertTableIfNotExists(tableName); @@ -708,12 +717,22 @@ export class TableManagementService { inputType?: string ): Promise { try { + // 🔥 'direct'나 'auto'는 프론트엔드의 입력 방식 구분값이므로 + // DB의 input_type(웹타입)으로 저장하면 안 됨 - 'text'로 변환 + let finalWebType = webType; + if (webType === "direct" || webType === "auto") { + logger.warn( + `잘못된 webType 값 감지: ${webType} → 'text'로 변환 (${tableName}.${columnName})` + ); + finalWebType = "text"; + } + logger.info( - `컬럼 입력 타입 설정 시작: ${tableName}.${columnName} = ${webType}` + `컬럼 입력 타입 설정 시작: ${tableName}.${columnName} = ${finalWebType}` ); // 웹 타입별 기본 상세 설정 생성 - const defaultDetailSettings = this.generateDefaultDetailSettings(webType); + const defaultDetailSettings = this.generateDefaultDetailSettings(finalWebType); // 사용자 정의 설정과 기본 설정 병합 const finalDetailSettings = { @@ -732,10 +751,10 @@ export class TableManagementService { input_type = EXCLUDED.input_type, detail_settings = EXCLUDED.detail_settings, updated_date = NOW()`, - [tableName, columnName, webType, JSON.stringify(finalDetailSettings)] + [tableName, columnName, finalWebType, JSON.stringify(finalDetailSettings)] ); logger.info( - `컬럼 입력 타입 설정 완료: ${tableName}.${columnName} = ${webType}` + `컬럼 입력 타입 설정 완료: ${tableName}.${columnName} = ${finalWebType}` ); } catch (error) { logger.error( @@ -760,13 +779,23 @@ export class TableManagementService { detailSettings?: Record ): Promise { try { + // 🔥 'direct'나 'auto'는 프론트엔드의 입력 방식 구분값이므로 + // DB의 input_type(웹타입)으로 저장하면 안 됨 - 'text'로 변환 + let finalInputType = inputType; + if (inputType === "direct" || inputType === "auto") { + logger.warn( + `잘못된 input_type 값 감지: ${inputType} → 'text'로 변환 (${tableName}.${columnName})` + ); + finalInputType = "text"; + } + logger.info( - `컬럼 입력 타입 설정 시작: ${tableName}.${columnName} = ${inputType}, company: ${companyCode}` + `컬럼 입력 타입 설정 시작: ${tableName}.${columnName} = ${finalInputType}, company: ${companyCode}` ); // 입력 타입별 기본 상세 설정 생성 const defaultDetailSettings = - this.generateDefaultInputTypeSettings(inputType); + this.generateDefaultInputTypeSettings(finalInputType); // 사용자 정의 설정과 기본 설정 병합 const finalDetailSettings = { @@ -788,7 +817,7 @@ export class TableManagementService { [ tableName, columnName, - inputType, + finalInputType, JSON.stringify(finalDetailSettings), companyCode, ] @@ -798,7 +827,7 @@ export class TableManagementService { await this.syncScreenLayoutsInputType( tableName, columnName, - inputType, + finalInputType, companyCode ); diff --git a/frontend/components/screen/TableTypeSelector.tsx b/frontend/components/screen/TableTypeSelector.tsx index 5da49312..c6757d92 100644 --- a/frontend/components/screen/TableTypeSelector.tsx +++ b/frontend/components/screen/TableTypeSelector.tsx @@ -174,30 +174,10 @@ export default function TableTypeSelector({ } }; - // 입력 타입 변경 - const handleInputTypeChange = async (columnName: string, inputType: "direct" | "auto") => { - try { - // 현재 컬럼 정보 가져오기 - const currentColumn = columns.find((col) => col.columnName === columnName); - if (!currentColumn) return; - - // 웹 타입과 함께 입력 타입 업데이트 - await tableTypeApi.setColumnWebType( - selectedTable, - columnName, - currentColumn.webType || "text", - undefined, // detailSettings - inputType, - ); - - // 로컬 상태 업데이트 - setColumns((prev) => prev.map((col) => (col.columnName === columnName ? { ...col, inputType } : col))); - - // console.log(`컬럼 ${columnName}의 입력 타입을 ${inputType}로 변경했습니다.`); - } catch (error) { - // console.error("입력 타입 변경 실패:", error); - alert("입력 타입 설정에 실패했습니다. 다시 시도해주세요."); - } + // 입력 타입 변경 (로컬 상태만 - DB에 저장하지 않음) + const handleInputTypeChange = (columnName: string, inputType: "direct" | "auto") => { + // 로컬 상태만 업데이트 (DB에는 저장하지 않음 - inputType은 화면 렌더링용) + setColumns((prev) => prev.map((col) => (col.columnName === columnName ? { ...col, inputType } : col))); }; const filteredTables = tables.filter((table) => table.displayName.toLowerCase().includes(searchTerm.toLowerCase())); diff --git a/frontend/lib/api/screen.ts b/frontend/lib/api/screen.ts index 74894dc0..9cdc1bd9 100644 --- a/frontend/lib/api/screen.ts +++ b/frontend/lib/api/screen.ts @@ -347,12 +347,10 @@ export const tableTypeApi = { columnName: string, webType: string, detailSettings?: Record, - inputType?: "direct" | "auto", ): Promise => { await apiClient.put(`/table-management/tables/${tableName}/columns/${columnName}/web-type`, { webType, detailSettings, - inputType, }); },