85 lines
12 KiB
JSON
85 lines
12 KiB
JSON
{
|
||
"featureDescription": "Phase E: 테이블 드롭 → 자동 화면 생성 시스템\n\n## 목표\n테이블을 캔버스에 드롭하면 \"화면 자동 생성\" 모달이 열리고,\n사용자가 형태(목록형/폼형/마스터-디테일/카드형)와 컬럼을 선택하면\n메타 컴포넌트(Search + DataView + Action + Modal/Field) 세트가 자동 생성된다.\n\n## 구현 파일\n\n### 1. 자동 생성 모달 컴포넌트 (신규)\n**파일**: `frontend/lib/meta-components/auto-generate/AutoGenerateModal.tsx`\n\nprops:\n```typescript\ninterface AutoGenerateModalProps {\n isOpen: boolean;\n onClose: () => void;\n tableName: string;\n tableLabel: string;\n columns: { columnName: string; label: string; webType: string; required: boolean; }[];\n onGenerate: (config: AutoGenerateConfig) => void;\n}\n\ninterface AutoGenerateConfig {\n templateType: \"list\" | \"form\" | \"master-detail\" | \"card\";\n selectedColumns: string[];\n includeSearch: boolean;\n includeCrud: boolean; // CRUD 버튼 포함 여부\n includeModal: boolean; // 등록/수정 모달 포함 여부\n}\n```\n\nUI 구성:\n```\n┌─────────────────────────────────────┐\n│ 화면 자동 생성 [×] │\n├─────────────────────────────────────┤\n│ 테이블: sales_order_mng (수주관리) │\n│ │\n│ 어떤 형태로 만들까요? │\n│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │\n│ │목록형│ │폼형 │ │마디 │ │카드 │ │\n│ │ ≡≡≡ │ │ □□ │ │≡≡│□│ │ ▦▦▦ │ │\n│ └─────┘ └─────┘ └─────┘ └─────┘ │\n│ │\n│ 포함할 컬럼: │\n│ ☑ order_no (수주번호) │\n│ ☑ customer_code (거래처) │\n│ ☑ order_date (수주일) │\n│ ☐ created_by (생성자) [숨김 추천] │\n│ │\n│ 옵션: │\n│ ☑ 검색 바 포함 │\n│ ☑ CRUD 버튼 포함 │\n│ ☑ 등록/수정 모달 포함 │\n│ │\n│ [생성하기] │\n└─────────────────────────────────────┘\n```\n\n- shadcn Dialog 사용 (max-w-[95vw] sm:max-w-[600px])\n- 템플릿 타입은 4개 카드로 선택 (선택 시 border-primary)\n- 컬럼 목록은 체크박스로 선택/해제\n- created_by, updated_at, created_date 등 시스템 컬럼은 기본 체크 해제 + \"[숨김 추천]\" 표시\n- \"use client\" 선언\n\n### 2. 자동 생성 로직 (신규)\n**파일**: `frontend/lib/meta-components/auto-generate/generateComponents.ts`\n\n```typescript\nexport function generateComponents(\n tableName: string,\n tableLabel: string,\n config: AutoGenerateConfig,\n columns: ColumnInfo[],\n startX: number,\n startY: number\n): ComponentData[]\n```\n\ntemplateType별 생성 로직:\n\n**목록형 (list)**:\n1. Search 컴포넌트 (mode: \"combined\", y: startY)\n2. Action 그룹 (등록/삭제 버튼, y: startY + 60)\n3. DataView 컴포넌트 (viewMode: \"table\", y: startY + 110)\n4. Modal 컴포넌트 (trigger: \"button\", form, y: startY + 510)\n\n**폼형 (form)**:\n1. Field 컴포넌트들 (selectedColumns 각각, 2열 그리드 배치)\n2. Action 그룹 (저장/취소 버튼)\n\n**마스터-디테일 (master-detail)**:\n1. Layout (mode: \"columns\", areas: [\"master\", \"detail\"])\n2. 좌측(master): Search + DataView (table)\n3. 우측(detail): Field 컴포넌트들 + Action (저장)\n\n**카드형 (card)**:\n1. Search 컴포넌트 (mode: \"simple\")\n2. DataView 컴포넌트 (viewMode: \"card\")\n\n각 컴포넌트는 ComponentData 형태로:\n```typescript\n{\n id: generateComponentId(),\n componentType: \"meta-field\" | \"meta-dataview\" | ...,\n position: { x, y, z: 1 },\n size: { width, height },\n layerId: 1,\n componentConfig: { ... },\n style: { labelDisplay: true, ... }\n}\n```\n\n시스템 컬럼 판별 함수:\n```typescript\nconst SYSTEM_COLUMNS = [\"created_by\", \"updated_by\", \"created_date\", \"updated_date\", \"created_at\", \"updated_at\", \"writer\", \"company_code\"];\nfunction isSystemColumn(name: string): boolean {\n return SYSTEM_COLUMNS.includes(name.toLowerCase());\n}\n```\n\n### 3. index.ts 업데이트\n**파일**: `frontend/lib/meta-components/auto-generate/index.ts`\nexport { AutoGenerateModal } from \"./AutoGenerateModal\";\nexport { generateComponents } from \"./generateComponents\";\n\n**파일**: `frontend/lib/meta-components/index.ts`에 추가\nexport { AutoGenerateModal, generateComponents } from \"./auto-generate\";\n\n### 4. ScreenDesigner.tsx 수정\n기존 `type === \"table\"` 분기 수정:\n\n현재 코드 (line ~3916):\n```typescript\nif (type === \"table\") {\n // 테이블 컨테이너 생성\n newComponent = { ... };\n}\n```\n\n변경:\n```typescript\nif (type === \"table\") {\n // V3 자동 화면 생성 모달 열기\n setAutoGenTable(table);\n setAutoGenOpen(true);\n return; // 기존 로직 대신 모달로 처리\n}\n```\n\n추가할 state:\n```typescript\nconst [autoGenOpen, setAutoGenOpen] = useState(false);\nconst [autoGenTable, setAutoGenTable] = useState<TableInfo | null>(null);\n```\n\n추가할 handler:\n```typescript\nconst handleAutoGenerate = useCallback((config: AutoGenerateConfig) => {\n if (!autoGenTable) return;\n const rect = canvasRef.current?.getBoundingClientRect();\n const components = generateComponents(\n autoGenTable.tableName,\n autoGenTable.tableLabel || autoGenTable.tableName,\n config,\n autoGenTable.columns || [],\n 100, // startX\n 100, // startY\n );\n const newLayout = {\n ...layout,\n components: [...layout.components, ...components],\n };\n setLayout(newLayout);\n saveToHistory(newLayout);\n setAutoGenOpen(false);\n setAutoGenTable(null);\n toast.success(`${components.length}개의 메타 컴포넌트가 자동 생성되었습니다.`);\n}, [autoGenTable, layout, saveToHistory]);\n```\n\nJSX에 모달 추가 (return 문 맨 끝에):\n```tsx\n<AutoGenerateModal\n isOpen={autoGenOpen}\n onClose={() => { setAutoGenOpen(false); setAutoGenTable(null); }}\n tableName={autoGenTable?.tableName || \"\"}\n tableLabel={autoGenTable?.tableLabel || autoGenTable?.tableName || \"\"}\n columns={(autoGenTable?.columns || []).map(c => ({\n columnName: c.columnName,\n label: c.columnLabel || c.columnName,\n webType: c.widgetType || \"text\",\n required: c.isNullable === \"NO\",\n }))}\n onGenerate={handleAutoGenerate}\n/>\n```\n\n## 기술 요구사항\n- \"use client\" 선언\n- shadcn/ui: Dialog, Button, Checkbox, Label, Badge, Separator\n- cn() 유틸리티\n- lucide-react: Table, FormInput, Columns, LayoutGrid, Check, X 등\n- 반응형: text-xs sm:text-sm, h-8 sm:h-10\n- ComponentData 타입은 기존 ScreenDesigner에서 사용하는 것 그대로\n- generateComponentId 함수: `comp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`\n- 테이블 드롭 시 기존 컬럼 정보(columns)가 TableInfo에 포함되어 있어야 함\n\n## 주의사항\n- ScreenDesigner.tsx는 거대 파일 - 최소 변경만\n- 기존 컬럼 드롭 (type === \"column\") 로직은 건드리지 않기\n- TableInfo 타입에 columns 배열이 있는지 확인하고 없으면 빈 배열 처리\n- import 경로 정확히: `import { AutoGenerateModal, generateComponents } from \"@/lib/meta-components\"`",
|
||
"round": 2,
|
||
"maxRounds": 5,
|
||
"agents": [
|
||
"frontend"
|
||
],
|
||
"messages": [
|
||
{
|
||
"round": 1,
|
||
"from": "frontend",
|
||
"type": "implementation",
|
||
"content": "Phase E 테이블 드롭 → 자동 화면 생성 시스템 구현 완료\n\n사용자가 테이블을 캔버스에 드롭하면 '화면 자동 생성' 모달이 열리고, 템플릿 타입(목록형/폼형/마스터-디테일/카드형)과 컬럼을 선택하면 메타 컴포넌트 세트가 자동 생성됩니다.\n\n**구현 파일**:\n1. `AutoGenerateModal.tsx`: 자동 생성 모달 UI (shadcn Dialog 기반, 반응형)\n2. `generateComponents.ts`: 템플릿별 메타 컴포넌트 자동 생성 로직 (목록형/폼형/마스터-디테일/카드형)\n3. `auto-generate/index.ts`: export 통합\n4. `lib/meta-components/index.ts`: 자동 생성 시스템 export 추가\n5. `ScreenDesigner.tsx`: 테이블 드롭 핸들러 수정 + 모달 통합\n\n**주요 기능**:\n- 4가지 템플릿: 목록형 (Search+DataView+Modal), 폼형 (Field 2열 배치), 마스터-디테일 (좌측 목록+우측 상세), 카드형 (카드뷰)\n- 시스템 컬럼 자동 감지 및 '숨김 권장' 표시\n- 옵션: 검색 바, CRUD 버튼, 등록/수정 모달 포함 여부 선택\n- 반응형 디자인 (mobile-first)\n- 생성된 컴포넌트는 자동으로 레이아웃에 추가되고 히스토리에 저장됨",
|
||
"timestamp": "2026-02-27T16:04:22.565Z"
|
||
},
|
||
{
|
||
"round": 2,
|
||
"from": "frontend",
|
||
"type": "fix",
|
||
"content": "Phase E 테이블 자동 생성 시스템 버그 수정 완료\n\nRound 1에서 구현한 코드에 2가지 버그 발견 및 수정:\n\n1. **모달 상태 리셋 누락**: 모달을 닫았다 다시 열면 이전 선택 상태가 남아 있던 문제 → `useEffect`로 `isOpen` 변경 시 리셋 로직 추가\n\n2. **하드코딩된 ID 충돌**: 같은 템플릿을 여러 번 생성하면 ID가 중복되어 컴포넌트 간 참조가 꼬이던 문제 → 모든 ID를 `generateComponentId()`로 동적 생성하고, Action → DataView 참조를 변수로 연결\n\n이제 테이블을 드롭하면 자동 생성 모달이 열리고, 사용자가 템플릿과 컬럼을 선택하면 메타 컴포넌트 세트가 생성됩니다. 같은 템플릿을 여러 번 생성해도 ID 충돌 없이 독립적으로 동작합니다.",
|
||
"timestamp": "2026-02-27T16:06:42.204Z"
|
||
}
|
||
],
|
||
"artifacts": [
|
||
{
|
||
"agent": "frontend",
|
||
"round": 1,
|
||
"filePath": "frontend/lib/meta-components/auto-generate/AutoGenerateModal.tsx",
|
||
"action": "create",
|
||
"summary": "자동 생성 모달 UI 컴포넌트 (템플릿 선택, 컬럼 선택, 옵션 설정)"
|
||
},
|
||
{
|
||
"agent": "frontend",
|
||
"round": 1,
|
||
"filePath": "frontend/lib/meta-components/auto-generate/generateComponents.ts",
|
||
"action": "create",
|
||
"summary": "템플릿별 메타 컴포넌트 자동 생성 로직 (4가지 템플릿 지원)"
|
||
},
|
||
{
|
||
"agent": "frontend",
|
||
"round": 1,
|
||
"filePath": "frontend/lib/meta-components/auto-generate/index.ts",
|
||
"action": "create",
|
||
"summary": "자동 생성 시스템 export"
|
||
},
|
||
{
|
||
"agent": "frontend",
|
||
"round": 1,
|
||
"filePath": "frontend/lib/meta-components/index.ts",
|
||
"action": "modify",
|
||
"summary": "자동 생성 시스템 re-export 추가"
|
||
},
|
||
{
|
||
"agent": "frontend",
|
||
"round": 1,
|
||
"filePath": "frontend/components/screen/ScreenDesigner.tsx",
|
||
"action": "modify",
|
||
"summary": "테이블 드롭 핸들러 수정 + 자동 생성 모달 통합 (state, handler, JSX 추가)"
|
||
},
|
||
{
|
||
"agent": "frontend",
|
||
"round": 2,
|
||
"filePath": "frontend/lib/meta-components/auto-generate/AutoGenerateModal.tsx",
|
||
"action": "modify",
|
||
"summary": "useEffect 추가 - 모달 열릴 때마다 선택 상태 리셋 (템플릿, 컬럼 선택)"
|
||
},
|
||
{
|
||
"agent": "frontend",
|
||
"round": 2,
|
||
"filePath": "frontend/lib/meta-components/auto-generate/generateComponents.ts",
|
||
"action": "modify",
|
||
"summary": "하드코딩된 ID 제거 - 모든 컴포넌트 ID를 generateComponentId()로 동적 생성 + Action → DataView 참조를 변수로 연결"
|
||
}
|
||
],
|
||
"testResults": [
|
||
{
|
||
"passed": true,
|
||
"exitCode": 0,
|
||
"stdout": "EXIT:0\n",
|
||
"stderr": "",
|
||
"duration": 4053
|
||
}
|
||
],
|
||
"converged": true
|
||
} |