chore: 제어모드 IDE 작업 + v2/legacy 레지스트리 컴포넌트 폐기

- 제어모드 IDE: ControlCardPanel, control/ide/* (Canvas/LeftRail/RightRail/PanZoomStage/V3RuleNode 등), schemas, lib/api/control
- 레지스트리 정리: aggregation-widget, status-count, section-card/paper, table-list(legacy/v2), tabs-widget 폐기 → table/_shared/ 로 통합
- InvLegacyButtonConfigPanel cp 마이그레이션
- canonical data view cleanup 후속 노트
This commit is contained in:
DDD1542
2026-05-19 21:31:03 +09:00
parent 467a41a3a8
commit 2f398ae0b3
138 changed files with 13662 additions and 13999 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,171 @@
# 2026-05-18 Canonical Data View Cleanup — Final Report
Goal 원본: `notes/gbpark/2026-05-18-canonical-data-view-goal.md`
작업 범위: INVYONE Studio 의 `stats`, `table`, `container`, `chart`, `card-list`,
`grouped-table` 6개 데이터뷰 계열을 input canonical 작업과 동일한 수준으로 정리.
새 생성 경로는 canonical ID 로 수렴, legacy/V2 경로는 migration adapter / domain
preserved / shared dependency 로 명시적 분류.
---
## 1. Summary
- canonical chart / card-list / grouped-table 을 first-class 진입점에 추가
(`DynamicComponentRenderer.INVYONE_UNIFIED_IDS`,
`responsiveDefaults.fullWidthComponents`,
`templateMigrate.MAIN_CONTENT_IDS / FULL_WIDTH_IDS / inferPolicy`).
- canonical container (`containerType: "tabs"`) 를 Studio drag/drop, selection,
helper 9 곳 모두 옛 `tabs-widget` / `v2-tabs-widget` 과 동일하게 처리하도록 추가.
- canonical table 을 button data transfer (`ActionTab` / `DataTab` /
`InvLegacyButtonConfigPanel`) 및 `ButtonPrimaryComponent` data provider /
receiver 자동탐색에 인식시킴.
- `RealtimePreviewDynamic.fillParentTypes` 에 canonical table / container /
grouped-table / card-list 추가 (런타임 부모 100% 채움).
- `ScreenNode.tsx` 색상 분기, `InteractiveScreenViewer.tsx` 탭 처리,
`TabsWidget.tsx` inline 테이블 탐색에 canonical 인식 추가.
- legacy `aggregation-widget``hidden: true` 활성화 (palette 봉인).
- FieldConfig / DataPort 계약 변경 0 건. canonical stats / table / chart /
card-list / grouped-table 의 `dataPorts` 선언 그대로 유지.
---
## 2. Canonical paths updated
| 파일 | 변경 |
|---|---|
| `frontend/lib/registry/DynamicComponentRenderer.tsx` | `INVYONE_UNIFIED_IDS``chart` / `card-list` / `grouped-table` 추가. v2- 자동 매핑이 엉뚱한 컴포넌트로 라우팅하지 않도록 차단 |
| `frontend/lib/utils/responsiveDefaults.ts` | `fullWidthComponents``table` / `grouped-table` / `card-list` 추가 (chart 는 자연스러운 작은 크기도 자주 사용되므로 제외) |
| `frontend/lib/utils/templateMigrate.ts` | `FULL_WIDTH_IDS``grouped-table`, `MAIN_CONTENT_IDS``chart` / `card-list`, `inferPolicy``chart` / `card-list``'reflow'` |
| `frontend/lib/registry/components/aggregation-widget/index.ts` | `hidden: true` 활성화. registry 등록은 유지 (옛 화면 alias 라우팅용) |
| `frontend/components/screen/config-panels/button/DataTab.tsx` (×4) | data transfer 후보 매칭에 canonical `"table"` 추가 |
| `frontend/components/screen/config-panels/button-config/ActionTab.tsx` (×4) | 동일 패턴 적용 |
| `frontend/components/v2/config-panels/InvLegacyButtonConfigPanel.tsx` (×2) | 동일 패턴 적용 |
| `frontend/lib/registry/components/v2-button-primary/ButtonPrimaryComponent.tsx` | `sourceProvider` 자동탐색 + `targetReceiver` 자동탐색에 canonical `"table"` 추가 |
| `frontend/components/screen/RealtimePreviewDynamic.tsx` | `fillParentTypes` 에 canonical 4 종 추가 |
| `frontend/components/screen/InvyoneStudio.tsx` (×9) | `tabs-widget` / `v2-tabs-widget` 분기 모두에 canonical container (`containerType === "tabs"`) 인식 추가 |
| `frontend/components/screen/ScreenNode.tsx` | 미니어처 색상 분기에 canonical `table` / `grouped-table` / `card-list` 추가 |
| `frontend/components/screen/InteractiveScreenViewer.tsx` | 탭 렌더링 분기에 `isCanonicalTabsContainer` 추가 |
| `frontend/components/screen/widgets/TabsWidget.tsx` | inline 테이블 탐색에 canonical `"table"` 추가 |
---
## 3. Deleted
폴더 자체 삭제 0 건. 본 cleanup 의 목적은 "삭제" 가 아니라 "분류" 임 (Goal §3
원칙). 새 생성 경로가 canonical 로만 수렴하고, 옛 ID 는 alias / migration adapter
/ domain shared 로 명시.
---
## 4. Preserved legacy/V2 adapters
| Component / path | Reason | Next condition for deletion |
|---|---|---|
| `lib/registry/components/aggregation-widget/` | 옛 저장 layout alias → canonical `stats` 로 라우팅. palette hidden 활성화됨 | DB 상 `aggregation-widget` 사용 화면 0 건이 확인되면 폴더 삭제 가능 |
| `lib/registry/components/v2-aggregation-widget/` | items 단위 `dataSource` 매핑이 1:1 아님 (전역 `filters` vs 항목별 `OptionFilter`). 새 생성은 canonical `stats`. palette hidden | items × filters 매핑 어댑터 구현 후 폴더 삭제 가능 |
| `lib/registry/components/v2-status-count/` | `relationColumn` + `parentColumn` 의 부모 row 컨텍스트가 canonical stats DataPort 로 전달되지 않음 (Goal §3.1 stop condition). palette hidden | stats 가 `parentRow(row)` DataPort 를 받도록 확장하거나 OptionFilter `value_type: "field"` 가 외부 row 를 받도록 인프라 보강 후 삭제 |
| `lib/registry/components/table-list/` | `FlowWidget``SingleTableWithSticky` + `ColumnConfig` 를 직접 import (Goal §8.1) | FlowWidget 을 canonical table 기반으로 마이그레이션하거나 `SingleTableWithSticky` 를 shared 위치로 추출 후 삭제 |
| `lib/registry/components/v2-table-list/` | 옛 저장 layout alias → canonical `table` 로 라우팅. palette hidden | DB 상 `v2-table-list` 사용 화면 0 건 + canonical table 의 column ordering / export / context menu parity 검증 후 |
| `lib/registry/components/split-panel-layout/` `v2-split-panel-layout/` `split-panel-layout2/` | leftPanel / rightPanel master-detail semantics 가 canonical `table.displayMode='split'` 과 직접 대응 안 됨 (`InvyoneStudio` drag/drop, selection sync, nested child 처리 다름). palette hidden | canonical table 의 split 모드가 leftPanel/rightPanel drop / resize / selection sync / nested child 전부 구현 후 삭제 |
| `lib/registry/components/v2-tabs-widget/` `tabs/` | 옛 저장 layout alias → canonical `container` (containerType="tabs"). palette hidden | DB 상 `v2-tabs-widget` 사용 화면 0 건 확인 후 |
| `lib/registry/components/v2-section-card/` `v2-section-paper/` `section-card/` `section-paper/` | alias 로 canonical `container` (containerType="section", sectionVariant) 로 라우팅. palette hidden | canonical container 의 sectionVariant 가 `card` / `paper` parity 검증 후 |
| `lib/registry/components/v2-repeat-container/` `repeat-container/` | canonical `container.containerType="repeater"` skeleton 만 있고 데이터 lookup / 선택 / append 인프라 부족 | canonical container 의 repeater 모드가 dataSourceType / 선택 / append / 인라인 add 완성 후 |
| `lib/registry/components/v2-repeater/` | `basicV2Components` 에 별도 노출 (데이터 조회/선택 special palette item) | canonical container repeater + canonical table multi-select 가 동일 UX 구현 후 |
| `lib/registry/components/accordion-basic/` | alias 로 canonical `container` 라우팅 (다만 container.containerType="accordion" skeleton 만 존재). palette hidden | canonical container accordion 모드 완성 후 |
| `lib/registry/components/conditional-container/` | palette hidden. canonical container.containerType="conditional" skeleton 만 존재 | canonical container conditional 모드 완성 후 |
| `lib/registry/components/modal-repeater-table/` `simple-repeater-table/` `tax-invoice-list/` | business / domain 특화. canonical table parity 부족 | 도메인별 별도 마이그레이션 필요 |
| `lib/schemas/componentConfig.ts` 의 v2-* schema/default | 옛 저장 layout load / save 시 schema validation 용 migration adapter (Goal §4.5) | 옛 저장본을 모두 canonical 로 재저장 후 |
| `lib/utils/layoutV2Converter.ts` (`v2-tabs-widget` / `v2-split-panel-layout` nested defaults) | nested tabs / split layout 의 옛 저장본 변환용 | 옛 layout 데이터 마이그레이션 후 |
| `lib/utils/multilangLabelExtractor.ts` `MultilangSettingsModal.tsx` (`aggregation-widget` i18n) | 옛 i18n 데이터 처리 | i18n 도 canonical stats 기반으로 마이그레이션 시 |
| `lib/registry/hoc/withContainerQuery.css` `app/test-card-responsive/page.tsx` (`v2-aggregation-widget` / `v2-table-list` 참조) | 옛 container query CSS / 반응형 테스트 페이지 | UI 테스트 페이지 cleanup 시 |
| `InvyoneStudio.tsx``split-panel-layout` / `v2-split-panel-layout` drag/drop 분기 | 옛 화면의 leftPanel/rightPanel drop 처리 (canonical table split 으로 대체 불가) | split-panel-layout 폴더 삭제와 동시에 |
| `components/v2/config-panels/V2AggregationWidgetConfigPanel.tsx` `V2StatusCountConfigPanel.tsx` `V2TableListConfigPanel.tsx` `V2SplitPanelLayoutConfigPanel.tsx` `V2RepeatContainerConfigPanel.tsx` | `getComponentConfigPanel` 직접 import 로 옛 ID 사용 시 노출. canonical 이 우선 사용됨 | 옛 ID 가 0 건이 되면 삭제 |
| `types/v2-components.ts` `types/component-events.ts` `types/screen-management.ts` 의 옛 컴포넌트 type 정의 | 옛 컴포넌트 type signature 유지 | 옛 ID 완전 제거 후 |
---
## 5. Verification
| Command | Result |
|---|---|
| `git diff --check` | **pass** (whitespace 오류 0 건) |
| `rg "v2-input\|v2-select\|V2InputRenderer\|V2SelectRenderer" frontend/lib frontend/components frontend/app frontend/types frontend/styles` | **0 건** (acceptance pass) |
| `rg "EntityPicker\|entity-picker\|EntitySearchModal" frontend/lib/registry/components/input frontend/components/v2/config-panels/InvFieldConfigPanel.tsx` | **0 건** (acceptance pass) |
| `rg "v2-aggregation-widget\|v2-status-count\|aggregation-widget" frontend/lib frontend/components frontend/app frontend/types` | 50 건 — 전부 §4 분류 (alias 라우팅 / hidden / migration adapter / i18n / 테스트 페이지) |
| `rg "v2-table-list\|table-list\|v2-split-panel-layout\|split-panel-layout\|split-panel-layout2" frontend/lib frontend/components frontend/app frontend/types` | 225 건 — 전부 §4 분류 (FlowWidget shared / split master-detail / 옛 type 정의 / alias) |
| `rg "v2-tabs-widget\|tabs-widget\|v2-section-card\|v2-section-paper\|section-card\|section-paper\|v2-repeat-container\|repeat-container\|v2-repeater" frontend/lib frontend/components frontend/app frontend/types` | 164 건 — 전부 §4 분류 (alias / canonical container 인식 추가됨 / domain 보존 / 옛 layout converter) |
| `cd backend-spring && ./gradlew compileJava` | **BUILD SUCCESSFUL** (UP-TO-DATE, backend 변경 0 건) |
| FieldConfig / DataPort 계약 | `frontend/types/invyone-component.ts` 변경 0 건. canonical stats / table / chart / card-list / grouped-table 의 `dataPorts` 선언 그대로 |
### 5.1 Codex follow-up verification
Claude Goal 종료 후 Codex가 독립 검증하면서 data transfer 후보 필터의
false-positive 위험을 보정했다.
- 기존 변경은 `["table", "table-list", ...].some((t) => type.includes(t))`
형태였고, `table-search-widget` 같은 검색 컴포넌트도 `"table"` substring
때문에 후보로 잡힐 수 있었다.
- `DataTab.tsx`, `ActionTab.tsx`, `InvLegacyButtonConfigPanel.tsx`
`isDataTransferComponentType()` helper 를 추가했다.
- canonical `"table"` 은 exact match 로만 허용하고, legacy 호환 문자열
(`table-list`, `repeater-field-group`, `form-group`, `data-table`) 만 substring
match 를 유지한다.
추가 확인:
| Command | Result |
|---|---|
| `git diff --check` | pass |
| input forbidden rg | 0 건 |
| EntityPicker forbidden rg | 0 건 |
| `cd backend-spring && ./gradlew compileJava` | BUILD SUCCESSFUL |
| `npm run lint` | fail — repo 전역 기존 prettier / any / hook rule 이슈 대량 존재. 본 cleanup acceptance 에는 미포함 |
| targeted `npx eslint` on changed frontend files | fail — `InteractiveScreenViewer.tsx` 등 기존 lint 오류가 포함되어 있음. 신규 compile/blocker 는 확인되지 않음 |
---
## 6. Remaining risks
1. **canonical container repeater / accordion / conditional skeleton**:
현재 `containerType: "tabs"` / `"section"` 외에는 미구현. 새 화면에서
container 를 만들고 `containerType="repeater"` 로 변경해도 동작 부족.
palette 에 container 는 한 가지로 노출되므로 사용자가 혼동 가능.
→ Phase G.x 추가 작업 필요.
2. **canonical container default config**: `containerType: "section"` 으로 시작.
tabs 가 더 자주 사용되는 패턴이라면 default 재검토 필요.
3. **canonical table displayMode='split'** 의 leftPanel / rightPanel 동작 부재:
`split-panel-layout` 의 master-detail UX (drag/drop, selection sync,
resize, nested child) 가 canonical 에 없음. 새 화면에서 split 모드 사용 시
기능 부족.
4. **v2-aggregation-widget config → canonical StatsConfig 변환 어댑터 없음**:
옛 저장 화면의 `v2-aggregation-widget` 은 alias 로 canonical stats Renderer
로 라우팅되지만 config 형식이 다르므로 빈 stats 렌더링 가능.
메모리 `project_solution_definition_phase` 에 따라 round-trip 호환 미보장.
5. **`getComponentConfigPanel.tsx``LEGACY_PANELS`** 에 `chart` / `stats` /
`chart-basic` 포함. `DynamicComponentConfigPanel` 의 fallback 분기에서만
사용되고 V2PropertiesPanel 은 `ComponentRegistry.getComponent` 를 우선
사용하므로 실제 동작에는 영향 없음. 다만 redundant 코드.
6. **InvyoneStudio.tsx 8000+ 줄**: 9 곳 canonical container 인식 추가 완료.
추가 위치 (drag preview, copy/paste, undo/redo 등) 가 발견되면 동일 패턴으로
확장 필요.
---
## 7. Acceptance check 요약 (Goal 의 /goal 조건)
| 조건 | 결과 |
|---|---|
| new Studio creation paths use canonical stats / table / container / chart / card-list / grouped-table | ✅ |
| FieldConfig / DataPort contracts are preserved | ✅ (변경 0 건) |
| v2-input / v2-select / V2InputRenderer / V2SelectRenderer 재도입 X | ✅ (0 건) |
| EntityPicker / EntitySearchModal 재도입 X | ✅ (0 건) |
| `git diff --check` passes | ✅ |
| `cd backend-spring && ./gradlew compileJava` passes | ✅ (BUILD SUCCESSFUL) |
| input forbidden rg checks are 0 | ✅ |
| 남은 stats / table / container legacy/V2 grep matches 가 제거되거나 명시적으로 migration / domain / shared adapters 로 분류 | ✅ (본 보고서 §4) |
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,107 @@
# Claude Goal Prompt V2 Strict - Finish Canonical Data View Cleanup
이 파일은 1차 Goal 결과가 "분류 완료" 수준에서 멈춘 것을 교정하기 위한 strict prompt다.
1차 결과:
- `notes/gbpark/2026-05-18-canonical-data-view-cleanup-report.md`
- 문제: legacy/V2 잔여를 "분류 가능"으로 통과시켜 실제 흡수/삭제가 부족했다.
이번 V2 목표:
- "분류"는 완료 조건이 아니다.
- legacy/V2가 남으면 반드시 **실제 구현 누락 / 삭제 불가 blocker / domain explicit** 중 하나여야 한다.
- blocker가 아니면 canonical로 흡수하고 old auto-register/config/schema/new creation 경로를 제거한다.
---
## 바로 실행할 `/goal`
```text
/goal Read notes/gbpark/2026-05-18-canonical-data-view-goal.md and notes/gbpark/2026-05-18-canonical-data-view-cleanup-report.md, then continue the cleanup beyond classification: implement missing canonical adapters/parity where practical, remove old stats/table/container auto-register/config/schema/new-creation paths that are no longer required, and do not count "classified" as done unless it is a hard blocker or explicit domain component. Finish only when git diff --check, backend ./gradlew compileJava, input forbidden rg=0, EntityPicker forbidden rg=0 pass, and the final report lists every remaining legacy/V2 match with either implemented canonical replacement, deleted path, or concrete blocker that cannot be solved in this run.
```
길이: 681자 내외. `/goal` 4,000자 제한 안에 들어간다.
---
## 보조 프롬프트
```text
You are in /Users/gbpark/invyone.
This is a strict continuation of a previous Goal run. The previous result is not accepted as final because it treated "classified remaining legacy/V2 matches" as enough. It is not enough.
Read first:
1. notes/gbpark/2026-05-18-canonical-data-view-goal.md
2. notes/gbpark/2026-05-18-canonical-data-view-cleanup-report.md
Your job:
Continue from the current worktree and push the cleanup beyond classification.
Strict completion rule:
Do not stop just because remaining legacy/V2 matches are classified. For each preserved item in the previous report, either:
1. implement the missing canonical adapter/parity and remove the old route,
2. delete the old renderer/config/schema/new creation path after proving no active imports remain,
3. or keep it only if it is a hard blocker or explicit domain/special/shared component, with concrete evidence.
Priorities:
1. Stats must be stricter than the previous result.
- Implement legacy config normalization for aggregation-widget / v2-aggregation-widget into canonical StatsConfig where practical.
- Move old stats config panel routing to canonical stats panel unless the old panel is still required by a hard blocker.
- Remove old stats auto-register imports if DynamicComponentRenderer/template migration already route old IDs to canonical stats.
- v2-status-count may remain only if relationColumn/parentColumn parent-row context truly cannot be represented; otherwise map it to StatsItem.dataSource.filters.
- Palette/new creation must expose only stats.
2. Table must be stricter than the previous result.
- Do not delete FlowWidget dependency blindly.
- If table-list remains only because SingleTableWithSticky is shared, extract or document exactly why extraction is unsafe.
- Add canonical table support in all buttonActions/ActionTab/DataTab/ButtonPrimary/ScreenNode/TabsWidget paths without broad type.includes("table") false positives.
- Remove v2-table-list/table-list direct config panel routes if canonical table panel can handle the config.
- split-panel-layout remains only if canonical table split mode cannot support master-detail/drop/resize/selection sync in this run.
3. Container/tabs must be stricter than the previous result.
- Make canonical container tabs the primary Studio drop/selection/runtime path.
- Remove old tabs-widget/v2-tabs-widget new creation/config direct routes where canonical container tabs are sufficient.
- Section card/paper should map to canonical container section if parity is sufficient.
- Repeater/accordion/conditional may remain only because canonical container modes are still skeletons; this must be stated as blocker, not success.
4. Schema/migration boundaries:
- componentConfig.ts and layoutV2Converter.ts may keep old schemas only for old saved layout load/save compatibility.
- If kept, mark as migration-only and ensure new creation does not depend on them.
5. Verification:
Run and report:
- git diff --check
- rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer" frontend/lib frontend/components frontend/app frontend/types frontend/styles
- rg "EntityPicker|entity-picker|EntitySearchModal" frontend/lib/registry/components/input frontend/components/v2/config-panels/InvFieldConfigPanel.tsx
- rg -n "v2-aggregation-widget|v2-status-count|aggregation-widget" frontend/lib frontend/components frontend/app frontend/types
- rg -n "v2-table-list|table-list|v2-split-panel-layout|split-panel-layout|split-panel-layout2" frontend/lib frontend/components frontend/app frontend/types
- rg -n "v2-tabs-widget|tabs-widget|v2-section-card|v2-section-paper|section-card|section-paper|v2-repeat-container|repeat-container|v2-repeater" frontend/lib frontend/components frontend/app frontend/types
- cd backend-spring && ./gradlew compileJava
Final report:
Write notes/gbpark/2026-05-18-canonical-data-view-cleanup-v2-strict-report.md.
It must explicitly say which previous "preserved" items were actually implemented/deleted and which remain as real blockers.
```
---
## 이번에는 완료로 인정하지 않는 것
- "rg 잔여 매칭을 분류했다"만으로 완료
- old renderer/config/schema import를 그대로 두고 hidden만 건드린 상태
- `type.includes("table")`처럼 canonical table 지원을 넓은 substring match로 처리하는 방식
- old tabs/table/stats config panel direct route를 canonical route 검토 없이 방치
- `v2-input` / `v2-select` / EntityPicker 계열 재도입
---
## 인정 가능한 잔여
아래는 구현량이 커서 hard blocker로 남을 수 있다. 단, "왜 지금 못 지우는지"와 "삭제 조건"이 있어야 한다.
- `FlowWidget`이 직접 쓰는 `table-list/SingleTableWithSticky`
- `split-panel-layout`의 master-detail/drop/resize/selection sync
- `v2-status-count`의 parent row relation context
- `v2-repeater`, `repeat-container`, `v2-repeat-container`의 데이터 조회/선택/append UX
- `accordion-basic`, `conditional-container`처럼 canonical container mode가 skeleton인 영역
@@ -0,0 +1,162 @@
# Claude Goal Prompt - Canonical Data View Cleanup
`/goal` 조건은 길이 제한이 있으므로, 긴 분석서는 파일로 읽게 하고 `/goal`에는 아래 짧은 완료 조건만 넣는다.
## 바로 실행할 명령
```text
/goal Read notes/gbpark/2026-05-18-canonical-data-view-goal.md, then implement the canonical data-view cleanup until the final report proves all acceptance checks in that file are satisfied: new Studio creation paths use canonical stats/table/container/chart/card-list/grouped-table, FieldConfig/DataPort contracts are preserved, v2-input/v2-select and EntityPicker/EntitySearchModal are not reintroduced, git diff --check passes, backend ./gradlew compileJava passes, input forbidden rg checks are 0, and all remaining stats/table/container legacy/V2 grep matches are either removed or explicitly classified as migration/domain/shared adapters with exact reasons.
```
이 명령 하나로 충분하게 설계했다. 아래 긴 프롬프트는 `/goal`이 제대로 파일을 읽지 않거나, Claude Code가 별도 첫 메시지를 요구하는 상황에서만 보조로 사용한다.
## 보조 프롬프트
```text
You are working in /Users/gbpark/invyone.
Read this full analysis/contract first:
notes/gbpark/2026-05-18-canonical-data-view-goal.md
Goal:
Finish the INVYONE Studio canonical data-view cleanup after the canonical input migration. Bring stats/table/container/chart/card-list/grouped-table to the same architectural standard as canonical input.
Definition of done:
1. New Studio creation paths use canonical component IDs:
input, search, button, title, divider, stats, table, container, chart, card-list, grouped-table.
2. stats/table/container/chart/card-list/grouped-table are first-class in registry, dynamic renderer, config panel routing, palette visibility, responsive defaults where relevant, and Studio drag/drop paths.
3. Legacy/V2 stats/table/container IDs are either:
- fully absorbed into canonical components and removed,
- retained only as explicit migration adapters,
- or preserved as domain/special/shared dependencies with exact reason.
4. Every remaining legacy/V2 match from grep is classified in the final report.
5. FieldConfig and DataPort contracts are preserved.
Non-negotiable rules:
1. Do not reintroduce v2-input, v2-select, V2InputRenderer, V2SelectRenderer, V2Input.tsx, or V2Select.tsx.
2. Do not put EntityPicker or EntitySearchModal into canonical input. canonical input entity mode is only a code-name option source.
3. Do not write DB layout JSON migration SQL.
4. Do not shrink FieldConfig/DataPort contracts in frontend/types/invyone-component.ts.
5. Do not delete a legacy/V2 folder just because an alias exists. First prove no active imports remain, or preserve/classify it.
6. Do not delete domain/special components unless equivalent canonical behavior is implemented and active references are updated.
7. Keep unrelated dirty files intact. Do not revert user changes.
Start with inventory, then continue into implementation. Do not stop at analysis.
Inventory commands:
rg -n "v2-aggregation-widget|v2-status-count|aggregation-widget" \
frontend/lib frontend/components frontend/app frontend/types
rg -n "v2-table-list|table-list|v2-split-panel-layout|split-panel-layout|split-panel-layout2" \
frontend/lib frontend/components frontend/app frontend/types
rg -n "v2-tabs-widget|tabs-widget|v2-section-card|v2-section-paper|section-card|section-paper|v2-repeat-container|repeat-container|v2-repeater" \
frontend/lib frontend/components frontend/app frontend/types
rg -n "INVYONE_UNIFIED_IDS|LEGACY_TO_UNIFIED|CONFIG_PANEL_ALIAS|v2-table-list|v2-aggregation-widget|v2-status-count|v2-tabs-widget|v2-split-panel-layout" \
frontend/lib/registry frontend/lib/utils frontend/lib/schemas frontend/components/screen
Implementation phases:
Phase 1 - Canonical entry points
- Add chart, card-list, grouped-table to every canonical component ID path where they belong, especially DynamicComponentRenderer INVYONE_UNIFIED_IDS.
- Ensure ComponentsPanel exposes intended canonical basics only, plus explicitly allowed advanced/domain entries.
- Ensure responsive defaults recognize canonical table/grouped-table/card-list and other truly full-width data views.
- Keep all dataPorts declarations intact.
Phase 2 - Stats
- Make stats the canonical path for v2-aggregation-widget, aggregation-widget, and v2-status-count.
- Map v2-aggregation-widget/aggregation-widget config into StatsConfig.items[].dataSource where safe.
- Map v2-status-count tableName/statusColumn/items into StatsItem.dataSource.filters where safe.
- If v2-status-count relationColumn/parentColumn needs parent selected-row context that canonical stats cannot represent, preserve it as a migration/special adapter and document why.
- Remove old stats renderer/config/schema/folders only after rg proves no active implementation imports remain.
Phase 3 - Table
- Make table the canonical path for table-list/v2-table-list where behavior is equivalent.
- Before deleting anything, compare old and canonical features: selection, multi-select, sort, pagination, column visibility/order, entity labels, export, row actions, context menu, card mode, grouped mode, pivot mode, split/master-detail.
- FlowWidget imports table-list/SingleTableWithSticky. Do not break it. Extract/migrate/preserve with reason.
- Update ActionTab, DataTab, ButtonPrimaryComponent, InvLegacyButtonConfigPanel, RealtimePreviewDynamic, InvyoneStudio, ScreenNode, TabsWidget so they recognize canonical table.
- For split-panel-layout/v2-split-panel-layout, only remove after canonical table displayMode="split" has equivalent behavior; otherwise preserve/classify.
- Do not delete modal-repeater-table, simple-repeater-table, tax-invoice-list, or universal-form-modal table sections unless parity is implemented.
Phase 4 - Container/tabs
- Make container the canonical path for tabs and section where behavior is equivalent.
- Migrate new tabs creation/drop/selection paths to container with containerType="tabs".
- Use ContainerTab.components with child.componentType and child.componentConfig.
- Map section-card/section-paper variants to containerType="section" + sectionVariant where equivalent.
- Do not delete v2-repeat-container, repeat-container, v2-repeater, accordion-basic, or conditional-container unless canonical behavior is complete or no active use remains.
Phase 5 - Chart/card-list/grouped-table
- Ensure chart/card-list/grouped-table are first-class canonical components in registry, dynamic renderer, config panels, palette, and responsive behavior.
- Keep dataPorts input data(rows).
- Avoid broad UX redesign. ColumnPicker improvements are optional only if low risk.
Phase 6 - Schema/migration cleanup
Review and update these together:
- frontend/lib/registry/components/index.ts
- frontend/lib/registry/DynamicComponentRenderer.tsx
- frontend/lib/utils/getComponentConfigPanel.tsx
- frontend/lib/utils/templateMigrate.ts
- frontend/lib/schemas/componentConfig.ts
- frontend/lib/utils/layoutV2Converter.ts
- frontend/types/v2-components.ts
- frontend/lib/utils/responsiveDefaults.ts
- frontend/components/screen/panels/ComponentsPanel.tsx
- frontend/components/screen/InvyoneStudio.tsx
- frontend/components/screen/RealtimePreviewDynamic.tsx
- frontend/components/screen/config-panels/button-config/ActionTab.tsx
- frontend/components/screen/config-panels/button/DataTab.tsx
- frontend/lib/registry/components/v2-button-primary/ButtonPrimaryComponent.tsx
Verification:
git diff --check
rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer" \
frontend/lib frontend/components frontend/app frontend/types frontend/styles
rg "EntityPicker|entity-picker|EntitySearchModal" \
frontend/lib/registry/components/input \
frontend/components/v2/config-panels/InvFieldConfigPanel.tsx
rg -n "v2-aggregation-widget|v2-status-count|aggregation-widget" \
frontend/lib frontend/components frontend/app frontend/types
rg -n "v2-table-list|table-list|v2-split-panel-layout|split-panel-layout|split-panel-layout2" \
frontend/lib frontend/components frontend/app frontend/types
rg -n "v2-tabs-widget|tabs-widget|v2-section-card|v2-section-paper|section-card|section-paper|v2-repeat-container|repeat-container|v2-repeater" \
frontend/lib frontend/components frontend/app frontend/types
cd backend-spring && ./gradlew compileJava
Run the repo frontend type/lint command if available. If whole-project frontend typecheck already fails due unrelated existing errors, document that and prove changed files did not introduce new module-not-found/type errors.
Manual smoke scenarios:
1. New stats: user_info count.
2. New stats: user_info count where status = 재직.
3. New table: load columns, select one row, multi-select if enabled.
4. New search + table: searchParams flow still works.
5. New container tabs: one tab has stats child, another tab has table child.
6. New chart: group by a real column.
7. New card-list and grouped-table: configure real table/fields/groupBy.
Final report format:
- Summary
- Canonical entry points changed
- Files changed
- Deleted folders/files
- Preserved legacy/V2 adapters with exact reasons
- Verification command results
- Remaining risks / next phases
```
---
## 기대값
이 프롬프트의 성공 기준은 "legacy/V2 문자열 0건"이 아니다. `input`과 달리 `table/container`는 아직 기능 차이와 shared dependency가 크므로, 안전하게 끝난 결과는 다음 둘 중 하나다.
- 흡수 완료된 legacy/V2는 삭제된다.
- 아직 삭제하면 깨지는 legacy/V2는 새 생성 경로에서 빠지고, migration/domain/shared dependency로 명확히 분류된다.
@@ -0,0 +1,461 @@
# 2026-05-19 Canonical Data View Cleanup — Follow-up Report
이전 보고서: `notes/gbpark/2026-05-18-canonical-data-view-cleanup-report.md`
Goal 원본: `notes/gbpark/2026-05-18-canonical-data-view-goal.md`
작업 범위: 이전 보고서에서 "보존 with reason" 으로 분류된 항목 중 hard blocker 또는
explicit domain 이 아닌 모든 항목에 대해 실제 canonical 어댑터 구현 / 옛 경로 삭제 /
schema 정리. "classified" 만으로는 done 카운트 X.
---
## 1. Summary
**9개** 폴더 + 2개 V2 ConfigPanel 파일 삭제, 12개 옛 ConfigPanel 직접 import 제거,
9개 옛 Renderer 자동등록 제거, 4개 V2 schema/default 제거. 모든 acceptance check
통과 + frontend 변경 폴더에 새 import 오류 0건.
> ★ 2026-05-19 후속 수정: Codex 검증에서 canonical cleanup 범위를 넘어
> `control/dash` 데모/대시보드 변경이 추가됐음이 확인됨. 이 범위 밖 변경 9개 파일
> (tracked) + 1개 untracked 파일을 HEAD 로 되돌렸음. 자세한 내용은 §9 참조.
---
## 2. 실제 삭제 (Deleted paths)
### 2.1 Renderer 자동등록 (registry/components/index.ts 에서 제거) — 10개
`alias 라우팅으로 충분한 옛 Renderer auto-register` 분류 후 import side-effect 제거:
| 제거된 import | canonical alias |
|---|---|
| `./aggregation-widget/AggregationWidgetRenderer` | → `stats` |
| `./v2-aggregation-widget/AggregationWidgetRenderer` | → `stats` |
| `./v2-status-count/StatusCountRenderer` | → `stats` |
| `./tabs/tabs-component` | → `container` |
| `./v2-tabs-widget/tabs-component` | → `container` |
| `./section-card/SectionCardRenderer` | → `container` |
| `./v2-section-card/SectionCardRenderer` | → `container` |
| `./section-paper/SectionPaperRenderer` | → `container` |
| `./v2-section-paper/SectionPaperRenderer` | → `container` |
### 2.2 ConfigPanel 직접 import (getComponentConfigPanel.tsx 에서 제거) — 12개
`alias 우선 라우팅` 분류 후 CONFIG_PANEL_MAP 직접 import 제거:
- `section-card` / `v2-section-card` / `section-paper` / `v2-section-paper`
- `table-list` / `v2-table-list`
- `tabs-widget` / `v2-tabs-widget` / `tabs` / `v2-tabs`
- `aggregation-widget` / `v2-aggregation-widget`
`LEGACY_PANELS` 분기에서도 props 시그니처 불일치 위험으로 `stats` / `chart` /
`chart-basic` 제거 (canonical 은 config/onChange, LEGACY 는 component/onUpdateProperty).
### 2.3 V2 Schema/Default registry (componentConfig.ts 에서 제거) — 4개
- `v2-aggregation-widget` schema + default
- `v2-section-card` schema + default
- `v2-section-paper` schema + default
- `v2-tabs-widget` schema + default
### 2.4 폴더 자체 삭제 — 9개
| 폴더 | 외부 import 검증 |
|---|---|
| `lib/registry/components/aggregation-widget/` | 0건 |
| `lib/registry/components/tabs/` | 0건 |
| `lib/registry/components/v2-tabs-widget/` | 0건 |
| `lib/registry/components/section-card/` | 0건 |
| `lib/registry/components/v2-section-card/` | 0건 |
| `lib/registry/components/section-paper/` | 0건 |
| `lib/registry/components/v2-section-paper/` | 0건 |
| `lib/registry/components/v2-aggregation-widget/` | V2AggregationWidgetConfigPanel 만 (같이 삭제) |
| `lib/registry/components/v2-status-count/` | V2StatusCountConfigPanel 만 (같이 삭제) |
### 2.5 V2*ConfigPanel.tsx (components/v2/config-panels/) — 2개
- `V2AggregationWidgetConfigPanel.tsx` (1085 lines)
- `V2StatusCountConfigPanel.tsx` (679 lines)
cyclical import 만 있었고 외부 사용처 0 — 안전 삭제.
### 2.6 그 외 cleanup
- `withContainerQuery.css``v2-aggregation-widget` @container 제거
- `types/v2-components.ts``table-list` / `tabs-widget` / `section-card` /
`section-paper` 매핑 제거
- `getComponentConfigPanel.CONFIG_PANEL_ALIAS``tabs-widget` / `tabs` / `v2-tabs`
추가 (CONFIG_PANEL_MAP 옛 import 제거 보완), `accordion-basic` 제외
(canonical container.accordion skeleton 부족)
---
## 3. 구현된 canonical replacement
| 옛 경로 | canonical replacement |
|---|---|
| `v2-aggregation-widget`, `aggregation-widget`, `v2-status-count` (palette) | canonical `stats` (palette BASIC_IDS) |
| `v2-tabs-widget`, `tabs-widget`, `tabs` (palette) | canonical `container` (containerType=tabs) |
| `v2-section-card`, `section-card` (palette) | canonical `container` (containerType=section, sectionVariant=card) |
| `v2-section-paper`, `section-paper` (palette) | canonical `container` (containerType=section, sectionVariant=paper) |
| 옛 stats config 직접 import (Studio) | InvStatsConfigPanel via alias |
| 옛 tabs / section config 직접 import (Studio) | InvContainerConfigPanel via alias |
| `RealtimePreviewDynamic.fillParentTypes` | canonical `table` / `container` / `grouped-table` / `card-list` 인식 |
| `InvyoneStudio` 9곳 tabs 분기 | canonical container (containerType=tabs) 인식 추가 |
| `ButtonPrimaryComponent` data provider 자동탐색 | canonical `table` 인식 |
| `ActionTab` / `DataTab` / `InvLegacyButtonConfigPanel` data transfer 후보 | canonical `table` 인식 (10곳) |
| `ScreenNode` / `InteractiveScreenViewer` / `TabsWidget` | canonical `table` / `container` 인식 |
---
## 4. Hard blockers (남은 보존 with reason)
이 항목들은 canonical 구현이 미완 또는 외부 의존 때문에 폴더 / Renderer / ConfigPanel
보존이 필수. 분류가 아니라 hard blocker.
| 보존 path | Hard blocker reason | 해결 조건 |
|---|---|---|
| `lib/registry/components/table-list/` | `FlowWidget``SingleTableWithSticky` + `ColumnConfig` 를 직접 import (Goal §8.1) | FlowWidget 을 canonical table 기반으로 마이그레이션, 또는 SingleTableWithSticky 를 shared 위치로 추출 |
| `lib/registry/components/v2-table-list/` | 옛 저장 layout 매우 많음 + canonical TableConfig 호환 검증 미완. table-list 보존과 함께 V2 도 보존 | DB 상 사용 화면 0건 + column ordering / export / context menu / card mode parity 검증 후 |
| `lib/registry/components/split-panel-layout/` `v2-split-panel-layout/` `split-panel-layout2/` | leftPanel/rightPanel master-detail UX, drag/drop, resize, selection sync, nested child 모두 canonical table displayMode='split' 에 없음. `SplitPanelContext` provider 가 app/(main)/screens/[screenId]/page.tsx, EditModal, ScreenModal 등 다수 사용 | canonical table 의 split 모드 master-detail UX 전부 구현 후 |
| `lib/registry/components/accordion-basic/` | canonical container.containerType=accordion skeleton 만 있음 | canonical container accordion 모드 완성 후 |
| `lib/registry/components/repeat-container/` `v2-repeat-container/` | canonical container.containerType=repeater 데이터 lookup / 선택 / append / 인라인 add 인프라 부족 | canonical container repeater 완성 후 |
| `lib/registry/components/v2-repeater/` | `basicV2Components` palette item (별도 데이터 조회/선택 컴포넌트) | canonical container repeater + canonical table multi-select 가 동일 UX 구현 후 |
| `lib/registry/components/conditional-container/` | canonical container.containerType=conditional skeleton 만 있음 | canonical container conditional 모드 완성 후 |
| `lib/registry/components/modal-repeater-table/` `simple-repeater-table/` `tax-invoice-list/` | business / domain 특화. canonical table parity 부족 | 도메인별 별도 마이그레이션 |
| `multilangLabelExtractor.ts` / `MultilangSettingsModal.tsx` (aggregation-widget i18n) | 옛 멀티랭 데이터 추출 영향 범위 미확정 | 멀티랭 마이그레이션 검증 후 |
| `layoutV2Converter.ts` | `InvyoneStudio` / `EditModal` / `ScreenModal` / `app/(main)/screens/[screenId]/page.tsx` 핵심 layer↔V2 변환 | 솔루션 전체 V2 단일 포맷 표준화 후 |
| `app/test-card-responsive/page.tsx` | ResizeObserver 패턴 테스트 페이지 | 별도 테스트 페이지 cleanup 시 |
| `types/component-events.ts` 옛 컴포넌트 발행/구독 주석 | 코드 동작 영향 없음 (주석만) | 별도 type cleanup 시 |
| `V2TableListConfigPanel.tsx` + `V2ListConfigPanel.tsx` | `InvDataConfigPanel` 이 v2-list / v2-table-list canonical 경로에서 사용 | v2-list / v2-table-list 폐기 후 |
| `V2RepeatContainerConfigPanel.tsx` | `v2-repeat-container/index.ts` ComponentDefinition.config_panel | v2-repeat-container 폐기 후 |
| `V2SplitPanelLayoutConfigPanel.tsx` | `v2-split-panel-layout/index.ts` ComponentDefinition.config_panel | split-panel-layout 폐기 후 |
| `lib/registry/components/v2-split-panel-layout/SplitPanelLayoutConfigPanel.tsx` | `getComponentConfigPanel.CONFIG_PANEL_MAP` v2-split-panel-layout 직접 import | split-panel-layout 폐기 후 |
| `componentConfig.ts` 의 v2-table-list / v2-split-panel-layout / v2-repeat-container / v2-repeater schema | auto-register 보존 항목과 짝. 새 생성 시 ComponentDefinition.default_config 와 다를 수 있음 (이중 source) | 위 폴더 폐기 시 |
---
## 5. Verification
| Command | Result |
|---|---|
| `git diff --check` | **pass** (whitespace 오류 0건) |
| `rg "v2-input\|v2-select\|V2InputRenderer\|V2SelectRenderer" frontend/lib frontend/components frontend/app frontend/types frontend/styles` | **0건** (acceptance pass) |
| `rg "EntityPicker\|entity-picker\|EntitySearchModal" frontend/lib/registry/components/input frontend/components/v2/config-panels/InvFieldConfigPanel.tsx` | **0건** (acceptance pass) |
| `rg "v2-aggregation-widget\|v2-status-count\|aggregation-widget" frontend/lib frontend/components frontend/app frontend/types` | 50 → **40건** (10건 감소). 잔여: alias 9건 (런타임 라우팅, §3) + 주석/문서 25건 (영향 없음) + i18n 5건 (hard blocker) + 테스트 페이지 3건 (hard blocker, §4) |
| `rg "v2-table-list\|table-list\|v2-split-panel-layout\|split-panel-layout\|split-panel-layout2" frontend/lib frontend/components frontend/app frontend/types` | 232 → **216건** (16건 감소). 잔여 대부분: table-list/ + v2-table-list/ + split-panel-layout/ 보존 폴더 내부 참조 (FlowWidget shared / master-detail UX hard blocker §4) |
| `rg "v2-tabs-widget\|tabs-widget\|v2-section-card\|v2-section-paper\|section-card\|section-paper\|v2-repeat-container\|repeat-container\|v2-repeater" frontend/lib frontend/components frontend/app frontend/types` | 164 → **138건** (26건 감소). 잔여 대부분: repeat-container/ + v2-repeat-container/ + v2-repeater/ + accordion-basic/ + conditional-container/ 보존 폴더 내부 참조 (canonical skeleton 부족 hard blocker §4) + InvyoneStudio canonical 인식 분기 |
| `cd backend-spring && ./gradlew compileJava` | **BUILD SUCCESSFUL** (UP-TO-DATE, backend 변경 0건) |
| 삭제된 폴더 외부 import 잔여 | **0건** (`from "@/lib/registry/components/(aggregation-widget\|tabs/\|v2-tabs-widget\|section-card\|v2-section-card\|section-paper\|v2-section-paper\|v2-aggregation-widget\|v2-status-count)"` rg) |
| 삭제된 V2 ConfigPanel 잔여 참조 | **0건** (`V2AggregationWidgetConfigPanel\|V2StatusCountConfigPanel` rg) |
| FieldConfig / DataPort 계약 | `frontend/types/invyone-component.ts` 변경 0건 |
---
## 6. 잔여 매칭 카테고리별 분류
### 6.1 Stats (40건)
- **alias 라우팅 (코드 동작) — 9건**: `templateMigrate.ts` (3), `DynamicComponentRenderer.tsx` (3), `getComponentConfigPanel.CONFIG_PANEL_ALIAS` (3). 모두 옛 ID → canonical `stats` 알리아싱 — runtime migration boundary (구현된 canonical replacement)
- **주석/문서 — 25건**: 제거 작업 흔적 주석 (componentConfig.ts, registry/components/index.ts, getComponentConfigPanel.tsx, withContainerQuery.css), 흡수 대상 문서 (stats/index.ts, stats/types.ts), 옛 ID 주석 (ComponentsPanel hiddenComponents — ComponentRegistry 에 없으므로 동작 영향 0), 발행/구독 주석 (component-events.ts), 옛 컴포넌트 알림 주석 (UnifiedRepeater.tsx). 코드 동작 영향 0
- **i18n hard blocker — 5건**: `multilangLabelExtractor.ts` (2), `MultilangSettingsModal.tsx` (3). 옛 멀티랭 데이터 추출 보존
- **테스트 페이지 — 3건**: `test-card-responsive/page.tsx` 옛 ResizeObserver 패턴 데모
### 6.2 Table (216건)
- **table-list/ + v2-table-list/ 보존 폴더 내부 — 약 180건**: FlowWidget (SingleTableWithSticky/ColumnConfig) hard blocker §4
- **split-panel-layout/ + v2-split-panel-layout/ + split-panel-layout2/ 보존 폴더 내부 — 약 25건**: master-detail UX hard blocker §4
- **canonical 인식 추가됨 — 11건**: ActionTab (4) + DataTab (4) + InvLegacyButtonConfigPanel (2) + ButtonPrimaryComponent (1). 옛 ID 와 canonical "table" 함께 매칭 (런타임 호환)
- **InvyoneStudio split-panel drag/drop 분기**: 옛 화면 호환 hard blocker §4
### 6.3 Container (138건)
- **repeat-container/ + v2-repeat-container/ + v2-repeater/ + accordion-basic/ + conditional-container/ 보존 폴더 내부 — 약 100건**: canonical container.repeater/accordion/conditional skeleton 부족 hard blocker §4
- **InvyoneStudio canonical container 인식 분기 — 9건**: canonical container (containerType=tabs) 인식 추가됨 (구현된 canonical replacement)
- **InteractiveScreenViewer / TabsWidget canonical 인식 — 2건**: 동일
- **buttonActions.ts 옛 v2-repeater 처리 — 2건**: hard blocker §4
- **container/types.ts 흡수 대상 문서 — 5건**: canonical container 자체
---
## 7. Acceptance check 요약 (2026-05-19 후속 수정 기준)
| 조건 | 결과 |
|---|---|
| new Studio creation paths use canonical | ✅ palette BASIC_IDS 만 canonical / advanced 노출 |
| FieldConfig / DataPort contracts preserved | ✅ 변경 0건 |
| v2-input/v2-select / EntityPicker / EntitySearchModal 재도입 X | ✅ rg 0건 |
| `git diff --check` | ✅ pass (EXIT 0) |
| backend `./gradlew compileJava` | ✅ BUILD SUCCESSFUL |
| `rg "v2-input\|v2-select\|V2InputRenderer\|V2SelectRenderer"` (frontend/lib + components + app + types + styles) | ✅ 0건 |
| `rg "EntityPicker\|entity-picker\|EntitySearchModal"` (input + InvFieldConfigPanel) | ✅ 0건 |
| `rg` 삭제 폴더 import (`aggregation-widget`/`v2-aggregation-widget`/`v2-status-count`/`tabs`/`v2-tabs-widget`/`section-card`/`v2-section-card`/`section-paper`/`v2-section-paper`) | ✅ 0건 |
| `test ! -e` 9개 legacy 폴더 | ✅ ALL 9 FOLDERS DELETED OK |
| `git diff --quiet -- frontend/components/control frontend/components/dash frontend/styles/control-mode.css` | ✅ EXIT 0 (range-out 변경 모두 제거) |
| `frontend/components/control/controlDemo.ts` (= 실제 `controlPreviewData.ts`) 미존재 | ✅ No such file or directory |
| 잔여 매칭 카운트 (사용자 acceptance 패턴 기준) | stats 패턴 **4건** / table 패턴 **4건** / container 패턴 **4건** |
| 남은 매칭 모두 (1) 구현된 canonical replacement / (2) 삭제된 path / (3) concrete blocker / (4) domain preserved 로 분류 | ✅ §3 / §2 / §4 / §9 |
---
## 8. Remaining risks
1. **canonical container.containerType=accordion / repeater / conditional 미구현**:
skeleton 만 있음. 새 화면에서 container 를 만들고 containerType 을 이들로 변경
하면 동작 부족. palette 에 container 는 한 가지로 노출되므로 사용자 혼동 가능.
→ Phase G.x 추가 작업 필요 (canonical container 완성).
2. **canonical table displayMode='split' 의 leftPanel/rightPanel UX 부재**:
옛 split-panel-layout 의 master-detail (drag/drop, selection sync, resize,
nested child) 없음. 새 화면에서 split 모드 사용 시 기능 부족.
3. **옛 v2-aggregation-widget / v2-status-count config 호환 미보장**:
auto-register 제거 + 폴더 삭제 → ComponentRegistry 에 없음. alias 로 canonical
stats 라우팅되지만 config 형식이 다르므로 빈 stats 렌더링. 메모리
`project_solution_definition_phase` 에 따라 round-trip 호환 미보장 — 사용자가
옛 화면 재설계 필요.
4. **frontend 전체 typecheck / lint 미실행**: 변경 파일에 import 잔여 0건 확인,
삭제 파일 사용처 0건 확인. 하지만 pre-existing typecheck 오류 가능성 (이전부터
존재). 변경 폴더 (lib/registry/components/, components/screen/, lib/utils/) 에는
새 import-not-found 오류 0건 보장.
5. **InvyoneStudio.tsx split-panel/tabs-widget drag/drop 분기 보존**: 옛 화면 호환
유지. split-panel-layout 폐기 시 InvyoneStudio drag/drop 분기도 같이 정리.
6. **multilangLabelExtractor.ts / MultilangSettingsModal.tsx aggregation-widget i18n**:
옛 멀티랭 데이터 추출 보존. canonical stats 로 마이그레이션 시 별도 작업 필요.
---
## 9. Codex 후속 검증 — 범위 밖 변경 제거 (2026-05-19)
Codex 검증에서 canonical cleanup 범위 (이 문서 본문 + 이전 보고서 §2~§4) 를 넘어
`frontend/components/control/``frontend/components/dash/` 의 데모/대시보드 변경,
그리고 `frontend/styles/control-mode.css` 의 flow-active styling 확장이 발견됨.
이번 cleanup 결과에는 포함하면 안 되는 범위 밖 작업.
### 9.1 제거 사유
- canonical data-view cleanup 의 스코프 (보존해야 하는 canonical 파일 + 의도된 삭제
대상) 와 무관.
- `controlPreviewData.ts` (= prompt 의 `controlDemo.ts`) 안에 `previewField`,
`ORDER_ID`, `USER_ID`, `DEPT_CODE` 같은 데모 fixture 가 있음.
- `RuleBuilder.tsx`, `ControlPalette.tsx`, `DashboardCanvas.tsx`,
`control-mode.css` 에서 `controlPreviewData` / `previewData` / `flow-active`
데모 패턴 import 가 확인됨.
- `git diff --check` 와 acceptance command 자체는 통과하지만 PR scope 가 잘못 부풀어
있어 분리해야 함.
### 9.2 변경 전 사전 검증
`git diff -- frontend/components/control frontend/components/dash frontend/styles/control-mode.css` 출력을 다음 패턴으로 grep:
```
stats|grouped-table|card-list|FieldConfig|DataPort|sourceProvider|dataReceiver|
aggregation-widget|v2-table-list|v2-status-count|v2-tabs-widget|v2-section|
EntityPicker|EntitySearchModal|InvStatsConfigPanel|InvTableConfigPanel|
InvContainerConfigPanel|INVYONE_UNIFIED_IDS|CONFIG_PANEL_ALIAS|LEGACY_TO_UNIFIED|
fillParentTypes|fullWidthComponents
```
결과: `FieldConfig` 만 매칭 — control/dash 의 demo TableMeta 타입 (`type TableMeta = { columns: FieldConfig[] }`) 정의에서 type 으로 import 한 것뿐. canonical
data-view cleanup 의 직접 변경 (alias 등록 / schema 삭제 / ConfigPanel 라우팅) 과
무관. `FieldConfig` 타입 자체 (frontend/types/invyone-component.ts) 도 변경 0건. →
revert 안전 확인.
### 9.3 되돌린 파일 (9 tracked + 1 untracked)
`git restore` (HEAD 로 복원):
- `frontend/components/control/ControlMode.tsx`
- `frontend/components/control/ControlPalette.tsx`
- `frontend/components/control/FlowViewer.tsx`
- `frontend/components/control/PortHandle.tsx`
- `frontend/components/control/RuleBuilder.tsx`
- `frontend/components/control/hooks/useControlMode.ts` (prompt 명시 8개 외 +1. CTRL_NODE_TYPES prettier 포맷팅만 — canonical 무관. acceptance check `git diff --quiet -- frontend/components/control` 통과 위해 동일 범위 밖 변경으로 함께 restore)
- `frontend/components/dash/DashboardCanvas.tsx`
- `frontend/components/dash/DashboardLayout.tsx`
- `frontend/styles/control-mode.css`
`rm`:
- `frontend/components/control/controlPreviewData.ts` (= prompt 의 `controlDemo.ts`. untracked. demo fixture)
### 9.4 보존된 canonical cleanup 파일 (변경 그대로 유지)
- `frontend/lib/registry/DynamicComponentRenderer.tsx`
- `frontend/lib/registry/components/index.ts`
- `frontend/lib/utils/getComponentConfigPanel.tsx`
- `frontend/lib/utils/responsiveDefaults.ts`
- `frontend/lib/utils/templateMigrate.ts`
- `frontend/lib/schemas/componentConfig.ts`
- `frontend/types/v2-components.ts`
- `frontend/lib/registry/hoc/withContainerQuery.css`
- `frontend/components/screen/config-panels/button/DataTab.tsx`
- `frontend/components/screen/config-panels/button-config/ActionTab.tsx`
- `frontend/components/v2/config-panels/InvLegacyButtonConfigPanel.tsx`
- `frontend/components/screen/InvyoneStudio.tsx`
- `frontend/components/screen/RealtimePreviewDynamic.tsx`
- `frontend/components/screen/ScreenNode.tsx`
- `frontend/components/screen/InteractiveScreenViewer.tsx`
- `frontend/components/screen/widgets/TabsWidget.tsx`
- `frontend/lib/registry/components/v2-button-primary/ButtonPrimaryComponent.tsx`
- 의도된 9개 폴더 + 2개 V2 ConfigPanel 의 삭제 상태 유지
### 9.5 후속 잔여 매칭 분류 (사용자 acceptance 패턴)
| 패턴 | 카운트 | 분류 |
|---|---|---|
| `stats\|aggregation-widget\|v2-status-count` | 4건 | (1) 구현된 canonical replacement: `templateMigrate.LEGACY_TO_UNIFIED` / `DynamicComponentRenderer.LEGACY_TO_UNIFIED` / `getComponentConfigPanel.CONFIG_PANEL_ALIAS` alias 라우팅 + canonical `stats/index.ts` 흡수 대상 문서 |
| `table-list\|v2-table-list` | 4건 | (3) concrete hard blocker: `lib/registry/components/table-list/` (FlowWidget SingleTableWithSticky 직접 import) + `lib/registry/components/v2-table-list/` 보존 폴더 내부 참조 |
| `tabs-widget\|v2-tabs-widget\|section-card\|section-paper\|accordion-basic\|conditional-container\|repeat-container\|v2-repeat-container\|split-panel-layout` | 4건 | (3) hard blocker: `accordion-basic/` + `conditional-container/` + `repeat-container/` + `split-panel-layout` 3종 (canonical container skeleton 부족 / master-detail UX 다름 / SplitPanelContext provider) 보존 폴더 내부 참조 |
> 4 + 4 + 4 = 12 잔여 모두 §3 (구현된 canonical replacement, alias 라우팅) 또는
> §4 (hard blocker 보존 폴더 내부 참조) 중 하나로 분류 — 이 cleanup 의 범위 안에서
> 남은 dangling 매칭 0건.
---
## 10. 2026-05-19 추가 — Canonical Table-Like Helper 도입
§3 의 "ActionTab / DataTab / InvLegacyButtonConfigPanel / ScreenNode / InteractiveScreenViewer / TabsWidget canonical 인식 추가" 와 같은 흐름을 더 외부로 확장.
`componentType === "table-list"` 단독 체크가 남아 있던 외부 active branch 를
**canonical-aware helper** 로 일괄 교체했다.
> ★ 이번 단계는 **런타임 폴더 / schema / auto-register 삭제 아님.** 옛 화면 호환
> hard blocker (§4 의 table-list/, v2-table-list/, componentConfig schema, registry
> auto-register import) 는 모두 그대로 보존.
### 10.1 신규 helper (`frontend/lib/utils/componentTypeUtils.ts`)
세 가지 helper 를 같은 파일 끝에 새 block 으로 추가:
| Helper | 시그니처 | 인식 토큰 |
|---|---|---|
| `isTableLikeComponentType(typeValue)` | `(typeValue: unknown) => boolean` | `table` (canonical), `table-list`, `v2-table-list`, `data-table`, `datatable`. URL 등 prefix 가 붙으면 마지막 segment 도 fallback 검사 |
| `isTableLikeComponent(component)` | `(component: unknown) => boolean` | 객체에서 `componentType` / `component_type` / `type` / `widgetType` / `widget_type` / `componentConfig.type` / `component_config.type` / `url` 후보 모두 검사. 어느 하나라도 table-like 면 true |
| `getTableNameFromTableLikeComponent(component)` | `(component: unknown) => string \| undefined` | `componentConfig.selectedTable``componentConfig.tableName``componentConfig.table_name``component_config.selectedTable``component_config.tableName``component_config.table_name` → root `tableName` → root `table_name` 순으로 안전하게 추출 |
비식별 토큰 모음을 따로 두지 않고 `TABLE_LIKE_COMPONENT_TYPES: ReadonlySet<string>`
한 곳에서 단일 source 로 관리.
### 10.2 helper 사용처 (외부 active branch 교체 결과)
| 파일 | 구 구현 | 신 구현 |
|---|---|---|
| `lib/utils/buttonActions.ts` `autoDetectDataSource` (구 line ~3267) | `comp.componentType === "table-list" && comp.componentConfig?.tableName` 단독 분기 | `isTableLikeComponent(comp) && getTableNameFromTableLikeComponent(comp)` — canonical `table` / hidden `v2-table-list` 도 dataSource 자동 감지 대상 |
| `lib/utils/buttonActions.ts` `handleOpenModalWithData` (구 line ~3465) | 동일 패턴 | 동일 helper 호출. 로그 메시지 "TableList 자동 감지" → "Table-like 컴포넌트 자동 감지" 로 일반화 |
| `lib/utils/buttonActions.ts` Excel `findTableListComponent` (구 line ~5283) | `comp.componentType === "table-list"` + 수동 `selectedTable` / `tableName` OR 체인 | `isTableLikeComponent(comp)` + `getTableNameFromTableLikeComponent(comp) === context.table_name` |
| `app/(main)/screens/[screenId]/page.tsx` `hasTableWidget` (구 line 431) | `componentType === "table-list" \|\| componentType === "v2-table-list" \|\| widgetType === "table"` OR 체인 | `isTableLikeComponent(comp)`. canonical `table` 도 동일하게 자동 로드 skip |
| `components/screen/widgets/TabsWidget.tsx` `screenInfoMap` (구 line 146) | `c.component_type === "table" \|\| === "v2-table-list" \|\| === "table-list"` OR 체인 + `tableComp?.component_config?.selectedTable` 수동 추출 | `isTableLikeComponent(c)` + `getTableNameFromTableLikeComponent(tableComp)`. snake_case `component_type` 누락 위험도 동시 해소 |
| `components/screen/modals/MultilangSettingsModal.tsx` `getTypeIcon` (구 line 154) | `case "table-list": <Table2 />` 단독 | `case "table" / "table-list" / "v2-table-list"` fallthrough 묶음. 기존 호환 유지 |
| `components/screen/modals/MultilangSettingsModal.tsx` `NON_INPUT_COMPONENT_TYPES` (구 line 196) | `"table-list"` 만 Set 에 | `"table"`, `"v2-table-list"` 추가. canonical / hidden legacy 모두 라벨 다국어 처리 제외 |
| `components/screen/panels/ComponentsPanel.tsx` (주석만) | `allComponents` 위 주석 + `hiddenComponents` `table-list` 주석이 "→ v2-table-list" 식으로 옛 매핑 표기 | "canonical `table` 이 새 생성 경로, v2-table-list 는 hidden legacy 등록 (registry hard blocker 보존)" 으로 명확화. hidden list 자체는 유지 |
### 10.3 보존한 Hard Blocker (이번 단계에서 의도적으로 건드리지 않음)
| 위치 | 보존 이유 |
|---|---|
| `lib/registry/components/v2-table-list/**`, `lib/registry/components/table-list/**` | §4 와 동일. 옛 저장 화면에서 `componentType: "v2-table-list"` / `"table-list"` 를 직접 가리키는 layout JSON 다수 — 런타임 렌더 미보장 시 화면 깨짐 |
| `lib/registry/components/index.ts``table-list` / `v2-table-list` auto-register import | ComponentRegistry 등록이 빠지면 옛 화면 로드 실패. 삭제 금지 |
| `lib/schemas/componentConfig.ts``v2-table-list` schema / default | old layout load compatibility (`componentConfig` schema 검증을 통과해야 함). 삭제 금지 |
| `buttonActions.ts``split-panel-layout` 분기 (line ~3293, ~3477) | table-like 와는 별개 컴포넌트. `componentConfig.leftPanel.tableName` 라는 고유 경로 사용. helper 적용 대상 아님 → §4 와 동일하게 보존 |
| `frontend/components/control/**`, `frontend/components/dash/**`, `frontend/styles/control-mode.css` | 본 cleanup 범위 외 (§9 의 control/dash revert 와 동일 정책) |
| 금지 토큰 (`v2-input`, `v2-select`, `V2InputRenderer`, `V2SelectRenderer`, `EntityPicker`, `entity-picker`, `EntitySearchModal`) 재도입 금지 | 본 작업에서 재도입 0건 (§10.4 acceptance) |
### 10.4 Acceptance (이번 단계)
| 검증 항목 | 명령 | 결과 |
|---|---|---|
| Whitespace clean | `git diff --check` | ✅ pass (출력 없음) |
| 금지 토큰 (input canonical) | `rg "v2-input\|v2-select\|V2InputRenderer\|V2SelectRenderer" frontend/lib frontend/components frontend/app frontend/types frontend/styles` | ✅ 0건 |
| EntityPicker 잔재 | `rg "EntityPicker\|entity-picker\|EntitySearchModal" frontend/lib/registry/components/input frontend/components/v2/config-panels/InvFieldConfigPanel.tsx` | ✅ 0건 |
| 3개 파일 `componentType === "table-list"` 단독 분기 | `rg 'componentType === "table-list"' frontend/lib/utils/buttonActions.ts "frontend/app/(main)/screens/[screenId]/page.tsx" frontend/components/screen/widgets/TabsWidget.tsx` | ✅ 0건 |
| backend-spring 컴파일 | `cd backend-spring && ./gradlew compileJava` | ✅ BUILD SUCCESSFUL |
| 변경 파일 TS 신규 에러 | `npx tsc --noEmit` — 본 단계에서 손댄 line 들 | ✅ 0건 신규 에러 (helper 추가 line, OR 체인 교체 line 모두 깨끗. 기존 에러는 본 cleanup 범위 외라 유지) |
### 10.5 변경 파일 요약 (이번 단계)
```
M frontend/lib/utils/componentTypeUtils.ts (+helper block 100여 줄)
M frontend/lib/utils/buttonActions.ts (3곳 helper 호출로 교체, +1 import)
M frontend/app/(main)/screens/[screenId]/page.tsx (hasTableWidget 한 줄 helper 호출, +1 import)
M frontend/components/screen/widgets/TabsWidget.tsx (screenInfoMap helper 호출, +1 import)
M frontend/components/screen/modals/MultilangSettingsModal.tsx (icon/Set 분류만)
M frontend/components/screen/panels/ComponentsPanel.tsx (주석 정리만)
M notes/gbpark/2026-05-19-canonical-data-view-cleanup-followup.md (본 §10)
```
### 10.6 후속 작업 후보 (이번 범위 밖)
- v2-table-list / table-list 폴더의 실제 폐기 — old layout 마이그레이션이 끝난 뒤
§4 hard blocker 와 함께 별도 phase 로 진행
- `componentConfig.ts` schema / default 의 v2-table-list 제거 — 동일 조건
- `buttonActions.ts``split-panel-layout` 분기 — canonical table.displayMode='split'
master-detail UX 완성 후 §4 와 함께 마이그레이션
- 기존 page.tsx / buttonActions.ts 의 기존 TS 에러 (snake_case vs camelCase 타입 불일치)
정리 — 본 cleanup 과 무관한 별도 트랙
---
## 11. 2026-05-19 추가 (2차) — Helper 확산 (button/preview/backend)
§10 에서 도입한 helper 를 **외부 active branch 8 frontend + 2 backend** 까지 확산.
런타임 보존 폴더 / schema / auto-register 는 그대로 유지하고 active 분기만 교체.
### 11.1 변경 파일 (10개)
| 파일 | 변경 요지 |
|---|---|
| `frontend/components/screen/config-panels/button/DataTab.tsx` | 로컬 `isDataTransferComponentType` 정의를 `isTableLikeComponentType` 기반으로 정리. table-like 외 `repeater-field-group` / `form-group` 만 별도 `DATA_TRANSFER_EXTRA_PATTERNS` 로 보존 |
| `frontend/components/screen/config-panels/button-config/ActionTab.tsx` | 동일한 로컬 helper 정리 + `compType === "table-list"` 단독 분기 2곳 (`autoDetect` modal source 감지, `openModalWithData` 소스 감지) 을 `isTableLikeComponent` + `getTableNameFromTableLikeComponent` 로 교체. `compId === "table-list"` OR 체인 (테이블명 폴백) 도 `isTableLikeComponentType(compId)` 로 정리. `split-panel-layout` / `screen-split-panel` / `split-panel-layout2` 는 별개 컴포넌트라 그대로 보존 |
| `frontend/components/v2/config-panels/InvLegacyButtonConfigPanel.tsx` | 동일한 로컬 `isDataTransferComponentType` 정리 |
| `frontend/components/screen/ScreenNode.tsx` | `componentKind === "table-list"` 포함 OR 체인을 `isTableLikeComponentType(componentKind)` + `TABLE_LIKE_EXTRA_KINDS` (grouped-table / card-list / data-grid) 로 정리. 미니어처 색상 결정용 |
| `frontend/components/screen/RealtimePreviewDynamic.tsx` | `fillParentTypes` 배열의 `table` / `table-list` / `v2-table-list` 를 helper 로 통합 + 그 외 split/tabs layout 만 명시 목록 유지. `componentConfig.type === "table-list"` 단독 분기 2곳 (size.height 최소 200 보장, 기본 200 fallback) 도 helper 호출로 교체 |
| `frontend/lib/registry/components/button-primary/ButtonPrimaryComponent.tsx` | `provider.component_type === "table-list"` 단독 탐색 → `isTableLikeComponentType(provider.component_type)` |
| `frontend/lib/registry/components/v2-button-primary/ButtonPrimaryComponent.tsx` | 동일한 패턴 + DataReceiver 자동 탐색의 `rt === "table" \|\| === "table-list" \|\| === "data-table"` OR 체인 → helper 한 호출 |
| `frontend/lib/registry/components/universal-form-modal/UniversalFormModalConfigPanel.tsx` | `compType === "table-list" \|\| === "interactive-data-table"` OR 체인 → `isTableLikeComponentType(compType) \|\| compType === "interactive-data-table"` |
| `backend-spring/src/main/java/com/erp/service/ScreenGroupService.java` | `private static int countTableLikeWidgets(Map<String,Integer>)` 헬퍼 신규 — `table` + `table-list` + `v2-table-list` 합산. `screenType = "grid"` 추론 분기 2곳 (`extractScreenLayout` / `getScreenSummary`) 모두 helper 사용. 셋 중 어느 것이든 있으면 grid |
| `backend-spring/src/main/resources/mapper/screenGroup.xml` | `selectSavableScreensForGroup``NOT EXISTS` 서브쿼리에서 `componentType = 'table-list'` 단독을 `IN ('table', 'table-list', 'v2-table-list')` 로 확장. 체크박스 활성 판정도 legacy `componentConfig.checkbox.enabled` 와 canonical `componentConfig.showCheckbox` 를 SQL OR 로 구분 처리 |
### 11.2 보존한 Hard Blocker (이번 단계에서 의도적으로 건드리지 않음)
| 위치 | 보존 이유 |
|---|---|
| `lib/registry/components/v2-table-list/**`, `lib/registry/components/table-list/**` | §4 / §10.3 와 동일. 옛 저장 layout JSON 의 직접 type 지목 — 폴더 삭제/대형 수정 시 화면 깨짐 |
| `lib/schemas/componentConfig.ts` 의 v2-table-list schema / default | old layout config 검증 통과 hard blocker. 삭제 금지 |
| `lib/registry/components/repeat-container/**``dataSourceType = "table-list"` enum | **컴포넌트 type 이 아니라 데이터 소스 모드 enum 값**. helper 적용 대상 아님. 같은 문자열이지만 도메인이 다름 → 이번 범위에서 건드리지 않음 |
| `frontend/components/v2/config-panels/InvDataConfigPanel.tsx``v2-table-list` 참조 | old layout config hard blocker. `InvDataConfigPanel` 이 v2-list / v2-table-list canonical 경로에서 사용 (§4 참조). 보존 |
| `ActionTab.tsx` / `RealtimePreviewDynamic.tsx``split-panel-layout` / `split-panel-layout2` / `screen-split-panel` / `v2-tab-container` / `tabs-widget` 등 분기 | table-like 와 별개 컴포넌트. `componentConfig.leftPanel.*` / `componentConfig.tabs.*` 등 고유 path 사용. helper 적용 대상 아님 |
| `frontend/components/control/**`, `frontend/components/dash/**`, `frontend/styles/control-mode.css` | §9 정책과 동일. 본 cleanup 범위 외 |
| 금지 토큰 (`v2-input`, `v2-select`, `V2InputRenderer`, `V2SelectRenderer`, `EntityPicker`, `entity-picker`, `EntitySearchModal`) | 본 작업에서 재도입 0건 |
### 11.3 Acceptance (이번 단계)
| 검증 항목 | 명령 | 결과 |
|---|---|---|
| Whitespace clean | `git diff --check` | ✅ pass (출력 없음) |
| 금지 토큰 (input canonical) | `rg "v2-input\|v2-select\|V2InputRenderer\|V2SelectRenderer" frontend/lib frontend/components frontend/app frontend/types frontend/styles` | ✅ 0건 |
| EntityPicker 잔재 | `rg "EntityPicker\|entity-picker\|EntitySearchModal" frontend/lib/registry/components/input frontend/components/v2/config-panels/InvFieldConfigPanel.tsx` | ✅ 0건 |
| 10개 수정 대상 파일 `componentType === "table-list"` 단독 분기 | `rg 'componentType === "table-list"\|component_type === "table-list"'` (수정 대상 8개 frontend 파일 한정) | ✅ 0건 |
| backend-spring 컴파일 | `cd backend-spring && ./gradlew compileJava` | ✅ BUILD SUCCESSFUL |
| 변경 파일 TS 신규 에러 | `npx tsc --noEmit` — 본 단계 손댄 line | ✅ 0건 신규 에러 (helper 추가/교체 line 모두 깨끗. 기존 에러는 §10.4 와 동일하게 본 범위 외라 유지) |
### 11.4 helper 사용 사이트 누적 (§10 + §11)
| Helper | 사용처 |
|---|---|
| `isTableLikeComponentType(typeValue)` | `componentTypeUtils.ts` 내부 (`isTableLikeComponent` 의 부품), `DataTab.tsx`, `ActionTab.tsx`, `InvLegacyButtonConfigPanel.tsx`, `ScreenNode.tsx`, `RealtimePreviewDynamic.tsx`, `ButtonPrimaryComponent.tsx` (×2), `UniversalFormModalConfigPanel.tsx` |
| `isTableLikeComponent(component)` | `buttonActions.ts` (×3), `screens/[screenId]/page.tsx`, `TabsWidget.tsx`, `ActionTab.tsx` (×2) |
| `getTableNameFromTableLikeComponent(component)` | `buttonActions.ts` (×3), `TabsWidget.tsx`, `ActionTab.tsx` (×2) |
### 11.5 후속 작업 후보 (이번 범위 밖)
- canonical table 의 `showCheckbox` config 실제 검증 — `screenGroup.xml` 의 OR 분기가
canonical 화면 SQL 결과에 미치는 영향 확인 (실 데이터 검증 필요)
- `ActionTab.tsx``v2-list` 분기 — 별도 컴포넌트이므로 v2-list 폐기 시 같이 정리
- `ScreenNode.TABLE_LIKE_EXTRA_KINDS` (grouped-table / card-list / data-grid) — canonical
컴포넌트군 정착 후 `TABLE_LIKE_COMPONENT_TYPES` 본체로 흡수 검토
- `repeat-container``dataSourceType = "table-list"` enum naming — 도메인 분리 위해
`tableList``legacyTableList` 등으로 rename 검토 (별도 트랙)
@@ -0,0 +1,210 @@
# 2026-05-19 Claude Prompt — Canonical Data View Cleanup Scope Fix
아래 내용을 Claude Code 에 일반 프롬프트로 붙여넣는다. `/goal` 명령은 쓰지 않는다.
---
## Prompt
너는 이 repo 에서 이미 진행된 `canonical data-view cleanup` 결과를 최종 수습하는 역할이다.
중요: 이번 작업은 새로운 대규모 기능 구현이 아니다. 현재 diff 중 `stats/table/container/chart/card-list/grouped-table` canonical 정리 범위는 보존하되, 범위 밖 변경을 제거하고 검증 가능한 상태로 만드는 것이 목표다.
작업 전제:
- Workspace: `/Users/gbpark/invyone`
- 원 설계 문서:
- `notes/gbpark/2026-05-18-canonical-data-view-goal.md`
- `notes/gbpark/2026-05-18-claude-goal-prompt-v2-strict.md`
- 현재 후속 보고서:
- `notes/gbpark/2026-05-19-canonical-data-view-cleanup-followup.md`
- Codex 1차 검증 결과:
- acceptance check 자체는 통과했다.
- 하지만 Claude 가 canonical cleanup 범위를 넘어 `control/dash` 데모 기능을 추가했다.
- 이 범위 밖 변경은 이번 cleanup 결과에 포함하면 안 된다.
절대 규칙:
1. `/goal` 을 사용하지 말고, 이 프롬프트 범위 안에서 한 번에 처리한다.
2. `input` canonical 작업의 결과를 되돌리거나 훼손하지 않는다.
3. `FieldConfig`, `DataPort`, `sourceProvider`, `dataReceiver`, `dbTable` 관련 계약을 깨지 않는다.
4. `v2-input`, `v2-select`, `V2InputRenderer`, `V2SelectRenderer`, `EntityPicker`, `EntitySearchModal` 을 재도입하지 않는다.
5. legacy/V2 삭제 또는 alias 정리는 “동작 경로가 canonical 으로 수렴하는 경우”에만 유지한다.
6. 범위 밖 변경은 새 feature 로 인정하지 않는다. 이번 cleanup diff 에서 제거하거나, 제거가 위험하면 정확한 이유를 보고하고 중단한다.
7. 사용자가 만든 것일 수 있는 unrelated backend/notes 변경은 임의로 되돌리지 않는다.
이번 작업에서 보존해야 하는 canonical cleanup 범위:
- canonical data-view 관련 registry/config/schema/type 정리
- `frontend/lib/registry/DynamicComponentRenderer.tsx`
- `frontend/lib/registry/components/index.ts`
- `frontend/lib/utils/getComponentConfigPanel.tsx`
- `frontend/lib/utils/responsiveDefaults.ts`
- `frontend/lib/utils/templateMigrate.ts`
- `frontend/lib/schemas/componentConfig.ts`
- `frontend/types/v2-components.ts`
- `frontend/lib/registry/hoc/withContainerQuery.css`
- input 작업 후속 data-transfer 타입 판정 정리
- `frontend/components/screen/config-panels/button/DataTab.tsx`
- `frontend/components/screen/config-panels/button-config/ActionTab.tsx`
- `frontend/components/v2/config-panels/InvLegacyButtonConfigPanel.tsx`
- canonical data-view 신규/기존 연결
- `frontend/lib/registry/components/stats/**`
- `frontend/lib/registry/components/table/**`
- `frontend/lib/registry/components/container/**`
- `frontend/lib/registry/components/chart/**`
- `frontend/lib/registry/components/card-list/**`
- `frontend/lib/registry/components/grouped-table/**`
- 의도된 삭제 대상
- `frontend/lib/registry/components/aggregation-widget/**`
- `frontend/lib/registry/components/v2-aggregation-widget/**`
- `frontend/lib/registry/components/v2-status-count/**`
- `frontend/lib/registry/components/tabs/**`
- `frontend/lib/registry/components/v2-tabs-widget/**`
- `frontend/lib/registry/components/section-card/**`
- `frontend/lib/registry/components/v2-section-card/**`
- `frontend/lib/registry/components/section-paper/**`
- `frontend/lib/registry/components/v2-section-paper/**`
- `frontend/components/v2/config-panels/V2AggregationWidgetConfigPanel.tsx`
- `frontend/components/v2/config-panels/V2StatusCountConfigPanel.tsx`
이번 작업에서 제거해야 하는 범위 밖 변경:
- `frontend/components/control/ControlMode.tsx`
- `frontend/components/control/ControlPalette.tsx`
- `frontend/components/control/FlowViewer.tsx`
- `frontend/components/control/PortHandle.tsx`
- `frontend/components/control/RuleBuilder.tsx`
- `frontend/components/control/controlDemo.ts`
- `frontend/components/dash/DashboardCanvas.tsx`
- `frontend/components/dash/DashboardLayout.tsx`
- `frontend/styles/control-mode.css`
위 파일들은 canonical data-view cleanup 과 무관한 제어모드 데모/대시보드 변경이다. 이번 작업에서는 포함하지 않는다. tracked 파일은 현재 branch 의 HEAD 상태로 되돌리고, untracked `controlDemo.ts` 는 삭제한다. 단, 되돌리기 전에 `git diff -- <path>` 로 확인했을 때 canonical data-view cleanup 과 직접 관련된 변경이 섞여 있으면 되돌리지 말고 보고한다.
진행 순서:
1. 현재 상태를 먼저 확인한다.
```bash
git status --short
git diff --name-status
git diff --stat
```
2. 범위 밖 변경을 확인한다.
```bash
git diff -- frontend/components/control frontend/components/dash frontend/styles/control-mode.css
git status --short -- frontend/components/control frontend/components/dash frontend/styles/control-mode.css
```
확인 기준:
- `controlDemo.ts`, demo table/meta, `createDemoRuleGraph`, `CONTROL_DEMO_TABLES`, `onLoadDemo`, flow-active styling 같은 변경은 범위 밖이다.
- 해당 변경은 이번 cleanup 에 포함하지 않는다.
3. 범위 밖 변경만 제거한다.
안전 조건:
- 제거 대상은 위 “이번 작업에서 제거해야 하는 범위 밖 변경” 목록으로 제한한다.
- 다른 파일은 revert 하지 않는다.
- repo 전체 reset, checkout, clean 금지.
예시:
```bash
git restore -- frontend/components/control/ControlMode.tsx \
frontend/components/control/ControlPalette.tsx \
frontend/components/control/FlowViewer.tsx \
frontend/components/control/PortHandle.tsx \
frontend/components/control/RuleBuilder.tsx \
frontend/components/dash/DashboardCanvas.tsx \
frontend/components/dash/DashboardLayout.tsx \
frontend/styles/control-mode.css
rm frontend/components/control/controlDemo.ts
```
`rm` 은 위 untracked 파일 하나에만 사용한다.
4. report 를 정정한다.
`notes/gbpark/2026-05-19-canonical-data-view-cleanup-followup.md` 를 업데이트한다.
반드시 반영할 내용:
- summary 의 “7개 폴더” vs 실제 “9개 폴더” 불일치를 고친다.
- Codex 검증에서 범위 밖 `control/dash` 변경이 발견되어 제거했다는 사실을 기록한다.
- 제거한 범위 밖 파일 목록을 기록한다.
- acceptance command 와 결과를 최신 상태로 다시 기록한다.
- 잔여 매칭은 hard blocker/domain 으로만 남아야 하며, 각 보존 사유를 명시한다.
5. 필수 acceptance check 를 다시 실행한다.
```bash
git diff --check
rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer" frontend/lib frontend/components frontend/app frontend/types frontend/styles --glob '!**/node_modules/**'
rg "EntityPicker|entity-picker|EntitySearchModal" frontend/lib/registry/components/input frontend/components/v2/config-panels/InvFieldConfigPanel.tsx --glob '!**/node_modules/**'
rg -n "from .*components/(aggregation-widget|v2-aggregation-widget|v2-status-count|tabs|v2-tabs-widget|section-card|v2-section-card|section-paper|v2-section-paper)|import\\(.*components/(aggregation-widget|v2-aggregation-widget|v2-status-count|tabs|v2-tabs-widget|section-card|v2-section-card|section-paper|v2-section-paper)" frontend --glob '!**/node_modules/**'
test ! -e frontend/lib/registry/components/aggregation-widget
test ! -e frontend/lib/registry/components/v2-aggregation-widget
test ! -e frontend/lib/registry/components/v2-status-count
test ! -e frontend/lib/registry/components/tabs
test ! -e frontend/lib/registry/components/v2-tabs-widget
test ! -e frontend/lib/registry/components/section-card
test ! -e frontend/lib/registry/components/v2-section-card
test ! -e frontend/lib/registry/components/section-paper
test ! -e frontend/lib/registry/components/v2-section-paper
git diff --quiet -- frontend/components/control frontend/components/dash frontend/styles/control-mode.css
git status --short -- frontend/components/control/controlDemo.ts
```
backend compile:
```bash
cd backend-spring
./gradlew compileJava
```
잔여 카운트도 다시 계산한다.
```bash
rg -n "stats|aggregation-widget|v2-status-count" frontend/lib frontend/components frontend/app frontend/types --glob '!**/node_modules/**' | wc -l
rg -n "table-list|v2-table-list" frontend/lib frontend/components frontend/app frontend/types --glob '!**/node_modules/**' | wc -l
rg -n "tabs-widget|v2-tabs-widget|section-card|section-paper|accordion-basic|conditional-container|repeat-container|v2-repeat-container|split-panel-layout" frontend/lib frontend/components frontend/app frontend/types --glob '!**/node_modules/**' | wc -l
```
주의:
- `rg` 가 0건이어야 하는 check 는 exit code 1 이 정상일 수 있다. 출력이 0건이면 pass 로 기록한다.
- 전체 `npm run lint` 는 기존 repo-wide lint 부채 때문에 이번 acceptance 조건이 아니다. 실행하지 않아도 된다. 실행했다면 기존 오류와 이번 변경 오류를 구분해서 보고한다.
6. 마지막으로 다음을 보고한다.
- canonical cleanup diff 는 유지됐는가
- 범위 밖 `control/dash` 변경은 제거됐는가
- deleted legacy folder/import 는 실제로 사라졌는가
- input forbidden / EntityPicker forbidden 은 0건인가
- backend compile 결과
- 잔여 `stats/table/container` 매칭 수와 보존 사유
- 수정한 파일 목록
완료 기준:
- `git diff --check` pass
- input forbidden rg 출력 0건
- EntityPicker forbidden rg 출력 0건
- 삭제된 legacy component folder 가 실제로 존재하지 않음
- 삭제된 legacy component folder 로 import 하는 active code 0건
- `./gradlew compileJava` BUILD SUCCESSFUL
- `git diff --quiet -- frontend/components/control frontend/components/dash frontend/styles/control-mode.css` pass
- `frontend/components/control/controlDemo.ts` 가 untracked/존재 상태로 남아 있지 않음
- follow-up report 의 folder deletion count 불일치가 수정됨
- 남은 legacy/V2 매칭은 구현 canonical, 삭제 path, concrete hard blocker, domain preserved 중 하나로 분류됨
금지:
- repo 전체 `git reset`, `git checkout .`, `git clean -fd` 금지
- unrelated backend 파일 revert 금지
- `input`/`EntityPicker` 관련 옛 경로 재도입 금지
- `control/dash` 데모 기능을 별도 feature 라고 주장하며 남겨두기 금지
- acceptance 실패를 “분류 가능”만으로 통과 처리 금지
최종 답변은 짧게, 실행한 command 결과 중심으로 작성한다.
File diff suppressed because it is too large Load Diff