- contentRows 기반 자유 레이아웃 지원 (header/aggregation/table/fields 타입)
- aggregationFields, tableColumns 직접 참조하도록 렌더링 로직 수정
- groupByField 없어도 grouping.enabled면 그룹핑 모드로 처리
- buttonActions에서 selectedRowsData를 모달 이벤트로 전달
- ScreenModal에서 selectedData를 groupedData props로 컴포넌트에 전달
- types.ts에 CardContentRowConfig, AggregationDisplayConfig 인터페이스 추가
- 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
- 같은 수주번호(order_no)를 가진 품목 일괄 수정 기능 추가
- groupByColumns 개념 도입 및 EditModal 그룹 데이터 처리 로직 구현
- ConditionalSectionViewer에서 DynamicComponentRenderer 사용으로 groupedData 전달 경로 확보
- ModalRepeaterTable onChange 에러 수정 및 sourceColumns 필터링 추가
- 조인된 컬럼 제외 로직 추가로 DB 저장 오류 해결
문제:
- targetTable이 메인 테이블과 동일할 때 헤더 단독 저장 + Repeater 병합 저장으로 2번 INSERT 발생
- 같은 수주번호로 헤더만 있는 레코드와 전체 데이터 레코드가 중복 생성됨
해결:
- Repeater를 병합/분리 모드로 분류하는 로직 추가
- 병합 모드: 헤더+품목을 통합하여 품목당 1개 레코드로 저장
- 분리 모드: 헤더와 품목을 별도 테이블에 저장
- 헤더 단독 INSERT 제거로 중복 방지
영향:
- 단일 테이블 구조에서 품목별 레코드 생성 방식으로 변경
- 확장/축소 UI를 통한 품목별 조회 지원
- 백엔드: 배열 객체 형식 Repeater 데이터 처리 로직 추가
- 백엔드: Repeater 저장 시 company_code 자동 주입
- 백엔드: 부모 테이블 데이터 자동 병합 (targetTable = tableName)
- 프론트엔드: beforeFormSave 이벤트로 formData 주입
- 프론트엔드: _targetTable 메타데이터 전달
- 프론트엔드: ComponentRendererProps 상속 및 Renderer 단순화
멀티테넌시 및 부모-자식 관계 자동 처리로
복잡한 배열 데이터 저장 안정성 확보
- buttonActions.ts: formData가 배열인 경우 일반 저장 건너뜀
- SelectedItemsDetailInput이 UPSERT를 완료한 후 일반 저장이 실행되어 null 레코드가 삽입되던 문제 해결
- ScreenModal에서 그룹 레코드를 배열로 전달하는 경우 감지하여 처리
- skipDefaultSave 플래그가 제대로 작동하지 않던 문제 근본 해결
변경사항:
- 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)
- 선택항목 상세입력 컴포넌트 확장
- 실시간 가격 계산 기능 추가 (할인율/할인금액, 반올림 방식)
- 카테고리 값 기반 연산 매핑 시스템
- 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)
- 입력 중 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 자동 감지 로직 디버깅 강화
- ConditionalSection 타입 변경 (components[] → screenId, screenName)
* 각 조건마다 컴포넌트를 직접 배치하는 대신 기존 화면을 선택
* 복잡한 입력 폼도 화면 재사용으로 간단히 구성
- ConditionalSectionDropZone을 ConditionalSectionViewer로 교체
* 드롭존 대신 InteractiveScreenViewer 사용
* 선택된 화면을 조건별로 렌더링
* 디자인 모드에서 화면 미선택 시 안내 메시지 표시
- ConfigPanel에서 화면 선택 드롭다운 구현
* screenManagementApi.getScreenList()로 화면 목록 로드
* 각 섹션마다 화면 선택 Select 컴포넌트
* 선택된 화면의 ID와 이름 자동 저장 및 표시
* 로딩 상태 표시
- 기본 설정 업데이트
* defaultConfig에서 components 제거, screenId 추가
* 모든 섹션 기본값을 screenId: null로 설정
- README 문서 개선
* 화면 선택 방식으로 사용법 업데이트
* 사용 사례에 화면 ID 예시 추가
* 구조 다이어그램 수정 (드롭존 → 화면 표시)
* 디자인/실행 모드 설명 업데이트
장점:
- 기존 화면 재사용으로 생산성 향상
- 복잡한 입력 폼도 간단히 조건부 표시
- 화면 수정 시 자동 반영
- 유지보수 용이
- 범용 컴포넌트 3종 개발 및 레지스트리 등록:
* AutocompleteSearchInput: 자동완성 검색 입력 컴포넌트
* EntitySearchInput: 엔티티 검색 모달 컴포넌트
* ModalRepeaterTable: 모달 기반 반복 테이블 컴포넌트
- 수주등록 전용 컴포넌트:
* OrderCustomerSearch: 거래처 검색 (AutocompleteSearchInput 래퍼)
* OrderItemRepeaterTable: 품목 관리 (ModalRepeaterTable 래퍼)
* OrderRegistrationModal: 수주등록 메인 모달
- 백엔드 API:
* Entity 검색 API (멀티테넌시 지원)
* 수주 등록 API (자동 채번)
- 화면 편집기 통합:
* 컴포넌트 레지스트리에 등록
* ConfigPanel을 통한 설정 기능
* 드래그앤드롭으로 배치 가능
- 개발 문서:
* 수주등록_화면_개발_계획서.md (상세 설계 문서)
**주요 변경사항:**
1. **메뉴 스코프 변경 (getSiblingMenuObjids)**
- 기존: 형제 메뉴 + 모든 형제의 자식 메뉴 포함
- 변경: 자신 + 자신의 자식 메뉴만 포함
- 결과: 각 2레벨 메뉴가 완전히 독립적으로 격리됨
2. **채번 규칙 메뉴 선택 상태 유지**
- useState 초기값 함수에서 저장된 selectedMenuObjid 복원
- 속성창 닫았다 열어도 선택한 메뉴와 채번 규칙 유지
- config.autoGeneration.selectedMenuObjid에 저장
3. **로그 정리**
- 프론트엔드: 디버깅 로그 제거
- 백엔드: info 레벨 로그를 debug 레벨로 변경
- 운영 환경에서 불필요한 로그 출력 최소화
**영향:**
- 영업관리 메뉴: 영업관리의 채번 규칙/코드만 조회
- 기준정보 메뉴: 기준정보의 채번 규칙/코드만 조회
- 각 메뉴 그룹이 독립적으로 데이터 관리 가능
- 메뉴 클릭 시 localStorage에 메뉴 이름 저장 (useMenu, AppLayout)
- 엑셀 다운로드 시 localStorage의 메뉴 이름을 파일명으로 사용
- 백엔드 카테고리 컬럼 조회 쿼리 파라미터 버그 수정
- API 호출 시 불필요한 autoFilter 파라미터 제거
파일명 형식: {메뉴이름}_{날짜}.xlsx
예시: 품목등록테스트_2025-11-11.xlsx
- 화면 편집기 컬럼 설정 기반 다운로드 (visible 컬럼만)
- 필터 조건 적용 (필터링된 데이터만 다운로드)
- 한글 라벨명 표시 (column_labels 테이블 조회)
- Entity 조인 값 표시 (writer → writer_name 등)
- 카테고리 타입 라벨 변환 (코드 → 라벨)
- 멀티테넌시 보안 강화 (autoFilter: true)
- 디버깅 로그 정리
변경된 파일:
- frontend/lib/utils/buttonActions.ts
- frontend/lib/registry/components/table-list/TableListComponent.tsx
관련 이슈: #엑셀다운로드개선
- 문제: 속성 패널에서 너비/높이 입력 시 격자 시스템이 자동으로 값을 변경
- 원인: updateComponentProperty에서 size.width/height 변경 시 무조건 격자 스냅 적용
- 해결: 직접 입력 시에는 격자 스냅을 적용하지 않도록 로직 주석 처리
- 영향:
- 속성 패널에서 원하는 크기로 자유롭게 설정 가능
- 드래그/리사이즈 시에는 별도 로직에서 격자 스냅 처리
- 디버깅 로그 제거