- ModernDatePicker: 로컬 상태 관리로 즉시 검색 방지
- tempValue 상태 추가하여 확인 버튼 클릭 시에만 검색 실행
- 빠른 선택 버튼 추가 (오늘, 이번주, 이번달, 최근 7일, 최근 30일)
- TableSearchWidget: ModernDatePicker 통합
- 기본 HTML input[type=date]를 ModernDatePicker로 교체
- 날짜 범위 객체 {from, to}를 파이프 구분 문자열로 변환
- 백엔드 재시작 없이 작동하도록 임시 포맷팅 적용
- tableManagementService: 날짜 범위 검색 로직 개선
- getColumnWebTypeInfo: web_type이 null이면 input_type 폴백
- buildDateRangeCondition: VARCHAR 타입 날짜 컬럼 지원
- 날짜 컬럼을 ::date로 캐스팅하여 타입 호환성 확보
- 파이프 구분 문자열 파싱 지원 (YYYY-MM-DD|YYYY-MM-DD)
- 디버깅 로깅 추가
- 컬럼 타입 정보 조회 결과 로깅
- 날짜 범위 검색 조건 생성 과정 추적
주요 수정사항:
1. 탭 컴포넌트 내 자식 화면에 menuObjid와 tableName 전달
- TabsWidget에 menuObjid prop 추가
- InteractiveScreenViewerDynamic를 통해 자식 화면에 전달
- 채번 규칙 생성 시 올바른 메뉴 스코프 및 테이블명 적용
2. 백엔드: 화면 레이아웃 API에 tableName 추가
- screenManagementService.getLayout()에서 테이블명 반환
- LayoutData 타입에 tableName 필드 추가
- 채번 규칙 생성 시 tableName 검증 강화
3. 카테고리 필터링 기능 복원
- DataFilterConfigPanel에 menuObjid 전달
- getCategoryValues API 사용으로 메뉴 스코프 적용
- 새로고침 후 카테고리 값 자동 재로드
- SplitPanelLayoutConfigPanel에 menuObjid 전달
4. 선택항목 상세입력 설정 패널 포커스 문제 해결
- 로컬 입력 상태 추가로 실시간 속성 편집 패턴 적용
- 텍스트 및 라벨 입력 시 포커스 유지
5. 테이블 리스트 설정 초기화 문제 해결
- handleChange 함수에서 기존 config와 병합하여 전달
- 다른 속성 손실 방지 (columns, dataFilter 등)
버그 수정:
- 채번 규칙 생성 시 빈 문자열 대신 null 전달
- 필터 설정 변경 시 컬럼 설정 초기화 방지
- 카테고리 컬럼 선택 시 셀렉트박스 표시
- RealtimePreview: border → outline 전환, getHeight() 함수 추가
- SectionPaperComponent: width/height 100%, overflow-auto, min-h 제거
- 모든 높이에서 선택 영역 = 컨텐츠 영역 정확히 일치
- 품목 추가 시 공통 필드(거래처, 담당자, 메모) 자동 복사
- ModalRepeaterTable onChange 시 groupData 반영
- 백엔드 타입 캐스팅으로 PostgreSQL 에러 해결
- 타입 정규화로 불필요한 UPDATE 방지
- 수정 모달에서 거래처/수주번호 읽기 전용 처리
- EditModal의 handleSave가 button-primary까지 전달되도록 수정
- ConditionalContainer/ConditionalSectionViewer에 onSave prop 추가
- DynamicComponentRenderer와 InteractiveScreenViewerDynamic에 onSave 전달 로직 추가
- ButtonActionExecutor에서 context.onSave 콜백 우선 실행 로직 구현
- 신규 품목 추가 시 groupByColumns 값 자동 포함 처리
기능:
- 품목 추가: order_no 자동 설정
- 품목 수정: 변경 필드만 부분 업데이트
- 품목 삭제: originalGroupData 비교 후 제거
🐛 문제:
- 제어(플로우) 실행으로 데이터 INSERT 시 writer, company_code 컬럼이 비어있는 문제
- 플로우 실행 API에 인증이 없어 사용자 정보를 사용할 수 없었음
✅ 해결:
1. 플로우 실행 API에 authenticateToken 미들웨어 추가
2. 사용자 정보(userId, userName, companyCode)를 contextData에 포함
3. INSERT 노드 실행 시 writer와 company_code 자동 추가
- 필드 매핑에 없는 경우에만 자동 추가
- writer: 현재 로그인한 사용자 ID
- company_code: 현재 사용자의 회사 코드
- 최고 관리자(companyCode = '*')는 제외
4. 플로우 제어 자동 감지 개선
- flowConfig가 있으면 controlMode 없이도 플로우 모드로 인식
- 데이터 미선택 시 명확한 오류 메시지 표시
🎯 영향:
- 입고처리, 출고처리 등 제어 기반 데이터 생성 시 멀티테넌시 보장
- 데이터 추적성 향상 (누가 생성했는지 자동 기록)
📝 수정 파일:
- frontend/lib/utils/buttonActions.ts
- backend-node/src/routes/dataflow/node-flows.ts
- backend-node/src/services/nodeFlowExecutionService.ts
- 데이터 내용 기반 컬럼 너비 자동 계산 (상위 50개 샘플링)
- 사용자가 조정한 컬럼 너비를 localStorage에 저장/복원
- 정렬 상태(컬럼, 방향)를 localStorage에 저장/복원
- 사용자별, 테이블별 독립적인 설정 관리
변경:
- TableListComponent.tsx: calculateOptimalColumnWidth 추가, 정렬 상태 저장/복원 로직 추가
- README.md: 새로운 기능 문서화
저장 키:
- table_column_widths_{테이블}_{사용자}: 컬럼 너비
- table_sort_state_{테이블}_{사용자}: 정렬 상태
Fixes: 수주관리 화면에서 컬럼 너비 수동 조정 번거로움, 정렬 설정 미유지 문제
- entityJoinApi 조회 데이터의 조인 컬럼(material_label 등) 필터링
- dynamicFormService.ts: 병합 모드에서 columnInfo 기반 유효 컬럼만 저장
- sales_order_mng 테이블에 존재하지 않는 컬럼 INSERT 방지
- "column does not exist" PostgreSQL 에러 해결
영향: 수주관리 그룹 편집 저장 정상 동작
- 같은 수주번호(order_no)를 가진 품목 일괄 수정 기능 추가
- groupByColumns 개념 도입 및 EditModal 그룹 데이터 처리 로직 구현
- ConditionalSectionViewer에서 DynamicComponentRenderer 사용으로 groupedData 전달 경로 확보
- ModalRepeaterTable onChange 에러 수정 및 sourceColumns 필터링 추가
- 조인된 컬럼 제외 로직 추가로 DB 저장 오류 해결
- autocomplete-search-input: !bg-background 강제 적용
- section-paper: 배경색 진하게(bg-muted/40), 기본 테두리 활성화, overflow-visible
- modal-repeater-table: tbody 흰색 배경, 스크롤 높이 제한(240px), 헤더 고정
- autocomplete 드롭다운: z-index 100으로 상향
배경색 통일로 일관된 디자인, 스크롤로 공간 효율 개선
1. Select Basic 다중선택 컴포넌트 높이 문제 해결
- 외부 wrapper에 height: 100% 추가
- 내부 div에 인라인 스타일로 height: 100% 명시
- items-center 추가하여 태그 세로 가운데 정렬
- Tailwind h-full 클래스 제거로 스타일 충돌 방지
2. 메뉴 복사 시 menu_objid=0 공통 카테고리 타입 처리
- menu_objid가 숫자 0, 문자열 '0' 모두 처리
- == 0 타입 강제 변환으로 모든 경우 감지
- 카테고리 컬럼 매핑, 카테고리 값 모두 적용
- 공통 카테고리 19개 정상 복사 가능
새로운 기능:
- 화면명에서 특정 텍스트 제거 (예: '탑씰' 제거)
- 화면명에 접두사 추가 (예: '한신' 추가)
- 변환 로직: 제거 → 접두사 추가 순서로 적용
백엔드:
- menuCopyService.copyMenu()에 screenNameConfig 파라미터 추가
- copyScreens()에서 화면명 변환 로직 적용
- 정규식으로 전역 치환 (new RegExp(text, 'g'))
프론트엔드:
- MenuCopyDialog에 화면명 일괄 변경 UI 추가
- Checkbox로 기능 활성화/비활성화
- 2개 Input: removeText, addPrefix
- API 호출 시 screenNameConfig 전달
사용 예시:
1. '탑씰 회사정보' → '회사정보' (제거만)
2. '회사정보' → '한신 회사정보' (접두사만)
3. '탑씰 회사정보' → '한신 회사정보' (제거 + 접두사)
관련 파일:
- backend-node/src/services/menuCopyService.ts
- backend-node/src/controllers/adminController.ts
- frontend/lib/api/menu.ts
- frontend/components/admin/MenuCopyDialog.tsx
- 문제: 화면 복사 시 참조되는 화면이 아직 복사되지 않아 screenIdMap에 매핑 정보가 없었음
- 해결: 2단계 복사 방식 도입
1단계: 모든 screen_definitions 먼저 복사하여 screenIdMap 완성
2단계: screen_layouts 복사하면서 완성된 screenIdMap으로 참조 업데이트
- 결과: targetScreenId가 올바르게 새 회사의 화면 ID로 매핑됨 (예: 149 → 517)
- 추가: 화면 수집 시 문자열 타입 ID도 올바르게 파싱하도록 개선
- 추가: 참조 화면 발견 및 업데이트 로그 추가
관련 파일:
- backend-node/src/services/menuCopyService.ts
- db/migrations/1003_add_source_menu_objid_to_menu_info.sql
- db/scripts/cleanup_company_11_*.sql
문제:
- targetTable이 메인 테이블과 동일할 때 헤더 단독 저장 + Repeater 병합 저장으로 2번 INSERT 발생
- 같은 수주번호로 헤더만 있는 레코드와 전체 데이터 레코드가 중복 생성됨
해결:
- Repeater를 병합/분리 모드로 분류하는 로직 추가
- 병합 모드: 헤더+품목을 통합하여 품목당 1개 레코드로 저장
- 분리 모드: 헤더와 품목을 별도 테이블에 저장
- 헤더 단독 INSERT 제거로 중복 방지
영향:
- 단일 테이블 구조에서 품목별 레코드 생성 방식으로 변경
- 확장/축소 UI를 통한 품목별 조회 지원
- 백엔드: 배열 객체 형식 Repeater 데이터 처리 로직 추가
- 백엔드: Repeater 저장 시 company_code 자동 주입
- 백엔드: 부모 테이블 데이터 자동 병합 (targetTable = tableName)
- 프론트엔드: beforeFormSave 이벤트로 formData 주입
- 프론트엔드: _targetTable 메타데이터 전달
- 프론트엔드: ComponentRendererProps 상속 및 Renderer 단순화
멀티테넌시 및 부모-자식 관계 자동 처리로
복잡한 배열 데이터 저장 안정성 확보
문제:
- 테이블에서 'CATEGORY_218152,CATEGORY_205381' 같은 다중 값이
- 배지로 표시되지 않고 코드값 그대로 보임
원인:
- formatCellValue의 카테고리 렌더링이 단일 값만 처리
- 콤마로 구분된 다중 값 파싱 로직 없음
해결:
1. 콤마 구분자 감지 및 값 배열로 분리
2. 단일 값: 기존 로직 유지 (단일 배지)
3. 다중 값: flex-wrap gap-1로 여러 배지 렌더링
4. 각 배지는 매핑된 라벨과 색상 사용
결과:
✅ 다중선택 저장된 데이터가 테이블에서 여러 배지로 표시됨
✅ 각 배지에 올바른 색상과 라벨 적용
✅ 단일 값도 기존처럼 정상 작동
문제:
- value: undefined, label: undefined로 나옴
- v.categoryValue, v.categoryLabel이 존재하지 않음
디버깅:
- API 응답의 첫 번째 항목 전체 출력
- 객체의 모든 키 목록 출력
- 여러 가능한 속성명 시도:
- category_value / categoryValue / value
- category_label / categoryLabel / label
다음 단계:
- 콘솔에서 원본 데이터 구조 확인
- 실제 속성명에 맞게 매핑 수정
문제:
- select-basic이 webType='category'일 때 옵션이 안 보임
- CATEGORY_218152 같은 코드값만 표시됨
- 체크박스는 보이지만 라벨이 비어있음
원인:
- select-basic은 useCodeOptions만 사용 (code 타입용)
- category 타입은 getCategoryValues API 필요
해결:
1. categoryOptions 상태 추가
2. webType === 'category'일 때 getCategoryValues 호출
3. getAllOptions에 categoryOptions 포함
4. 로딩 상태에 isLoadingCategories 추가
디버깅:
- 카테고리 로딩 시작/완료 로그
- API 응답 로그
- 최종 allOptions 로그 추가
다음 단계:
- 콘솔에서 categoryOptions가 제대로 로드되는지 확인
문제:
- 이전 커밋에서 로직을 반대로 작성
- componentType !== 'select-basic'로 했지만
- componentType === 'select-basic'일 때 건너뛰어야 함
수정:
- componentType === 'select-basic'이면 통과 (아무것도 안 함)
- 그 외 카테고리는 CategorySelectComponent 사용
로직:
if (category && componentType === 'select-basic') {
// 통과 - ComponentRegistry로 진행
} else if (category) {
// CategorySelectComponent 사용
}
문제:
- componentType이 'select-basic'이지만 webType이 'category'일 때
- DynamicComponentRenderer가 무조건 CategorySelectComponent 사용
- select-basic의 multiple 설정이 무시됨
원인:
- 152줄에서 webType === 'category' 조건만 체크
- componentType을 확인하지 않아 select-basic도 가로챔
해결:
- componentType !== 'select-basic' 조건 추가
- select-basic은 카테고리 조건을 건너뛰고 ComponentRegistry로 진행
- 다중선택 등 select-basic의 고급 기능 사용 가능
변경사항:
- DynamicComponentRenderer.tsx 152줄
- 카테고리 조건에 componentType 체크 추가
문제:
- SelectBasicComponent 렌더링 로그가 전혀 안 보임
- select-basic이 ComponentRegistry에 등록되었는지 확인 필요
디버깅:
- componentType이 'select-basic'일 때 조회 결과 로그
- found: true/false로 등록 여부 확인
- componentConfig 값도 함께 출력
예상 결과:
- found: false면 등록 실패
- found: true면 다른 문제 (렌더링 과정에서 문제)
문제:
- 다중선택 설정했지만 UI에 반영 안됨
- 디버깅 로그가 콘솔에 전혀 안 보임
원인 추정:
- SelectBasicComponent가 아예 렌더링 안되고 있을 가능성
- 또는 다른 select 컴포넌트가 대신 렌더링될 가능성
테스트:
- 최상단에 눈에 띄는 로그 (🚨🚨🚨) 추가
- componentId, componentType, columnName, multiple 값 출력
- 이 로그가 안 보이면 다른 컴포넌트가 렌더링되는 것
더 명확한 로그 출력:
- 단계별로 구분된 로그
- 각 props 출처별로 명확히 표시
- 최종 isMultiple 값 강조
- 활성화/비활성화 상태 명확히 표시
사용자는 브라우저 콘솔에서 다음을 확인:
1. '🔍 [SelectBasicComponent] ========== 다중선택 디버깅 ==========' 로그 찾기
2. '최종 isMultiple 값' 확인
3. 각 props 출처의 multiple 값 확인
4. ✅/❌ 상태 메시지 확인
기능:
- 설정 패널에 '다중 선택' 체크박스 추가
- multiple 옵션 활성화 시 다중선택 UI 렌더링
- 선택된 항목을 태그 형식으로 표시
- 각 태그에 X 버튼으로 개별 제거 가능
- 드롭다운에 체크박스 표시
- 콤마(,) 구분자로 값 저장/파싱
수정사항:
- SelectBasicConfigPanel: 다중 선택 체크박스 추가
- SelectBasicConfigPanel: config 병합 방식으로 변경 (다른 속성 보호)
- SelectBasicComponent: 초기값 콤마 구분자로 파싱
- SelectBasicComponent: 외부 value 변경 시 다중선택 배열 동기화
- SelectBasicComponent: 다중선택 UI 렌더링 로직 추가
사용법:
1. 설정 패널에서 '다중 선택' 체크
2. 드롭다운에서 여러 항목 선택
3. 선택된 항목이 태그로 표시되며 X로 제거 가능
4. 저장 시 '값1,값2,값3' 형식으로 저장
- displayMode가 undefined일 때 기본값 'list' 처리 누락
- 조건문을 (config.rightPanel?.displayMode || 'list') === 'list'로 변경
- 이제 처음 들어갔을 때부터 라벨 표시 설정 UI가 보임
문제: LIST 모드가 기본값인데 초기에는 설정 UI가 안 보이고 테이블 모드로 변경 후 다시 LIST로 바꿔야 보임
원인: undefined === 'list'가 false가 되어 조건문이 작동하지 않음
해결: 기본값 처리 추가
- 초기 렌더링 시 기존 필드들의 autoFillFromTable이 설정되어 있으면 컬럼 자동 로드
- useEffect로 localFields 초기화 시점에 모든 필드 순회하며 컬럼 로드
- 사용자가 저장된 설정을 열었을 때 즉시 컬럼 목록 표시
문제: 품목정보 테이블을 선택했지만 컬럼이 표시되지 않음
원인: 기존에 설정된 autoFillFromTable에 대한 컬럼이 초기 로드되지 않음
해결: 초기화 useEffect 추가로 기존 설정 복원
- types.ts에 targetTable 필드 추가하여 config에 저장되도록 수정
- ConfigPanel에서 targetTable을 localConfig로 관리하여 설정 유지
- Renderer 단순화 (TextInput 패턴 적용)
- Component에서 직접 isInteractive 체크 및 필드 매핑 처리
- ComponentRendererProps 상속으로 필수 props 타입 안정성 확보
문제:
- ConfigPanel 설정이 초기화되는 문제
- 필드 매핑 데이터가 DB에 저장되지 않는 문제
해결:
- 정상 작동하는 TextInput 컴포넌트 패턴 분석 및 적용
- Renderer는 props만 전달, Component가 저장 로직 처리
- 추가 입력 필드에서 자동 채우기 테이블을 드롭다운으로 선택 가능
- 텍스트 입력 대신 allTables에서 선택하는 방식으로 개선
- 테이블 선택 시 해당 테이블의 컬럼을 자동으로 로드
- autoFillTableColumns 상태로 필드별 테이블 컬럼 관리
- 선택한 테이블에 따라 컬럼 드롭다운이 동적으로 변경됨
사용자 경험 개선:
- 테이블명을 직접 입력하는 대신 목록에서 선택
- 선택한 테이블의 컬럼만 표시되어 혼란 방지
- 원본 테이블(기본) 또는 다른 테이블 선택 가능
- 원본 테이블(sourceTable) 변경 시 컬럼 자동 로드
- 대상 테이블(targetTable) 변경 시 컬럼 자동 로드
- props로 받은 컬럼은 백업으로 사용하고, 내부에서 로드한 컬럼 우선 사용
- tableManagementApi.getColumnList() 사용하여 동적 로드
이제 원본/대상 테이블 선택 시 해당 테이블의 컬럼 목록이 자동으로 나타남
- TableListConfigPanel: handleNestedChange에서 전체 config 병합 로직 추가
- TableListComponent: checkbox.enabled 및 position 기본값 처리 (undefined시 기본값 사용)
- SelectedItemsDetailInputConfigPanel: handleChange에서 전체 config 병합 로직 추가
- SelectedItemsDetailInputConfigPanel: 원본 데이터 테이블 선택 disabled 조건 제거
- UnifiedPropertiesPanel: allTables 로드 및 ConfigPanel에 전달 추가
문제:
1. table-list 컴포넌트 체크박스 설정 변경 시 다른 설정 초기화
2. selected-items-detail-input 설정 변경 시 컴포넌트 이름 등 다른 속성 손실
3. 원본 데이터 테이블 선택이 비활성화되어 있음
해결:
- 모든 설정 패널에서 부분 업데이트 시 기존 config와 병합하도록 수정
- checkbox 관련 기본값 처리로 기존 컴포넌트 호환성 보장
- allTables를 별도로 로드하여 전체 테이블 목록 제공