_groupedData를 테이블 섹션에 초기화하여 기존 품목 표시
originalGroupedData로 원본 데이터 보관하여 변경 추적
handleUniversalFormModalTableSectionSave()에 INSERT/UPDATE/DELETE 분기 로직 구현
EditModal, ConditionalSectionViewer에서 UniversalFormModal 감지 시 onSave 미전달
저장 완료 후 closeEditModal 이벤트 발생
SectionSaveMode 타입 추가 (공통 저장/개별 저장)
SaveSettingsModal에 섹션별/필드별 저장 방식 설정 UI 추가
saveSingleRow()에 공통 필드 + 품목 병합 저장 로직 구현
buttonActions.ts에 외부 저장 버튼용 병합 저장 처리 추가
- LookupConfig, LookupOption, LookupCondition 타입 정의
- sourceType 4가지 유형 지원 (currentRow, sourceTable, sectionField, externalTable)
- TableColumnSettingsModal에 "조회 설정" 탭 추가
- TableSectionSettingsModal에 간단 조회 설정 UI 추가
- fetchExternalValue, fetchExternalLookupValue 함수 구현
- 헤더 드롭다운에서 조회 옵션 선택 기능
- FormSectionConfig에 type("fields"|"table") 및 tableConfig 필드 추가
- TableSectionRenderer, TableSectionSettingsModal 신규 컴포넌트 생성
- ItemSelectionModal에 모달 필터 기능 추가 (소스 테이블 distinct 값 조회)
- 설정 패널에서 테이블 섹션 추가/설정 UI 구현
- 옵셔널 필드 그룹: 섹션 내 선택적 필드 그룹 지원 (추가/제거, 연동 필드 자동 변경)
- 카테고리 Select: table_column_category_values 테이블 값을 Select 옵션으로 사용
- 전체 카테고리 컬럼 조회 API: GET /api/table-categories/all-columns
- RepeaterFieldGroup 저장 시 공통 필드 자동 병합
- @dnd-kit 라이브러리로 행 순서 드래그 앤 드롭 구현
- SortableRow 컴포넌트로 드래그 가능한 테이블 행 구현
- GripVertical 아이콘 드래그 핸들 추가
- 드래그 시 선택된 행 인덱스 자동 재계산
- "균등 분배" 버튼으로 컬럼 너비 컨테이너에 맞게 균등 분배
- 컬럼 헤더 더블클릭으로 데이터 기준 자동 확장/복구 토글
- Input 컴포넌트 min-w-0 w-full 적용으로 컬럼 너비 초과 방지
- RepeaterTable: 체크박스 컬럼 추가 (전체 선택/개별 선택 지원)
- RepeaterTable: 선택된 행 시각적 피드백 (bg-blue-50)
- RepeaterTable: 기존 개별 삭제 버튼 컬럼 제거
- ModalRepeaterTableComponent: selectedRows 상태 및 handleBulkDelete 함수 추가
- ModalRepeaterTableComponent: "선택 삭제" 버튼 UI 추가
- RepeatScreenModalConfigPanel: 행 번호 컬럼 선택에서 빈 값 필터링
- handleModal: context.selectedRowsData를 selectedData로 복원하여 출하계획 등 모달에서 사용 가능
- handleOpenModalWithData: modalDataStore 데이터를 selectedData/selectedIds로 이벤트에 포함
- ButtonConfigPanel: split-panel-layout2 타입 소스 테이블 감지 지원 추가
- ButtonConfigPanel: column_name/display_name 컬럼 형식 폴백 추가
- ButtonConfigPanel: currentTableName 폴백으로 테이블명 감지 안정성 향상
- ButtonConfigPanel: 필드 매핑 UI를 세로 배치로 변경하여 가독성 개선
- handleOpenModalWithData에서 modalDataStore 데이터를 selectedData/selectedIds로 이벤트에 포함
- RepeatScreenModal에서 groupedData로 사용할 수 있도록 데이터 전달 경로 완성
- ButtonConfigPanel 필드 매핑 UI를 세로 배치로 변경하여 가독성 개선
- split-panel-layout2 컴포넌트 타입 소스 테이블 감지 지원 추가
- currentTableName 폴백 로직 추가로 테이블명 감지 안정성 향상
; Please enter a commit message to explain why this merge is necessary,
; especially if it merges an updated upstream into a topic branch.
;
; Lines starting with ';' will be ignored, and an empty message aborts
; the commit.
- EditModal에서 INSERT/UPDATE/그룹 저장 완료 후 제어로직 자동 실행
- loadSaveButtonConfig(): 모달 내부 저장 버튼의 제어로직 설정 조회
- findSaveButtonInComponents(): 재귀적으로 저장 버튼 탐색 (conditional-container 내부 포함)
- buttonActions.ts: openEditModal 이벤트에 buttonConfig, buttonContext 전달
- executeAfterSaveControl()을 public으로 변경하여 외부 호출 가능
- 제어로직 실행 오류 시 저장 성공 유지, 경고 토스트만 표시
문제:
- 외부 테이블 조인 시 ID 값이 문자열로 전달되어 백엔드에서 ILIKE 검색 수행
- 문자열 '189'로 검색하면 '189', '1890', '18900' 등 모두 매칭되는 문제
- 발주 등록 화면에서 품목 참조 데이터 조회 실패
해결:
- fetchReferenceValue 함수: 조인 조건 값 타입 변환 추가
- resolveDynamicValue 함수 (단순 테이블 조회): 조인 조건 값 타입 변환 추가
- resolveDynamicValue 함수 (복합 조인): 조인 조건 값 타입 변환 추가
변환 로직:
- targetField가 '_id'로 끝나거나 'id'인 경우 Number()로 변환
- NaN 체크로 변환 불가능한 값은 원본 유지
- 백엔드에서 숫자는 = 비교, 문자열은 ILIKE 검색 수행하므로 정확한 매칭 필요
영향 범위:
- modal-repeater-table 컴포넌트를 사용하는 모든 화면
- 발주 등록, 수주 등록 등 품목 참조 테이블 조회
- 모달 재오픈 시 동일 번호 유지 (previewCode 사용)
- 저장 시 정상적인 순번 증가 (allocateCode에서 nextSequence 사용)
- refreshKey를 React key로 전달하여 컴포넌트 강제 리마운트
- ruleId를 부모 컴포넌트까지 전달하여 buttonActions에서 감지
- 미리보기와 저장 번호 일치 (currentSequence + 1 통일)
- generateNumberingValues 중복 호출 방지 (ref 플래그 추가)
- generateOnOpen 시 allocateCode 직접 호출로 변경
- config 변경 시 initializeForm 재호출 비활성화
- cleanup 함수에서 플래그 초기화 추가
- 저장 시점 채번 로직 간소화 (generateOnSave만 처리)
- 미리보기 시 currentSequence + 1로 다음 순번 표시
- UniversalFormModal에서 미리보기/실제할당 분리
- _needsAllocation 플래그로 저장 시 재할당 여부 판단
- RepeatScreenModal 외부 데이터 소스 조인/필터 설정 UI 추가
- UniversalFormModalConfigPanel을 3개 모달로 분리 (2300줄 → 300줄)
- FieldDetailSettingsModal: 필드 상세 설정
- SaveSettingsModal: 저장 설정
- SectionLayoutModal: 섹션 레이아웃 설정
- FloatingPanel, DetailSettingsPanel 가로 스크롤 오버플로우 수정
- SelectOptionConfig에 saveColumn 필드 추가 (저장 값 별도 지정)
- 컬럼 헤더 드래그로 너비 조정 기능 추가 (최소 60px)
- 헤더 더블클릭으로 기본 너비 복원 기능 추가
- 엑셀 스타일 테두리 및 색상 적용 (border-b border-r)
- 테이블 최대 높이 240px → 400px 확장
- 입력 필드 높이 및 포커스 스타일 개선
; Please enter a commit message to explain why this merge is necessary,
; especially if it merges an updated upstream into a topic branch.
;
; Lines starting with ';' will be ignored, and an empty message aborts
; the commit.
- dataflowConfig.flowConfig 설정 시 저장 완료 후 노드 플로우 자동 실행
- executeNodeFlow API 동적 import로 번들 최적화
- RepeatScreenModal에서 _groupedData props 수신 지원 추가
- tiptap 라이브러리 버전 업그레이드 (2.11.5 → 2.27.1)
- 기존 소프트 삭제(_isDeleted 플래그) 방식에서 즉시 삭제로 변경
- DB에 저장된 기존 행: DELETE API 즉시 호출 후 UI에서 제거
- 새로 추가된 행: UI에서만 제거 (DB에 없음)
- _originalData.id 존재 여부로 DB 데이터 판단
- 삭제 후 집계 재계산 정상 작동
- SyncSaveConfig: 모달 저장 시 다른 테이블에 집계 값 동기화 기능
- RowNumberingConfig: 행 추가 시 채번 규칙 적용하여 자동 번호 생성
- externalTableRefs: SUM_EXT 함수가 참조할 외부 테이블 제한 기능
- triggerRepeatScreenModalSave: 외부에서 저장 트리거 가능한 이벤트 리스너
- TableColumnConfig.hidden: 테이블 컬럼 숨김 기능 (데이터는 유지, 화면만 숨김)
- beforeFormSave: FK 자동 채우기 및 _isNew 행 포함 로직 개선
- 여러 외부 테이블 데이터를 합산하여 집계 계산 지원
- 집계 설정 전용 모달(AggregationSettingsModal) 추가
- AggregationConfig에 hidden 속성 추가 (연산에만 사용, 표시 제외)
- 채번 규칙 API 에러 처리 개선 (조용히 무시, 로그 최소화)
- screenManagementService: PostgreSQL regexp_replace로 정확한 최대 번호 조회
- CopyScreenModal: linkedScreens 의존성 추가로 모달 코드 생성 보장
- UniversalFormModal: beforeFormSave 이벤트 리스너로 ButtonPrimary 연동
- 설정된 필드만 병합하여 의도치 않은 덮어쓰기 방지
- ModalRepeaterTable: 컬럼 헤더 클릭으로 데이터 소스 동적 전환
- 단순 조인, 복합 조인(다중 테이블), 전용 API 호출 지원
- DynamicDataSourceConfig, MultiTableJoinStep 타입 추가
- 설정 패널에 동적 데이터 소스 설정 모달 추가
- UniversalFormModal: showSaveButton 옵션 추가
- generateNumberingCode를 allocateNumberingCode로 변경 (순번 실제 증가)
- saveSingleRow/saveMultipleRows/saveWithMultiTable 모두 적용
- NumberingRuleCard: 파트 타입 변경 시 defaultAutoConfig 적용
- NumberingRuleDesigner: 저장 시 partsWithDefaults로 기본값 병합
- sequenceLength/numberLength 기본값 4에서 3으로 변경
- 불필요한 console.log 제거
- renderFieldWithColumns()에 repeatContext 파라미터 추가
- linkedFieldGroup 선택 시 repeatContext 유무에 따라 formData/repeatSections 분기 저장
- multiTableSave: UPSERT 대신 SELECT-UPDATE/INSERT 명시적 분기로 변경
- ON CONFLICT 조건 불일치 에러 방지
- 서브 테이블 저장 상세 로그 추가
; Please enter a commit message to explain why this merge is necessary,
; especially if it merges an updated upstream into a topic branch.
;
; Lines starting with ';' will be ignored, and an empty message aborts
; the commit.
- sourceColumnLabels 타입 정의 (Record<string, string>)
- ConfigPanel에 소스 컬럼별 표시 라벨 입력 UI 추가
- columnLabels 생성 시 sourceColumnLabels 우선 적용
- 컬럼 삭제 시 해당 라벨도 함께 삭제
- 빈 상태 안내 메시지 추가
- CustomApiSaveConfig 타입 정의 (apiType, mainDeptFields, subDeptFields)
- saveWithCustomApi() 함수 추가로 테이블 직접 저장 대신 전용 API 호출
- adminController에 saveUserWithDept(), getUserWithDept() API 추가
- user_info + user_dept 트랜잭션 저장, 메인 부서 변경 시 자동 겸직 전환
- ConfigPanel에 전용 API 저장 설정 UI 추가
- SplitPanelLayout2: getColumnValue()로 조인 테이블 컬럼 값 추출 개선
- 검색 컬럼 선택 시 표시 컬럼 기반으로 변경
- JoinTableConfig 타입 정의 (joinTable, joinType, mainColumn, joinColumn, selectColumns)
- RightPanelConfig.joinTables 배열 추가로 다중 조인 지원
- loadJoinTableData(), mergeJoinData() 함수로 클라이언트 사이드 조인 처리
- JoinTableItem 컴포넌트로 조인 테이블 설정 UI 제공
- 표시 컬럼에 sourceTable 추가로 테이블별 컬럼 구분
- 메인+조인 테이블 컬럼 통합 로드 기능
- 섹션 레벨 linkedFieldGroups 제거, 필드 레벨 linkedFieldGroup으로 변경
- FormFieldConfig에 linkedFieldGroup 속성 추가 (enabled, sourceTable, displayColumn, displayFormat, mappings)
- select 필드 렌더링에서 linkedFieldGroup 활성화 시 다중 컬럼 저장 처리
- API 응답 파싱 개선 (responseData.data 구조 지원)
- 저장 실패 시 상세 에러 메시지 표시
- ConfigPanel에 다중 컬럼 저장 설정 UI 및 HelpText 추가
; Please enter a commit message to explain why this merge is necessary,
; especially if it merges an updated upstream into a topic branch.
;
; Lines starting with ';' will be ignored, and an empty message aborts
; the commit.
- RepeaterTable에서 DB 조회된 ISO 형식 날짜를 yyyy-mm-dd로 변환
- formatDateValue 함수 추가: ISO 문자열, Date 객체, 기존 형식 모두 처리
- 수주일(order_date), 납기일(item_due_date) 등 날짜 필드 정상 표시
- value 상수를 localValue useState로 변경하여 내부 상태 관리
- useEffect로 외부 값(formData, propValue) 변경 시 동기화
- handleChange에서 setLocalValue 호출하여 즉각적인 UI 업데이트
- RepeaterTable, ItemSelectionModal 등 모든 참조를 localValue로 변경
- validateRequiredFields 함수 추가로 필수 필드 미입력 시 저장 차단
- 섹션별 열 수 설정 (1열/2열/3열/4열) 및 gridSpan 자동 계산
- 버튼 이벤트 버블링 방지 (type=button, preventDefault, stopPropagation)
- onChange 콜백 렌더링 사이클 분리 (setTimeout)
- 다중 행 저장 시 빈 객체 건너뛰기 로직 추가
- 섹션 기반 폼 레이아웃 지원 (접힘/펼침, 그리드 컬럼)
- 반복 섹션 지원 (겸직 등 동일 필드 그룹 여러 개 추가)
- 채번규칙 연동 (모달 열릴 때 또는 저장 시점 자동 생성)
- 다중 행 저장 지원 (공통 필드 + 개별 필드 조합)
- Select 옵션 동적 로드 (정적/테이블/공통코드)
- 스크린 디자이너 설정 패널 구현
- 표시 모드 추가 (card/table)
- 카드 모드 라벨 표시 옵션 (이름 행/정보 행 가로 배치)
- 체크박스 선택 기능 (전체/개별 선택)
- 개별 수정/삭제 핸들러 구현 (openEditModal, DELETE API)
- 복수 액션 버튼 배열 지원 (add, edit, bulk-delete, custom)
- 설정 패널에 표시 라벨 입력 필드 추가
- 기본키 컬럼 설정 옵션 추가
- SearchColumnConfig 타입 추가 (types.ts)
- 좌측/우측 패널 모두 여러 검색 컬럼 설정 가능
- ConfigPanel에 검색 컬럼 추가/삭제 UI 구현
- 검색 시 OR 조건으로 여러 컬럼 동시 검색
- 기존 searchColumn 단일 설정과 하위 호환성 유지
좌측 패널(마스터)-우측 패널(디테일) 분할 레이아웃 컴포넌트 추가
EditModal에 isCreateMode 플래그 추가하여 INSERT/UPDATE 분기 처리
dataFilter 기반 정확한 조인 필터링 구현
좌측 패널 선택 데이터를 모달로 자동 전달하는 dataTransferFields 설정 지원
ConfigPanel에서 테이블, 컬럼, 조인 설정 가능
- SearchColumnConfig 타입 추가 (types.ts)
- 좌측/우측 패널 모두 여러 검색 컬럼 설정 가능
- ConfigPanel에 검색 컬럼 추가/삭제 UI 구현
- 검색 시 OR 조건으로 여러 컬럼 동시 검색
- 기존 searchColumn 단일 설정과 하위 호환성 유지
좌측 패널(마스터)-우측 패널(디테일) 분할 레이아웃 컴포넌트 추가
EditModal에 isCreateMode 플래그 추가하여 INSERT/UPDATE 분기 처리
dataFilter 기반 정확한 조인 필터링 구현
좌측 패널 선택 데이터를 모달로 자동 전달하는 dataTransferFields 설정 지원
ConfigPanel에서 테이블, 컬럼, 조인 설정 가능
- RepeatScreenModal 집계 결과를 연관 테이블에 저장하는 기능 추가
- ButtonPrimary 저장 시 채번 규칙 값(shipment_plan_no) 함께 저장
- _repeatScreenModal_* 데이터 감지 시 메인 테이블 중복 저장 방지
- 기존 행 수정 모드(_isEditing) 지원
- AggregationSaveConfig 타입 및 ConfigPanel UI 추가
- DB 로드 데이터에 _isEditing: false 명시적 설정
- handleEditExternalRow: 수정 모드 전환 함수 추가
- handleCancelEditExternalRow: 수정 취소 및 원본 복원 함수 추가
- renderTableCell: isRowEditable 파라미터 추가로 행 수준 편집 제어
- UPDATE API 요청 형식 { originalData, updatedData }로 수정
- 테이블 작업 컬럼에 수정/수정취소/삭제/복원 버튼 그룹화
- 삭제 버튼 클릭 시 _isDeleted 플래그 설정 (소프트 삭제)
- 삭제된 행 시각적 표시 (취소선, 투명도)
- 삭제 취소(복원) 기능 추가
- 저장 버튼 클릭 시 DELETE API 호출하여 DB 반영
- 삭제된 행 집계 계산에서 제외
- axios DELETE 요청 시 body 전달 방식 수정
- TableCrudConfig에 allowSave, saveButtonLabel 속성 추가
- CRUD 설정 패널에 저장 스위치 추가
- saveTableAreaData 함수: editable 컬럼 + 조인키만 필터링하여 저장
- 날짜 필드 ISO 8601 -> YYYY-MM-DD 형식 변환
- 백엔드: company_code 자동 주입 로직 추가
- tableManagementService에 hasColumn 메서드 추가
- 외부 테이블 데이터 소스 설정 (TableDataSourceConfig) 추가
- 다중 테이블 조인 지원 (AdditionalJoinConfig)
- 테이블 필터링 (equals/notEquals) 지원
- 테이블 CRUD (행 추가/수정/삭제) 기능 추가
- 데이터 변경 시 집계 실시간 재계산 (recalculateAggregationsWithExternalData)
- 시각적 수식 빌더 (FormulaBuilder) 컴포넌트 추가
- 테이블 컬럼 순서 변경 기능 추가
- 백엔드: 배열 파라미터 IN 절 변환 로직 추가
; Please enter a commit message to explain why this merge is necessary,
; especially if it merges an updated upstream into a topic branch.
;
; Lines starting with ';' will be ignored, and an empty message aborts
; the commit.
- contentRows 기반 자유 레이아웃 지원 (header/aggregation/table/fields 타입)
- aggregationFields, tableColumns 직접 참조하도록 렌더링 로직 수정
- groupByField 없어도 grouping.enabled면 그룹핑 모드로 처리
- buttonActions에서 selectedRowsData를 모달 이벤트로 전달
- ScreenModal에서 selectedData를 groupedData props로 컴포넌트에 전달
- types.ts에 CardContentRowConfig, AggregationDisplayConfig 인터페이스 추가
- SimpleRepeaterTable: 검색/추가 없이 데이터 표시 및 편집, 자동 계산 지원
- RepeatScreenModal: 그룹핑 기반 카드 레이아웃, 집계 기능, 테이블 모드 지원
- UnifiedPropertiesPanel: overflow-x-auto 추가로 가로 스크롤 활성화
- Flexbox에서 Grid 레이아웃으로 변경 (160px 200px 250px 1fr)
- "상세 설정" 컬럼 제거하고 4개 컬럼 구조로 단순화
- Entity 조인 설정(참조/조인/표시 컬럼)을 입력 타입 컬럼 내 세로 배치
- Select 박스 너비를 192px (w-48)로 통일
- UI 겹침 현상 해결 및 순차적 설정 흐름 개선
- OrderItemRepeaterTable에 order_date 컬럼 추가
- ModalRepeaterTableComponent에 수주일 일괄 적용 로직 구현
- 원본 newData 참조로 납기일 로직과 독립적으로 작동
- 모든 행이 비어있는 초기 상태에서 첫 선택 시 자동 적용
- isOrderDateApplied 플래그로 1회만 실행 보장
- 프론트엔드: EditModal 날짜 정규화 함수 추가 (YYYY-MM-DD)
- 백엔드: convertValueForPostgreSQL에서 DATE 타입 문자열 유지
- 백엔드: 날짜 변환 로직에서 YYYY-MM-DD 문자열 변환 제거
- 프론트엔드: ModalRepeaterTableConfigPanel prop 이름 통일 (onChange)
- OrderItemRepeaterTable 필드명 수정 (delivery_date → item_due_date)
closes #납기일-TIMESTAMP-저장-이슈 #설정패널-prop-오류
- ModalRepeaterTableComponent에 납기일 자동 일괄 적용 로직 구현
- 첫 납기일 선택 시 빈 행에 자동으로 동일 날짜 적용
- isDeliveryDateApplied 플래그로 중복 실행 방지
- ScreenModal 환경에서 onFormDataChange 경로 지원
- 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를 별도로 로드하여 전체 테이블 목록 제공
- 검색 필터 설정을 화면별로 독립적으로 저장하도록 개선 (screenId 포함)
- FilterPanel, TableSearchWidget, TableListComponent에 화면 ID 기반 localStorage 키 적용
- 동적 모드(사용자 설정)와 고정 모드(디자이너 설정) 2가지 필터 방식 추가
- 고정 모드에서 컬럼 드롭다운 선택 기능 구현
- 컬럼 선택 시 라벨 및 필터 타입 자동 설정
- ConfigPanel 표시 문제 해결 (type='component' 지원)
- UnifiedPropertiesPanel에서 독립 컴포넌트 ConfigPanel 조회 개선
주요 변경:
- 같은 테이블을 사용하는 다른 화면에서 필터 설정이 독립적으로 관리됨
- 고정 모드에서는 설정 버튼이 숨겨지고 지정된 필터만 표시
- 테이블 정보가 있으면 컬럼을 드롭다운으로 선택 가능
- inputType에 따라 filterType 자동 추론 (number, date, select, text)
- buttonActions.ts: formData가 배열인 경우 일반 저장 건너뜀
- SelectedItemsDetailInput이 UPSERT를 완료한 후 일반 저장이 실행되어 null 레코드가 삽입되던 문제 해결
- ScreenModal에서 그룹 레코드를 배열로 전달하는 경우 감지하여 처리
- skipDefaultSave 플래그가 제대로 작동하지 않던 문제 근본 해결
- 필드 자동 매핑 기능 구현
* FieldMapping 타입 추가 (sourceField → targetField)
* applyFieldMappings() 함수로 선택 시 자동 입력
* 여러 필드를 한 번에 자동으로 채움 (거래처 선택 → 주소/전화 자동 입력)
- 값 필드 저장 위치 선택 기능 추가
* ValueFieldStorage 타입 추가 (targetTable, targetColumn)
* 기본값(화면 연결 테이블) 또는 명시적 테이블/컬럼 지정 가능
* 중간 테이블, 이력 테이블 등 다중 테이블 저장 지원
- UI/UX 개선
* 모든 선택 필드를 Combobox 스타일로 통일
* 각 필드 아래 간략한 사용 설명 추가
* 저장 위치 동작 미리보기 박스 추가
- 문서 작성
* 사용_가이드.md 신규 작성 (실전 예제 3개 포함)
* 빠른 시작 가이드, FAQ, 체크리스트 제공
- 하드코딩 제거: 필드명 패턴을 동적으로 처리
- 민감한 필드(id, password, token, company_code)만 제외하고 모두 표시
- 그룹 삭제 기능: 중복 제거 활성화 시 관련된 모든 레코드 삭제
- URL 파라미터 초기화: 모달 닫을 때 자동으로 초기화
- 백엔드: deleteGroupRecords API 추가
- 프론트엔드: dataApi.deleteGroupRecords 클라이언트 추가
- SelectedItemsDetailInput 컴포넌트 수정 모드 지원
- 그룹화된 데이터 UPSERT API 추가 (/api/data/upsert-grouped)
- 부모 키 기준으로 기존 레코드 조회 후 INSERT/UPDATE/DELETE
- 각 레코드의 모든 필드 조합을 고유 키로 사용
- created_date 보존 (UPDATE 시)
- 수정 모드에서 groupByColumns 기준으로 관련 레코드 조회
- 날짜 타입 ISO 형식 자동 감지 및 포맷팅 (YYYY.MM.DD)
주요 변경사항:
- backend: dataService.upsertGroupedRecords() 메서드 구현
- backend: dataRoutes POST /api/data/upsert-grouped 엔드포인트 추가
- frontend: ScreenModal에서 groupByColumns 파라미터 전달
- frontend: SelectedItemsDetailInput 수정 모드 로직 추가
- frontend: 날짜 필드 타임존 제거 및 포맷팅 개선
문제:
- reference 매핑 시 조인 조건의 소스 필드 값이 undefined
- API 호출 시 filters 파라미터를 백엔드가 인식 못함
해결:
- 컬럼 처리를 2단계로 분리 (source/manual → reference)
- API 파라미터 변경 (filters→search, limit/offset→size/page)
- 응답 경로 수정 (data.data → data.data.data)
결과:
- 외부 테이블 참조 매핑 정상 작동
- 품목 선택 시 customer_item_mapping에서 단가 자동 조회 성공
새로운 기능
- 컬럼별 독립적인 소스 테이블 선택 기능
- SourceColumnSelector, ReferenceColumnSelector 컴포넌트 추가
- 계산 규칙 자동 동기화 로직 (cleanupInitialConfig)
UI/UX 개선
- 컬럼 설정 UI를 세로 레이아웃으로 재구성 (h-10 통일)
- 매핑 타입별 색상 구분 (파란색/보라색/초록색)
- 계산 규칙 섹션 재디자인 (안내 박스, 번호 배지, 빈 상태)
- 현재 설정 시각화 (코드 스타일 표시)
버그 수정
- 계산 규칙 삭제 시 컬럼이 수정 불가능 상태로 남는 문제 해결
- 결과 필드 변경 시 이전 필드의 calculated 속성 제거
- 초기 로드 시 계산 규칙과 컬럼 속성 동기화
개선 사항
- 모든 입력 필드의 높이와 텍스트 크기 일관성 확보
- 섹션별 명확한 제목과 설명 추가
- 접근성 향상 (ARIA 레이블, 포커스 스타일)
변경사항:
- handleBatchSave의 모든 console.log 제거
- 핵심 로직만 유지 (데이터 매핑, 조합 생성, 저장)
- 코드 가독성 향상
제거된 로그:
- modalDataStore 데이터 확인 로그
- parentDataMapping 설정 로그
- 품목/그룹 처리 로그
- 조합 생성/병합 로그
- 데이터 소스 상세 로그
- 저장 요청/결과 로그
유지된 기능:
- Zustand modalDataStore에서 부모 데이터 가져오기
- 무한 깊이 모달 지원
- 완전히 설정 기반 parentDataMapping
- 카티션 곱 조합 생성
- 하드코딩 없는 동적 매핑
문제:
- modalDataStore가 window 전역 변수가 아닌 Zustand store임
- window.__modalDataRegistry로 접근 시도했으나 빈 객체 반환
- 거래처 데이터를 찾을 수 없어 customer_code 매핑 실패
해결:
- useModalDataStore.getState().dataRegistry로 Zustand store 직접 접근
- ModalDataItem[] 배열에서 originalData 추출
- 각 테이블별 데이터를 modalDataStore 객체로 변환
- 거래처(customer_mng), 품목(item_info) 데이터 모두 접근 가능
기술적 변경:
- dynamic import로 Zustand store 로드
- ModalDataItem 구조 이해 및 originalData 추출
- 에러 핸들링 (store 로드 실패 시)
- 상세한 디버깅 로그 (테이블별 데이터 count)
문제:
- 메인 화면(거래처 선택) → 첫 번째 모달(품목 선택) → 두 번째 모달(상세 입력)
- selectedRowsData는 바로 이전 화면 데이터만 제공하여 2단계 이전 데이터 접근 불가
- customer_id가 NULL로 저장됨
해결:
- modalDataStore의 전역 레지스트리에서 모든 누적 데이터 접근
- sourceTable에 따라 적절한 데이터 소스 자동 선택
- 거래처 데이터(customer_mng)를 modalDataStore에서 직접 가져옴
기술적 변경:
- ButtonPrimaryComponent: allComponents에서 componentConfigs 수집 및 전달
- ButtonActionContext: componentConfigs 속성 추가
- handleBatchSave: modalDataStore에서 테이블별 데이터 조회
- parentDataMapping 로직: sourceTable 기반 데이터 소스 자동 감지
- 디버깅 로그 강화 (modalDataStore 키, 데이터 소스 추적)
- 여러 테이블(거래처, 품목 등)에서 데이터를 가져와 자동 매핑 가능
- 각 매핑마다 소스 테이블, 원본 필드, 저장 필드를 독립적으로 설정
- 검색 가능한 Combobox로 테이블 및 컬럼 선택 UX 개선
- 소스 테이블 선택 시 해당 테이블의 컬럼 자동 로드
- 라벨, 컬럼명, 데이터 타입으로 검색 가능
- 세로 레이아웃으로 가독성 향상
기술적 변경사항:
- ParentDataMapping 인터페이스 추가 (sourceTable, sourceField, targetField)
- buttonActions.ts의 handleBatchSave에서 소스 테이블 기반 데이터 소스 자동 판단
- tableManagementApi.getColumnList() 사용하여 테이블 컬럼 동적 로드
- Command + Popover 조합으로 검색 가능한 Select 구현
- 각 매핑별 독립적인 컬럼 상태 관리 (mappingSourceColumns)
문제:
- 조건부 컨테이너 내부의 modal-repeater-table 컴포넌트가 데이터 업데이트 불가
- ConditionalSectionViewer가 RealtimePreview에 formData/onFormDataChange 미전달
해결:
- ConditionalSectionViewer.tsx: RealtimePreview에 formData, onFormDataChange props 추가
- DynamicComponentRenderer.tsx: 디버깅 로그 정리
- ScreenModal.tsx: 디버깅 로그 정리
영향:
- 수주 등록 화면 품목 추가 기능 정상 작동
- 조건부 컨테이너 내부 모든 폼 컴포넌트 데이터 바인딩 정상화
Refs: #수주관리 #modal-repeater-table #ConditionalContainer
- ResizableDialog 콘텐츠 영역에 pointer-events 및 z-index 설정 추가
- TextInputComponent를 제어 컴포넌트에서 비제어 컴포넌트로 변경 (value → defaultValue)
- ItemSelectionModal 및 TextInputComponent 디버그 로그 제거
수정 파일:
- frontend/components/ui/resizable-dialog.tsx
- frontend/lib/registry/components/text-input/TextInputComponent.tsx
- frontend/lib/registry/components/modal-repeater-table/ItemSelectionModal.tsx
- uniqueField 값이 undefined일 때 객체 참조 비교로 폴백
- 멀티셀렉트 모드에서 선택/해제 로직 안정화
- 체크박스 클릭 이벤트 전파 개선
- 유효한 컬럼만 렌더링하도록 필터링 추가
- 디버깅을 위한 콘솔 로그 추가
- 선택된 항목의 uniqueField 값 표시
- 선택항목 상세입력 컴포넌트 확장
- 실시간 가격 계산 기능 추가 (할인율/할인금액, 반올림 방식)
- 카테고리 값 기반 연산 매핑 시스템
- 3단계 드릴다운 방식 설정 UI (메뉴 → 카테고리 → 값 매핑)
- 설정 가능한 계산 로직
- autoCalculation 설정으로 계산 필드명 동적 지정
- valueMapping으로 카테고리 코드와 연산 타입 매핑
- 할인 방식: none/rate/amount
- 반올림 방식: none/round/floor/ceil
- 반올림 단위: 1/10/100/1000
- UI 개선
- 입력 필드 가로 배치 (반응형 Grid)
- 카테고리 타입 필드 옵션 로딩 개선
- 계산 결과 필드 자동 표시 및 읽기 전용 처리
- 날짜 입력 필드 네이티브 피커 지원
- API 연동
- 2레벨 메뉴 목록 조회
- 메뉴별 카테고리 컬럼 조회
- 카테고리별 값 목록 조회
- 문서화
- 기간별 단가 설정 가이드 작성
새로운 그룹화 레이아웃 컴포넌트 2종 추가:
- Section Card: 제목+테두리 기반 명확한 섹션 구분
- Section Paper: 배경색 기반 미니멀한 섹션 구분
주요 변경사항:
- 새 컴포넌트 등록 (각 4개 파일: Component, ConfigPanel, Renderer, index)
- UnifiedPropertiesPanel에 인라인 설정 UI 추가 (280줄)
- DetailSettingsPanel ConfigPanel 인터페이스 통일화 (config → componentConfig)
- getComponentConfigPanel에 동적 import 매핑 추가
- 기존 컴포넌트 타입 정리 (autocomplete, entity-search, modal-repeater)
특징:
- shadcn/ui 기반 일관된 디자인 시스템 준수
- 중첩 박스 금지 원칙 적용
- 반응형 지원 (모바일 우선)
- collapsible 기능 지원 (Section Card)
- 필드 그룹을 Collapsible로 변경하여 펼침/접힘 가능
- 항목 표시 설정도 Collapsible로 분리하여 깔끔하게 정리
- 그룹 제목에 displayItems 개수 표시
- 기본적으로 그룹은 펼쳐진 상태, 표시 설정은 접힌 상태
- ChevronDown/ChevronRight 아이콘으로 펼침 상태 표시
- 복잡한 설정을 단계적으로 볼 수 있어 가독성 대폭 향상
- FieldGroup에 displayItems 추가 (그룹별 독립적인 표시 설정)
- SelectedItemsDetailInputConfig에서 전역 displayItems 제거
- renderDisplayItems에 groupId 파라미터 추가하여 그룹별 설정 사용
- 설정 패널에서 그룹별로 displayItems 관리
- 각 그룹마다 다른 표시 형식 가능 (예: 거래처 정보 vs 단가 정보)
- 그룹의 필드만 선택 가능하도록 필터링
- DisplayItem 타입 추가 (icon, field, text, badge)
- 필드별 표시 형식 지원 (text, currency, number, date, badge)
- 빈 값 처리 옵션 추가 (hide, default, blank)
- 기본값 설정 기능 추가
- 스타일 옵션 추가 (굵게, 밑줄, 기울임, 색상)
- renderDisplayItems 헬퍼 함수로 유연한 표시 렌더링
- SelectedItemsDetailInputConfigPanel에 항목 표시 설정 UI 추가
- displayItems가 없으면 기존 방식(모든 필드 나열)으로 폴백
- handleAddGroupEntry: + 추가 버튼 클릭 시 미리 빈 entry를 배열에 추가
- handleFieldChange: 기존 entry 업데이트만 수행 (새로운 entry 추가 로직 제거)
- 이제 첫 글자 입력 시에도 배열 길이가 변하지 않아 포커스가 유지됨
- 입력 중 onFormDataChange 호출 제거하여 불필요한 리렌더링 방지
- 저장 버튼 클릭 시에만 데이터 전달하도록 변경 (beforeFormSave 이벤트)
- handleSave에서 beforeFormSave 이벤트 발생 및 100ms 대기
- 원본 데이터 표시 버그 수정 (modalData 중첩 구조 처리)
- fieldGroups 구조 감지 로직 수정 (details → fieldGroups)
이제 사용자가 타이핑할 때 포커스가 유지됩니다.
- 데이터 구조 변경: ItemData.details → ItemData.fieldGroups (그룹별 관리)
- 각 필드 그룹마다 독립적으로 여러 항목 추가/수정/삭제 가능
- renderFieldsByGroup: 그룹별 입력 항목 목록 + 편집 + 추가 버튼 구현
- renderGridLayout/renderCardLayout: 품목별 그룹 카드 표시로 단순화
- handleFieldChange: groupId 파라미터 추가 (itemId, groupId, entryId, fieldName, value)
- handleAddGroupEntry, handleRemoveGroupEntry, handleEditGroupEntry 핸들러 추가
- buttonActions handleBatchSave: fieldGroups 구조 처리하도록 수정
- 원본 데이터 표시 버그 수정: modalData의 중첩 구조 처리
사용 예:
- 품목 1
- 그룹 1 (거래처 정보): 3개 항목 입력 가능
- 그룹 2 (단가 정보): 5개 항목 입력 가능
- 각 항목 클릭 → 수정 가능
- 저장 시 모든 입력 항목이 개별 레코드로 저장됨
- Select 컴포넌트에서 빈 문자열 value를 가진 SelectItem 제거
- category/code 타입 필드의 옵션 로딩 디버깅 로그 추가
- 빈 값 필터링으로 'SelectItem must not have empty value' 에러 해결
- codeCategory 자동 감지 로직 디버깅 강화
- InteractiveScreenViewer는 screenId가 아닌 component, allComponents를 받음
- screenApi.getLayout()과 getScreen()으로 화면 데이터 로드
- 로드된 컴포넌트들을 InteractiveScreenViewer로 렌더링
- 화면 로딩 상태 추가
- screenInfo 전달하여 테이블 컨텍스트 제공
- screenManagementApi → screenApi로 변경
- @/lib/api/screenManagement → @/lib/api/screen
- screenApi.getScreens() 사용하여 화면 목록 조회
- ScreenDefinition 타입에 맞게 필드명 수정 (id → screenId)
- ConditionalSection 타입 변경 (components[] → screenId, screenName)
* 각 조건마다 컴포넌트를 직접 배치하는 대신 기존 화면을 선택
* 복잡한 입력 폼도 화면 재사용으로 간단히 구성
- ConditionalSectionDropZone을 ConditionalSectionViewer로 교체
* 드롭존 대신 InteractiveScreenViewer 사용
* 선택된 화면을 조건별로 렌더링
* 디자인 모드에서 화면 미선택 시 안내 메시지 표시
- ConfigPanel에서 화면 선택 드롭다운 구현
* screenManagementApi.getScreenList()로 화면 목록 로드
* 각 섹션마다 화면 선택 Select 컴포넌트
* 선택된 화면의 ID와 이름 자동 저장 및 표시
* 로딩 상태 표시
- 기본 설정 업데이트
* defaultConfig에서 components 제거, screenId 추가
* 모든 섹션 기본값을 screenId: null로 설정
- README 문서 개선
* 화면 선택 방식으로 사용법 업데이트
* 사용 사례에 화면 ID 예시 추가
* 구조 다이어그램 수정 (드롭존 → 화면 표시)
* 디자인/실행 모드 설명 업데이트
장점:
- 기존 화면 재사용으로 생산성 향상
- 복잡한 입력 폼도 간단히 조건부 표시
- 화면 수정 시 자동 반영
- 유지보수 용이
- 품목 검색 모달에서 컬럼명 대신 라벨명 표시
* ItemSelectionModal에 columnLabels prop 추가
* ModalRepeaterTableComponent에서 columns 설정의 라벨 매핑 생성
* 테이블 헤더에 한글 라벨 표시 (품번, 품명, 규격, 재질 등)
- 이미 추가된 품목은 검색 결과에서 완전 제외
* filteredResults로 중복 항목 필터링
* 회색 표시 대신 목록에서 아예 제거
* 사용자 친화적인 안내 메시지 추가
- 수주등록 버튼 크기 및 렌더링 수정
* 기본 크기를 200x40에서 120x40으로 변경 (다른 버튼과 통일)
* h-full w-full 클래스 적용하여 컨테이너 크기에 맞게 렌더링
* style prop의 width/height 제거하여 Tailwind 클래스 우선순위 문제 해결
- 수주등록 모달에 판매 유형 및 무역 정보 추가
* 국내/해외 판매 선택 기능
* 해외 판매 시 무역 정보 섹션 표시 (인코텀즈, 결제조건, 통화 등)
* 거래처 정보 확장 (담당자, 납품처, 납품장소)
- 품목 반복 테이블 컬럼 조정
* 품목번호를 품번으로 변경
* 비고 컬럼 제거
* 규격, 재질 컬럼 추가
* 납품일을 납기일로 변경
- 범용 컴포넌트 3종 개발 및 레지스트리 등록:
* AutocompleteSearchInput: 자동완성 검색 입력 컴포넌트
* EntitySearchInput: 엔티티 검색 모달 컴포넌트
* ModalRepeaterTable: 모달 기반 반복 테이블 컴포넌트
- 수주등록 전용 컴포넌트:
* OrderCustomerSearch: 거래처 검색 (AutocompleteSearchInput 래퍼)
* OrderItemRepeaterTable: 품목 관리 (ModalRepeaterTable 래퍼)
* OrderRegistrationModal: 수주등록 메인 모달
- 백엔드 API:
* Entity 검색 API (멀티테넌시 지원)
* 수주 등록 API (자동 채번)
- 화면 편집기 통합:
* 컴포넌트 레지스트리에 등록
* ConfigPanel을 통한 설정 기능
* 드래그앤드롭으로 배치 가능
- 개발 문서:
* 수주등록_화면_개발_계획서.md (상세 설계 문서)
- 잘못된 API 경로 수정
- 이전: /api/table-type/category-values/{tableName}/{columnName}
- 수정: /api/table-categories/{tableName}/{columnName}/values
- 백엔드 라우트와 일치하도록 변경 (app.ts에서 /api/table-categories로 마운트됨)
- 좌측/우측 패널 카테고리 매핑 로드 API 호출 경로 수정
- 좌측/우측 패널 테이블의 카테고리 타입 컬럼 매핑 로드
- formatCellValue 함수 추가하여 카테고리 코드를 라벨+배지로 변환
- 좌측 패널 테이블 렌더링 부분(그룹화/일반)에 formatCellValue 적용
- 우측 패널 테이블 렌더링 부분에 formatCellValue 적용
- Badge 컴포넌트 import 및 카테고리별 색상 표시
변경 사항:
- 카테고리 매핑 상태 추가 (leftCategoryMappings, rightCategoryMappings)
- API 클라이언트 import 추가
- 카테고리 값 조회 API 호출 useEffect 2개 추가
- 셀 값 포맷팅 함수 formatCellValue 추가
- 모든 테이블 td 렌더링에서 String(value) → formatCellValue() 적용
- ScreenModal에 onRefresh 콜백 추가하여 refreshTable 이벤트 발송
- InteractiveScreenViewerDynamic에 onRefresh, onFlowRefresh prop 추가 및 하위 컴포넌트로 전달
- TableListComponent에 refreshTable 이벤트 리스너 추가
- SplitPanelLayoutComponent에 refreshTable 이벤트 리스너 추가하여 좌/우측 패널 모두 새로고침
- 모달에서 데이터 저장 시 부모 화면의 모든 테이블 컴포넌트가 자동으로 새로고침되도록 개선
변경된 파일:
- frontend/components/common/ScreenModal.tsx
- frontend/components/screen/InteractiveScreenViewerDynamic.tsx
- frontend/lib/registry/components/table-list/TableListComponent.tsx
- frontend/lib/registry/components/split-panel-layout/SplitPanelLayoutComponent.tsx
- 카테고리 색상 설정 시 '배지 없음' 옵션 추가
- color='none'일 때 배지 대신 일반 텍스트로 표시
- CategoryValueEditDialog, CategoryValueAddDialog에 배지 없음 버튼 추가
- InteractiveDataTable, TableListComponent에서 배지 없음 처리
- CategoryValueManager에서 배지 없음 표시 추가
- 기본 색상을 배지 없음으로 변경
- table_column_category_values JOIN 시 회사 데이터만 사용하도록 수정
- 공통 데이터(company_code='*') 사용 금지
- is_active=true 필터 추가로 활성화된 카테고리만 조회
- entityJoinService.ts의 buildJoinQuery 및 buildCountQuery 수정
- 품목 정보 테이블 등에서 발생하던 2배 중복 문제 해결
- category_column_mapping 테이블 생성 (마이그레이션 054)
- 테이블 타입 관리에서 2레벨 메뉴 선택 기능 추가
- 카테고리 컬럼 조회 시 현재 메뉴 및 상위 메뉴 매핑 자동 조회
- 캐시 무효화 로직 개선
- 메뉴별 카테고리 설정 저장 및 불러오기 기능 구현
## 문제점
- URL 직접 입력 모드에서 빈 값으로 저장 시 menu_url은 비워지지만
- screen_code는 기존 값이 남아있어 화면 할당이 해제되지 않음
## 해결방법
### 백엔드 (adminController.ts)
- updateMenu: menu_url이 비어있으면 screen_code도 null로 자동 설정
- 로직: menuUrl ? screenCode : null
### 프론트엔드 (MenuFormModal.tsx, menu.ts)
- 화면 선택 시 screenCode도 함께 formData에 저장
- URL 타입 변경 시 screenCode 초기화
- MenuFormData 인터페이스에 screenCode 필드 추가
## 동작 방식
1. 화면 할당: menuUrl + screenCode 함께 저장
2. URL 직접 입력: menuUrl만 저장, screenCode는 undefined
3. 빈 값 저장: menuUrl = null, screenCode = null (자동)
이제 메뉴에서 화면 할당을 완전히 해제할 수 있습니다.
## 주요 변경사항
### 1. 화면 복사 기능 강화
- 최고 관리자가 다른 회사로 화면 복사 가능하도록 개선
- 메인 화면과 연결된 모달 화면 자동 감지 및 일괄 복사
- 복사 시 버튼의 targetScreenId 자동 업데이트
- 일괄 이름 변경 기능 추가 (복사본 텍스트 제거)
- 중복 화면명 체크 기능 추가
#### 백엔드 (screenManagementService.ts)
- generateMultipleScreenCodes: 여러 화면 코드 일괄 생성 (Advisory Lock 사용)
- detectLinkedModalScreens: edit 액션도 모달로 감지하도록 개선
- checkDuplicateScreenName: 중복 화면명 체크 API 추가
- copyScreenWithModals: 메인+모달 일괄 복사 및 버튼 업데이트
- updateButtonTargetScreenIds: 복사된 모달로 버튼 targetScreenId 업데이트
- updated_date 컬럼 제거 (screen_layouts 테이블에 존재하지 않음)
#### 프론트엔드 (CopyScreenModal.tsx)
- 회사 선택 UI 추가 (최고 관리자 전용)
- 연결된 모달 화면 자동 감지 및 표시
- 일괄 이름 변경 기능 (텍스트 제거/추가)
- 실시간 미리보기
- 중복 화면명 체크
### 2. 버튼 설정 모달 화면 선택 개선
- 편집 중인 화면의 company_code 기준으로 화면 목록 조회
- 최고 관리자가 다른 회사 화면 편집 시 해당 회사의 모달 화면만 표시
- targetScreenId 문자열/숫자 타입 불일치 수정
#### 백엔드 (screenManagementController.ts)
- getScreens API에 companyCode 쿼리 파라미터 추가
- 최고 관리자는 다른 회사의 화면 목록 조회 가능
#### 프론트엔드
- ButtonConfigPanel: currentScreenCompanyCode props 추가
- DetailSettingsPanel: currentScreenCompanyCode 전달
- UnifiedPropertiesPanel: currentScreenCompanyCode 전달
- ScreenDesigner: selectedScreen.companyCode 전달
- targetScreenId 비교 시 parseInt 처리 (문자열→숫자)
### 3. 카테고리 메뉴별 컬럼 분리 기능
- 메뉴별로 카테고리 컬럼을 독립적으로 관리
- 카테고리 컬럼 추가/삭제 시 메뉴 스코프 적용
## 수정된 파일
- backend-node/src/services/screenManagementService.ts
- backend-node/src/controllers/screenManagementController.ts
- backend-node/src/routes/screenManagementRoutes.ts
- frontend/components/screen/CopyScreenModal.tsx
- frontend/components/screen/config-panels/ButtonConfigPanel.tsx
- frontend/components/screen/panels/DetailSettingsPanel.tsx
- frontend/components/screen/panels/UnifiedPropertiesPanel.tsx
- frontend/components/screen/ScreenDesigner.tsx
- frontend/lib/api/screen.ts
문제:
- 분할 패널에서 필터 입력 시 검색이 제대로 작동하지 않음
- 백엔드가 {value: '전자', operator: 'contains'} 형태를 처리하지 못함
원인:
- buildAdvancedSearchCondition이 필터 객체의 value 속성을 추출하지 않음
- 객체를 직접 문자열로 변환하여 '[object Object]'로 검색됨
해결:
1. tableManagementService.buildAdvancedSearchCondition 수정:
- {value, operator} 형태의 필터 객체 감지
- actualValue 추출 및 operator 처리
- 모든 웹타입 케이스에 actualValue 전달
2. 프론트엔드 디버깅 로그 제거:
- SplitPanelLayoutComponent의 console.log 제거
- 필터, 컬럼 가시성, API 호출 로그 정리
테스트 필요:
- 분할 패널에서 필터 입력 → 정상 검색 확인
- 텍스트, 날짜, 숫자, 코드 타입 필터 동작 확인
문제:
1. ColumnVisibilityPanel에서 순서 변경 후 onColumnOrderChange가 호출되지 않음
2. 필터 입력 시 데이터가 제대로 필터링되지 않음
3. useAuth 훅 import 경로 오류 (@/hooks/use-auth → @/hooks/useAuth)
해결:
1. ColumnVisibilityPanel.handleApply()에 onColumnOrderChange 호출 추가
2. 필터 변경 감지 및 데이터 로드 로직 디버깅 로그 추가
3. useAuth import 경로 수정
테스트:
- 거래처관리 화면에서 컬럼 순서 변경 → 실시간 반영 ✅
- 페이지 새로고침 → 순서 유지 (localStorage) ✅
- 필터 입력 → 필터 변경 감지 (추가 디버깅 필요)
문제:
- 분할 패널에서 검색 컴포넌트의 필터/그룹/컬럼 설정이 동작하지 않음
- 테이블 리스트 컴포넌트에 있던 로직이 분할 패널에는 없었음
해결:
1. 필터 처리:
- leftFilters를 searchValues 형식으로 변환
- API 호출 시 필터 조건 전달
- 필터 변경 시 데이터 자동 재로드
2. 컬럼 가시성:
- visibleLeftColumns useMemo 추가
- leftColumnVisibility를 적용하여 표시할 컬럼 필터링
- 렌더링 시 가시성 처리된 컬럼만 표시
3. 그룹화:
- groupedLeftData useMemo 추가
- leftGrouping 배열로 데이터를 그룹화
- 그룹별 헤더와 카운트 표시
4. 테이블 등록:
- columns 속성을 올바르게 참조 (displayColumns → columns)
- 객체/문자열 타입 모두 처리
- 화면 설정에 맞게 테이블 등록
테스트:
- 거래처 관리 화면에서 검색 컴포넌트 버튼 활성화
- 필터 설정 → 데이터 필터링 동작
- 그룹 설정 → 데이터 그룹화 동작
- 테이블 옵션 → 컬럼 가시성/순서 변경 동작
문제:
- displayColumns가 비어있을 때 전체 컬럼을 보여주는 오류
- 화면에 설정된 컬럼만 표시되어야 함
해결:
- displayColumns가 비어있으면 테이블을 등록하지 않음
- displayColumns에 설정된 컬럼만 검색 컴포넌트에 등록
- 화면 관리에서 설정한 컬럼 구성을 정확히 반영
테스트:
- 거래처 관리 화면에서 좌측 테이블의 displayColumns(14개) 정상 표시
- 테이블 옵션/필터 설정/그룹 설정 버튼 정상 작동
- 우측 테이블은 검색 컴포넌트에서 제외
변경 사유:
- 분할 패널은 마스터-디테일 구조로 좌측(마스터)만 독립적으로 검색 가능
- 우측(디테일)은 좌측 선택 항목에 종속되므로 별도 검색 불필요
변경 내용:
- 우측 테이블 registerTable 호출 제거 (주석 처리)
- TableSearchWidget에서 좌측 테이블만 선택 가능
- 우측 테이블 관련 상태(rightFilters, rightGrouping 등)는 내부 로직용으로 유지
효과:
- 분할 패널 사용 시 좌측 마스터 테이블만 검색 설정 가능
- 우측 디테일 테이블은 좌측 선택에 따라 자동 필터링
- 검색 컴포넌트 UI가 더 직관적으로 개선
문제:
- 분할 패널의 테이블 옵션/검색필터 설정/그룹 설정에서 모든 컬럼이 표시됨
- 우측 패널에서 rightTableColumns (전체 컬럼) 사용하여 등록
해결:
- componentConfig.rightPanel?.columns (화면 표시 컬럼)만 등록하도록 수정
- 좌측 패널과 동일한 방식으로 displayColumns 사용
- 의존성 배열도 rightTableColumns → rightPanel.columns로 수정
변경 사항:
- rightTableColumns 대신 displayColumns 사용
- 컬럼 매핑 로직 개선 (col.columnName || col.name || col)
- 화면에 실제 표시되는 컬럼만 설정 UI에 노출
- 테이블 상단 헤더 UI 전체 제거 (AdvancedSearchFilters 영역)
- 테이블 옵션, 필터 설정, 그룹 설정 버튼 제거
- 전체 개수 표시 제거
- 검색 필터 로직은 모두 유지 (상태, 함수, localStorage)
- 해당 기능은 TableSearchWidget 컴포넌트에서 제공 예정
변경 사유:
- 검색 필터 기능을 독립적인 TableSearchWidget으로 분리
- 테이블 컴포넌트와 검색 필터 UI의 관심사 분리
- 재사용 가능한 검색 필터 컴포넌트 구조로 개선
- TableListComponent: grouping 상태 변경 시 groupByColumns 자동 업데이트
- 그룹화 시 카테고리/엔티티/코드 타입 컬럼은 _name 필드 사용
- 그룹 키 생성 시 실제 이름 표시 (코드 대신)
예시:
- 이전: 상태:CATEGORY_159712 > 품번:SLI-2025-0001
- 이후: 상태:완제품 > 품번:SLI-2025-0001
- TableSearchWidgetHeightContext 추가: 위젯 높이 변화 관리
- TableSearchWidget: ResizeObserver로 높이 변화 감지 및 localStorage 저장
- 실제 화면(/screens/[screenId]/page.tsx)에서만 동작 (디자이너 제외)
- TableSearchWidget 아래 컴포넌트들의 Y 위치를 높이 차이만큼 자동 조정
- 화면 로딩 시 저장된 높이 복원 및 컴포넌트 위치 재조정
주요 변경사항:
1. 필터가 여러 줄로 wrap될 때 높이 자동 증가
2. 높이가 늘어난 만큼 아래 컴포넌트들이 자동으로 아래로 이동
3. 새로고침 후에도 설정 유지 (localStorage)
4. 화면 디자이너에서는 기존대로 동작 (영향 없음)
기술 구현:
- Context API로 위젯 높이 전역 관리
- ResizeObserver로 실시간 높이 감지
- localStorage로 사용자별 높이 설정 영구 저장
- 컴포넌트 렌더링 시 동적 Y 위치 계산
- FilterPanel: 필터별 너비(width) 설정 기능 추가 (50-500px)
- TableSearchWidget: 필터가 여러 줄로 자동 wrap되도록 flex-wrap 적용
- TableSearchWidget: 필터 너비 설정을 localStorage에 저장/복원
- InteractiveScreenViewerDynamic: TableSearchWidget의 높이를 auto로 설정하여 콘텐츠에 맞게 자동 조정
- globals.css: 입력 필드 포커스 시 검정 테두리 제거 (combobox, input)
주요 변경사항:
1. 필터 설정에서 각 필터의 표시 너비를 개별 설정 가능
2. 필터가 많을 때 자동으로 여러 줄로 배치 (overflow 방지)
3. 설정된 필터 너비가 새로고침 후에도 유지됨
4. TableSearchWidget 높이가 콘텐츠에 맞게 자동 조정
TODO: TableSearchWidget 높이 변화 시 아래 컴포넌트 자동 재배치 기능 구현 예정
- 모든 필터 입력창 높이 통일 (h-9, 36px)
- 실시간 검색: 입력 시 즉시 필터 적용 (검색 버튼 제거)
- 초기화 버튼 추가: 모든 필터값을 한번에 리셋
- filters → searchValues 자동 변환 로직 추가
- select 필터: 선택된 값의 라벨 저장하여 데이터 없을 때도 표시 유지
- select 옵션 초기 로드 후 계속 유지 (dataCount 변경 시에도 유지)
주요 개선사항:
1. Input, Select, Date 등 모든 필터의 높이가 동일하게 표시
2. 사용자가 값을 입력하면 바로 테이블이 필터링됨
3. 초기화 버튼으로 간편하게 모든 필터 제거 가능
4. 필터링 결과가 0건이어도 select 박스의 선택값이 유지됨
알려진 제한사항:
- 카테고리/엔티티 필터는 현재 테이블 데이터 기반으로만 옵션 표시
(전체 정의된 카테고리 값이 아닌, 실제 데이터에 있는 값만 표시)
- TableRegistration에 getColumnUniqueValues 콜백 함수 추가
- TableListComponent에서 현재 데이터의 고유 값 추출 함수 구현
- TableSearchWidget에서 select 타입 필터의 옵션을 자동으로 로드
- 테이블 데이터가 변경되면 필터 옵션도 자동 업데이트
- 데이터 건수 표시 기능도 함께 수정 (등록 순서 문제 해결)
- TableOptionsContext 기반 테이블 자동 감지 시스템 구현
- 독립 위젯으로 드래그앤드롭 배치 가능
- 3가지 기능: 컬럼 가시성, 필터 설정, 그룹 설정
- FlowWidget, TableList, SplitPanel 등 모든 테이블 컴포넌트 지원
- 유틸리티 카테고리에 등록 (1920×80px)
- 위젯 크기 제어 가이드 룰 파일에 추가
**문제:**
- 화면 편집기에서 버튼의 스타일(색상, 폰트 등)을 변경해도 실시간으로 반영되지 않음
- 저장 후 실제 화면에서는 정상적으로 보임
**원인:**
- ButtonPrimaryComponent에서 isInteractive 모드일 때만 component.style을 적용
- 디자인 모드(isDesignMode)에서는 사용자 정의 스타일이 무시됨
**해결:**
- buttonElementStyle에 component.style을 항상 적용하도록 수정
- width/height는 레이아웃 충돌 방지를 위해 제외 유지
- 디자인 모드와 인터랙티브 모드 모두에서 스타일 실시간 반영
**영향:**
- 화면 편집기에서 버튼 스타일 변경 시 즉시 미리보기 가능
- 저장하지 않아도 시각적 피드백 제공
**주요 변경사항:**
1. **메뉴 스코프 변경 (getSiblingMenuObjids)**
- 기존: 형제 메뉴 + 모든 형제의 자식 메뉴 포함
- 변경: 자신 + 자신의 자식 메뉴만 포함
- 결과: 각 2레벨 메뉴가 완전히 독립적으로 격리됨
2. **채번 규칙 메뉴 선택 상태 유지**
- useState 초기값 함수에서 저장된 selectedMenuObjid 복원
- 속성창 닫았다 열어도 선택한 메뉴와 채번 규칙 유지
- config.autoGeneration.selectedMenuObjid에 저장
3. **로그 정리**
- 프론트엔드: 디버깅 로그 제거
- 백엔드: info 레벨 로그를 debug 레벨로 변경
- 운영 환경에서 불필요한 로그 출력 최소화
**영향:**
- 영업관리 메뉴: 영업관리의 채번 규칙/코드만 조회
- 기준정보 메뉴: 기준정보의 채번 규칙/코드만 조회
- 각 메뉴 그룹이 독립적으로 데이터 관리 가능