diff --git a/.cursor/mcp.json b/.cursor/mcp.json index 7a87d1a0..84a8729c 100644 --- a/.cursor/mcp.json +++ b/.cursor/mcp.json @@ -3,6 +3,10 @@ "agent-orchestrator": { "command": "node", "args": ["/Users/gbpark/ERP-node/mcp-agent-orchestrator/build/index.js"] + }, + "Framelink Figma MCP": { + "command": "npx", + "args": ["-y", "figma-developer-mcp", "--figma-api-key=figd_NrYdIWf-CnC23NyH6eMym7sBdfbZTuXyS91tI3VS", "--stdio"] } } } diff --git a/.gitignore b/.gitignore index 24814953..ff1bb5b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Claude Code (로컬 전용 - Git 제외) +.claude/ + # Dependencies node_modules/ npm-debug.log* @@ -293,4 +296,12 @@ uploads/ claude.md -.cursor/mcp.json \ No newline at end of file +.cursor/mcp.json + +# AI 에이전트 테스트 산출물 +*-test-screenshots/ +*-screenshots/ +*-test.mjs + +# 개인 작업 문서 (popdocs) +popdocs/ \ No newline at end of file diff --git a/PLAN.MD b/PLAN.MD index 0eff7965..45468fa4 100644 --- a/PLAN.MD +++ b/PLAN.MD @@ -1,139 +1,548 @@ -# 프로젝트: V2/V2 컴포넌트 설정 스키마 정비 +# 현재 구현 계획: pop-dashboard 4가지 아이템 모드 완성 -## 개요 - -레거시 컴포넌트를 제거하고, V2/V2 컴포넌트 전용 Zod 스키마와 기본값 레지스트리를 한 곳에서 관리한다. - -## 핵심 기능 - -1. [x] 레거시 컴포넌트 스키마 제거 -2. [x] V2 컴포넌트 overrides 스키마 정의 (16개) -3. [x] V2 컴포넌트 overrides 스키마 정의 (9개) -4. [x] componentConfig.ts 한 파일에서 통합 관리 - -## 정의된 V2 컴포넌트 (18개) - -- v2-table-list, v2-button-primary, v2-text-display -- v2-split-panel-layout, v2-section-card, v2-section-paper -- v2-divider-line, v2-repeat-container, v2-rack-structure -- v2-numbering-rule, v2-category-manager, v2-pivot-grid -- v2-location-swap-selector, v2-aggregation-widget -- v2-card-display, v2-table-search-widget, v2-tabs-widget -- v2-v2-repeater - -## 정의된 V2 컴포넌트 (9개) - -- v2-input, v2-select, v2-date -- v2-list, v2-layout, v2-group -- v2-media, v2-biz, v2-hierarchy - -## 테스트 계획 - -### 1단계: 기본 기능 - -- [x] V2 레이아웃 저장 시 컴포넌트별 overrides 스키마 검증 통과 -- [x] V2 컴포넌트 기본값과 스키마가 매칭됨 - -### 2단계: 에러 케이스 - -- [x] 잘못된 overrides 입력 시 Zod 검증 실패 처리 (safeParse + console.warn + graceful fallback) -- [x] 누락된 기본값 컴포넌트 저장 시 안전한 기본값 적용 (레지스트리 조회 → 빈 객체) - -## 에러 처리 계획 - -- 스키마 파싱 실패 시 로그/에러 메시지 표준화 -- 기본값 누락 시 안전한 fallback 적용 - -## 진행 상태 - -- [x] 레거시 컴포넌트 제거 완료 -- [x] V2/V2 스키마 정의 완료 -- [x] 한 파일 통합 관리 완료 - -# 프로젝트: 화면 복제 기능 개선 (DB 구조 개편 후) - -## 개요 - -채번/카테고리에서 `menu_objid` 의존성 제거 완료 후, 화면 복제 기능을 새 DB 구조에 맞게 수정하고 테스트합니다. - -## 핵심 변경사항 - -### DB 구조 변경 (완료) - -- 채번규칙: `menu_objid` 의존성 제거 → `table_name + column_name + company_code` 기반 -- 카테고리: `menu_objid` 의존성 제거 → `table_name + column_name + company_code` 기반 -- 복제 순서 의존성 문제 해결 - -### 복제 옵션 정리 (완료) - -- [x] **삭제**: 코드 카테고리 + 코드 복사 옵션 -- [x] **삭제**: 연쇄관계 설정 복사 옵션 -- [x] **이름 변경**: "카테고리 매핑 + 값 복사" → "카테고리 값 복사" - -### 현재 복제 옵션 (3개) - -1. **채번 규칙 복사** - 채번규칙 복제 -2. **카테고리 값 복사** - 카테고리 값 복제 (table_column_category_values) -3. **테이블 타입관리 입력타입 설정 복사** - table_type_columns 복제 +> **작성일**: 2026-02-10 +> **상태**: 코딩 완료 (방어 로직 패치 포함) +> **목적**: 대시보드 설정 패널의 미구현/버그 4건을 수정하여 KPI카드, 차트, 게이지, 통계카드 모두 실제 데이터로 동작하도록 완성 --- -## 테스트 계획 +## 1. 문제 요약 -### 1. 화면 간 연결 복제 테스트 +pop-dashboard 컴포넌트의 4가지 아이템 모드 중 **설정 UI가 누락**되거나 **데이터 처리 로직에 버그**가 있어 실제 테스트 불가. -- [ ] 수주관리 1번→2번→3번→4번 화면 연결 상태에서 복제 -- [ ] 복제 후 연결 관계가 유지되는지 확인 -- [ ] 각 화면의 고유 키값이 새로운 화면을 참조하도록 변경되는지 확인 - -### 2. 제어관리 복제 테스트 - -- [ ] 다른 회사로 제어관리 복제 -- [ ] 복제된 플로우 스텝/연결이 정상 작동하는지 확인 - -### 3. 추가 옵션 복제 테스트 - -- [ ] 채번규칙 복사 정상 작동 확인 -- [ ] 카테고리 값 복사 정상 작동 확인 -- [ ] 테이블 타입관리 입력타입 설정 복사 정상 작동 확인 - -### 4. 기본 복제 테스트 - -- [ ] 단일 화면 복제 (모달 포함) -- [ ] 그룹 전체 복제 (재귀적) -- [ ] 메뉴 동기화 정상 작동 +| # | 문제 | 심각도 | 영향 | +|---|------|--------|------| +| BUG-1 | 차트: groupBy 설정 UI 없음 | 높음 | 차트가 단일 값만 표시, X축 카테고리 분류 불가 | +| BUG-2 | 차트: xAxisColumn 설정 UI 없음 | 높음 | groupBy 결과의 컬럼명과 xKey 불일치로 차트 빈 화면 | +| BUG-3 | 통계 카드: 카테고리 설정 UI 없음 | 높음 | statConfig.categories를 설정할 방법 없음 | +| BUG-4 | 통계 카드: 카테고리별 필터 미적용 | 높음 | 모든 카테고리에 동일 값(rows.length) 입력되는 버그 | --- -## 관련 파일 +## 2. 수정 대상 파일 (2개) -- `frontend/components/screen/CopyScreenModal.tsx` - 복제 모달 -- `frontend/components/screen/ScreenGroupTreeView.tsx` - 트리 뷰 + 컨텍스트 메뉴 -- `backend-node/src/services/screenManagementService.ts` - 복제 서비스 -- `backend-node/src/services/numberingRuleService.ts` - 채번규칙 서비스 -- `docs/DB_STRUCTURE_DIAGRAM.md` - DB 구조 문서 +### 파일 A: `frontend/lib/registry/pop-components/pop-dashboard/PopDashboardConfig.tsx` -## 진행 상태 +**변경 유형**: 설정 UI 추가 3건 + +#### 변경 A-1: DataSourceEditor에 groupBy 설정 추가 (라인 253~362 부근, 집계 함수 아래) + +집계 함수가 선택된 상태에서 "그룹핑 컬럼"을 선택할 수 있는 드롭다운 추가. + +**추가할 위치**: `{/* 집계 함수 + 대상 컬럼 */}` 블록 다음, `{/* 자동 새로고침 */}` 블록 이전 + +**추가할 코드** (약 50줄): + +```tsx +{/* 그룹핑 (차트용 X축 분류) */} +{dataSource.aggregation && ( +
+ 차트에서 X축 카테고리로 사용됩니다 +
++ 그룹핑 컬럼명과 동일하게 입력. 비우면 첫 번째 groupBy 컬럼 사용 +
++ 카테고리를 추가하면 각 조건에 맞는 건수가 표시됩니다 +
+ )} ++ 다른 테이블의 카테고리 값 참조 시 입력 +
+화면 데이터가 없습니다.
diff --git a/frontend/components/numbering-rule/NumberingRuleCard.tsx b/frontend/components/numbering-rule/NumberingRuleCard.tsx index d1444d4e..e9731017 100644 --- a/frontend/components/numbering-rule/NumberingRuleCard.tsx +++ b/frontend/components/numbering-rule/NumberingRuleCard.tsx @@ -25,7 +25,7 @@ export const NumberingRuleCard: React.FC- 규칙 사이에 들어갈 문자입니다 -
-규칙을 추가하여 코드를 구성하세요
데이터 바인딩
-- Phase 4에서 구현 예정 -
-연결 없음
++ 이 컴포넌트는 다른 컴포넌트와 연결할 수 없습니다 +
+연결 수정
+ +새 연결 추가
+ )} + + {/* 보내는 값 */} +필터할 컬럼
+ + {dbColumnsLoading ? ( +화면 표시 컬럼
+ {displayColumns.map((col) => ( +데이터 전용 컬럼
+ {dataOnlyColumns.map((col) => ( ++ {filterColumns.length}개 컬럼 중 하나라도 일치하면 표시 +
+ )} + + {/* 필터 방식 */} +필터 방식
+ ++ {r.description} +
+ )} +연결된 소스
+ {incoming.map((conn) => { + const sourceComp = allComponents.find( + (c) => c.id === conn.sourceComponent + ); + return ( ++ 아직 연결된 소스가 없습니다. 보내는 컴포넌트에서 연결을 설정하세요. +
+ )} +화면 데이터가 없습니다.
diff --git a/frontend/components/screen/InteractiveScreenViewerDynamic.tsx b/frontend/components/screen/InteractiveScreenViewerDynamic.tsx index e2143e8e..05d228f4 100644 --- a/frontend/components/screen/InteractiveScreenViewerDynamic.tsx +++ b/frontend/components/screen/InteractiveScreenViewerDynamic.tsx @@ -571,8 +571,38 @@ export const InteractiveScreenViewerDynamic: React.FC테이블, 반복 필드 그룹 등 데이터를 제공하는 컴포넌트
++ 레이어별로 다른 테이블이 있을 경우 "자동 탐색"을 선택하면 현재 활성화된 레이어의 테이블을 자동으로 사용합니다 +
타겟 테이블에 저장될 필드명
+추가 데이터가 저장될 타겟 테이블 컬럼
- 소스 필드를 타겟 필드에 매핑합니다. 비워두면 같은 이름의 필드로 자동 매핑됩니다. + 여러 소스 테이블에서 데이터를 전달할 때, 각 테이블별로 매핑 규칙을 설정합니다. 런타임에 소스 테이블을 자동 감지합니다.
- {!config.action?.dataTransfer?.sourceTable || !config.action?.dataTransfer?.targetTable ? ( + {!config.action?.dataTransfer?.targetTable ? (먼저 소스 테이블과 타겟 테이블을 선택하세요.
+먼저 타겟 테이블을 선택하세요.
- 매핑 규칙이 없습니다. 같은 이름의 필드로 자동 매핑됩니다. + 매핑 그룹이 없습니다. 소스 테이블을 추가하세요.
소스 테이블을 먼저 선택하세요.
+ ) : activeRules.length === 0 ? ( +매핑 없음 (동일 필드명 자동 매핑)
+ ) : ( + activeRules.map((rule: any, rIdx: number) => { + const popoverKeyS = `${activeMappingGroupIndex}-${rIdx}-s`; + const popoverKeyT = `${activeMappingGroupIndex}-${rIdx}-t`; + return ( ++ {config.detailTable + ? allTables.find((t) => t.tableName === config.detailTable)?.displayName || config.detailTable + : "미설정"} +
+ {config.detailTable && config.foreignKey && ( ++ FK: {config.foreignKey} → {currentTableName || "메인 테이블"}.id +
+ )} ++ 메인 FK와 부모-자식 계층 FK를 선택하세요 +
+ + {fkCandidateColumns.length > 0 ? ( ++ {loadingColumns ? "로딩 중..." : "디테일 테이블을 먼저 선택하세요"} +
++ 트리 노드에 표시할 품목 정보의 소스 엔티티 +
+ + {entityColumns.length > 0 ? ( + + ) : ( ++ {loadingColumns + ? "로딩 중..." + : !config.detailTable + ? "디테일 테이블을 먼저 선택하세요" + : "엔티티 타입 컬럼이 없습니다"} +
+선택된 엔티티
+참조 테이블: {config.dataSource.sourceTable}
+FK 컬럼: {config.dataSource.foreignKey}
++ BOM 변경 이력과 버전 관리에 사용할 테이블을 선택하세요 +
+ +{currentTableName}
++ 컬럼 {detailTableColumns.length}개 / 엔티티 {entityColumns.length}개 +
++ 트리 노드에 표시할 소스/디테일 컬럼을 선택하세요 +
+ + {/* 소스 테이블 컬럼 (표시용) */} + {config.dataSource?.sourceTable && ( + <> +로딩 중...
+ ) : sourceTableColumns.length === 0 ? ( +컬럼 정보가 없습니다
+ ) : ( +로딩 중...
+ ) : displayableColumns.length === 0 ? ( +컬럼 정보가 없습니다
+ ) : ( +테이블
+{config.categoryTable || tableName || "-"}
+컬럼
+{config.categoryColumn || columnName || "-"}
+화면 로드 시 자동 선택될 카테고리 값
++ 카테고리 값이 없습니다. 테이블 카테고리 관리에서 값을 추가해주세요. +
+ )} +테이블 컬럼을 조회할 수 없습니다. 테이블 타입 관리에서 참조 테이블을 설정해주세요.
)} + + {config.entityTable && entityColumns.length > 0 && ( ++ 같은 폼에 참조 테이블({config.entityTable})의 컬럼이 배치되어 있으면, 엔티티 선택 시 해당 필드가 자동으로 + 채워집니다. +
+