# 저장 후 플로우 실행 시 폼 데이터 전달 오류 수정 ## 오류 현상 사용자가 폼에서 데이터를 저장한 후, 연결된 노드 플로우(예: 비밀번호 자동 설정)가 실행될 때 `sabun` 값이 `undefined`로 전달되어 UPDATE 쿼리의 WHERE 조건이 작동하지 않는 문제. ### 증상 - 저장 버튼 클릭 시 INSERT는 정상 작동 - 저장 후 실행되는 노드 플로우에서 `user_password` UPDATE가 실패 (0건 업데이트) - 콘솔 로그에서 `savedData.sabun: undefined` 출력 ``` 📦 [executeAfterSaveControl] savedData 필드: ['id', 'screenId', 'tableName', 'data', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'] 📦 [executeAfterSaveControl] savedData.sabun: undefined ``` --- ## 원인 분석 ### API 응답 구조의 3단계 중첩 저장 API(`DynamicFormApi.saveFormData`)의 응답이 3단계로 중첩되어 있었음: ```typescript // 1단계: Axios 응답 saveResult = { data: { ... } // API 응답 } // 2단계: API 응답 래핑 (ApiResponse 인터페이스) saveResult.data = { success: true, data: { ... }, // 저장된 레코드 message: "저장 완료" } // 3단계: 저장된 레코드 (dynamic_form_data 테이블 구조) saveResult.data.data = { id: 123, screenId: 106, tableName: "user_info", data: { sabun: "20260205-087", user_name: "TEST", ... }, // ← 실제 폼 데이터 createdAt: "2026-02-05T...", updatedAt: "2026-02-05T...", createdBy: "admin", updatedBy: "admin" } // 4단계: 실제 폼 데이터 (우리가 필요한 데이터) saveResult.data.data.data = { sabun: "20260205-087", user_name: "TEST", user_id: "Kim1542", ... } ``` ### 기존 코드의 문제점 ```typescript // 기존 코드 (buttonActions.ts:1619-1621) const savedData = saveResult?.data?.data || saveResult?.data || {}; const formData = savedData; // ← 2단계까지만 추출 // savedData = { id, screenId, tableName, data: {...}, createdAt, ... } // savedData.sabun = undefined ← 문제 발생! ``` 기존 코드는 2단계(`saveResult.data.data`)까지만 추출했기 때문에, `savedData`가 저장된 레코드 메타데이터를 가리키고 있었음. 실제 폼 데이터는 `savedData.data` 안에 있었음. --- ## 해결 방법 ### 수정된 코드 ```typescript // 수정된 코드 (buttonActions.ts:1619-1628) // 🔧 수정: saveResult.data가 3단계로 중첩된 경우 실제 폼 데이터 추출 // saveResult.data = API 응답 { success, data, message } // saveResult.data.data = 저장된 레코드 { id, screenId, tableName, data, createdAt... } // saveResult.data.data.data = 실제 폼 데이터 { sabun, user_name... } const savedRecord = saveResult?.data?.data || saveResult?.data || {}; const actualFormData = savedRecord?.data || savedRecord; // ← 3단계까지 추출 const formData = (Object.keys(actualFormData).length > 0 ? actualFormData : context.formData || {}); ``` ### 수정 핵심 1. `savedRecord`: 저장된 레코드 메타데이터 (`{ id, screenId, tableName, data, ... }`) 2. `actualFormData`: `savedRecord.data`가 있으면 그것을 사용, 없으면 `savedRecord` 자체 사용 3. 폴백: `actualFormData`가 비어있으면 `context.formData` 사용 --- ## 수정된 파일 | 파일 | 수정 내용 | |------|-----------| | `frontend/lib/utils/buttonActions.ts` | 3단계 중첩 데이터 구조에서 실제 폼 데이터 추출 로직 수정 (라인 1619-1628) | --- ## 검증 결과 ### 수정 전 ``` 📦 [executeAfterSaveControl] savedData 필드: ['id', 'screenId', 'tableName', 'data', ...] 📦 [executeAfterSaveControl] savedData.sabun: undefined ``` ### 수정 후 ``` 📦 [executeAfterSaveControl] savedRecord 구조: ['id', 'screenId', 'tableName', 'data', ...] 📦 [executeAfterSaveControl] actualFormData 추출: ['sabun', 'user_id', 'user_password', ...] 📦 [executeAfterSaveControl] formData.sabun: 20260205-087 ``` ### DB 확인 ```sql SELECT sabun, user_name, user_password FROM user_info WHERE sabun = '20260205-087'; -- 결과: sabun: "20260205-087", user_name: "TEST", user_password: "1e538e2abdd9663437343212a4853591" ``` --- ## 교훈 1. **API 응답 구조 확인**: API 응답이 여러 단계로 래핑될 수 있음. 프론트엔드에서 `apiClient`가 한 번, `ApiResponse` 인터페이스가 한 번, 그리고 실제 데이터 구조가 또 다른 레벨을 가질 수 있음. 2. **로그 추가의 중요성**: 중간 단계마다 로그를 찍어 데이터 구조를 확인하는 것이 디버깅에 필수적. 3. **폴백 처리**: 데이터 추출 시 여러 단계의 폴백을 두어 다양한 응답 구조에 대응. --- ## 관련 이슈 - 비밀번호 자동 설정 노드 플로우가 저장 후 실행되지 않는 문제 - 저장 후 연결된 UPDATE 플로우에서 WHERE 조건이 작동하지 않는 문제 --- ## 작성 정보 - **작성일**: 2026-02-05 - **작성자**: AI Assistant - **관련 화면**: 부서관리 > 사용자 등록 모달 - **관련 플로우**: flowId: 120 (부서관리 비밀번호 자동세팅)