# Codex Handoff — Input Canonical Migration

날짜: 2026-05-12
브랜치: `gbpark-node`
주 작업 문서: `notes/gbpark/2026-05-08-input-canonical-migration.md`

이 문서는 다른 컴퓨터에서 Codex가 바로 이어받기 위한 요약이다.

---

## 1. 목표

INVYONE Studio 입력 계열을 `FieldConfig / DataPort` 계약을 유지한 채 canonical `input`으로 통합한다.

핵심 원칙:
- `FieldConfig`의 원천은 `frontend/types/invyone-component.ts`다. 설정 패널 UI가 원천이 아니다.
- `DataPort / Connection` 계약은 축소하지 않는다.
- `v2-input`, `v2-select`는 구현체, alias, fallback, schema, DB layout 마이그 대상이 아니다. 제거 대상이다.
- 기존 DB layout JSON 마이그레이션은 하지 않는다. 새 솔루션 개발 기준이다.
- `entity`는 검색 모달이 아니라 참조 테이블의 code-name 옵션 source다.
- 검색 모달이 필요하면 별도 `entity-search-input` 계열에서 처리한다.

---

## 2. 완료된 범위

### V2 input/select 제거

삭제 완료:
- `frontend/lib/registry/components/v2-input/`
- `frontend/lib/registry/components/v2-select/`
- `frontend/components/v2/V2Input.tsx`
- `frontend/components/v2/V2Select.tsx`
- `frontend/components/v2/config-panels/V2InputConfigPanel.tsx`
- `frontend/components/v2/config-panels/V2SelectConfigPanel.tsx`

정리 완료:
- renderer alias / fallback 제거
- config panel alias 제거
- schema/default 제거
- registerV2Components 등록 제거
- V2 demo / V2 renderer 직접 참조 제거
- `types/v2-components.ts`에서 V2Input/V2Select 타입 제거

검증 기준:
```bash
rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer" frontend/lib frontend/components frontend/app frontend/types frontend/styles
```
결과는 0건이어야 한다.

### canonical select/entity

추가:
- `frontend/lib/registry/components/input/use-option-loader.ts`
- `frontend/lib/registry/components/input/select-pickers.tsx`의 `SwapPicker`

`useOptionLoader` source:
- `static`
- `code`
- `category`
- `entity`
- `distinct` / `select`
- `api`
- `db`

entity 정책:
- `/entity/{table}/options?value={valueColumn}&label={labelColumn}`
- `config.entityTable/entityValueColumn/entityLabelColumn`
- 또는 `config.ref.table/valueColumn/displayColumn`
- entity modal 재유입 금지

filter runtime:
- `OptionFilter[]`를 runtime에서 `formData` / `userContext`로 치환
- `entity`, `distinct/select`, `db` URL에 `filters=` query append
- `code`, `category`, `api`는 backend/external spec 미정으로 미적용

### canonical file/image/img

추가:
- `frontend/lib/registry/components/input/file-picker.tsx`

변경:
- `InputComponent`의 `case "file"`이 `FilePicker` 사용
- `file/image/img/picture/photo`는 canonical input file로 라우팅
- `webTypeMapping.ts`에서 `file/image/img` 모두 `componentType: "input"`
- `DynamicWebTypeRenderer`의 old FileUpload/ImageWidget 직접 import 제거
- `InteractiveScreenViewerDynamic` master save에서 canonical file 값 업로드 후 id/path로 치환

file 저장 정책:
- `string/string[]`: 이미 저장된 값으로 보고 유지
- `File/File[]`: `uploadFiles` 호출 후 `id ?? server_path ?? server_filename`로 치환
- mixed `(File | string)[]`: string 유지 + File 업로드 결과 합침
- 업로드 실패 시 `File` 객체가 `saveData`에 들어가지 않도록 string만 유지

old file/media 삭제 완료:
- `frontend/lib/registry/components/v2-file-upload/`
- `frontend/lib/registry/components/v2-media/`
- `frontend/lib/registry/components/image-widget/`
- `frontend/lib/registry/components/image-display/`
- `frontend/components/v2/V2Media.tsx`
- `frontend/components/v2/config-panels/V2MediaConfigPanel.tsx`
- `frontend/components/v2/config-panels/V2FileUploadConfigPanel.tsx`
- `frontend/components/screen/widgets/types/ImageWidget.tsx`
- `frontend/lib/registry/components/file-upload/FileUploadComponent.tsx`
- `frontend/lib/registry/components/file-upload/FileUploadRenderer.tsx`
- `frontend/lib/registry/components/file-upload/FileUploadConfigPanel.tsx`
- `frontend/lib/registry/components/file-upload/config.ts`
- `frontend/lib/registry/components/file-upload/README.md`

보존:
- `frontend/lib/registry/components/file-upload/FileViewerModal.tsx`
- `frontend/lib/registry/components/file-upload/FileManagerModal.tsx`
- `frontend/lib/registry/components/file-upload/types.ts`
- `frontend/lib/registry/components/file-upload/index.ts`는 shared viewer/type export shim

검증 기준:
```bash
rg "componentType: \"v2-file-upload\"|file: \"v2-file-upload\"|image: \"v2-file-upload\"|img: \"v2-file-upload\"" frontend/lib frontend/components frontend/app frontend/types
rg "FileUploadComponent|FileUploadRenderer|FileUploadConfigPanel|V2Media\\b|V2MediaConfigPanel|V2FileUpload|ImageWidget|ImageDisplay" frontend/lib frontend/components frontend/app frontend/types
```
첫 번째는 0건이어야 한다. 두 번째는 폐기 주석, `WidgetRenderer`의 `isImageWidget` 문자열, `pop-text` 내부 helper 정도만 남아야 한다.

---

## 3. 현재 known verification

통과:
```bash
git diff --check
git diff --cached --check
rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer" frontend/lib frontend/components frontend/app frontend/types frontend/styles
rg "componentType: \"v2-file-upload\"|file: \"v2-file-upload\"|image: \"v2-file-upload\"|img: \"v2-file-upload\"" frontend/lib frontend/components frontend/app frontend/types
rg "EntityPicker|entity-picker|EntitySearchModal" frontend/lib/registry/components/input frontend/components/v2/config-panels/InvFieldConfigPanel.tsx
```

전체 `tsc`는 아직 전역 기존 오류로 실패한다. D.6 삭제로 인한 old file/media `Cannot find module`은 0건이었다.

현재 확인된 기존 module 오류:
```text
@/lib/api/hierarchyColumn
@formkit/auto-animate/react
@/lib/types/screen
```

---

## 4. 다음 작업

### Phase D.7 — canonical input mask / slider / color 흡수

목표:
- 남은 옛 입력 고유 기능 `mask`, `slider`, `color`를 canonical `input`에 흡수한다.
- `v2-input/v2-select` 복구 금지.
- old file/media 복구 금지.
- FieldConfig / DataPort 변경 금지.

구현 방향:
- `slider`
  - `type="number" + format="slider"` 또는 `inputType/webType === "slider"`
  - `min/max/step` 지원
  - `propagate` 흐름 유지
  - readonly/disabled 처리
- `color`
  - `type="text" + format="color"` 또는 `inputType/webType === "color"`
  - native color input + hex text input
  - 값은 `#rrggbb` 문자열
- `mask`
  - `InputConfig.mask?: string`
  - text onChange에서 간단 mask 적용
  - `#` 또는 `0` = digit, `A` = alphabet, `*` = any char, 나머지는 literal

수정 후보:
- `frontend/lib/registry/components/input/InputComponent.tsx`
- `frontend/lib/registry/components/input/types.ts`
- `frontend/components/v2/config-panels/InvFieldConfigPanel.tsx`
- `frontend/lib/utils/webTypeMapping.ts`
- `frontend/components/screen/panels/ComponentsPanel.tsx`
- `frontend/lib/registry/components/index.ts`

검증:
```bash
git diff --check
git diff --cached --check
rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer" frontend/lib frontend/components frontend/app frontend/types frontend/styles
rg "componentType: \"v2-file-upload\"|file: \"v2-file-upload\"|image: \"v2-file-upload\"|img: \"v2-file-upload\"" frontend/lib frontend/components frontend/app frontend/types
rg "EntityPicker|entity-picker|EntitySearchModal" frontend/lib/registry/components/input frontend/components/v2/config-panels/InvFieldConfigPanel.tsx
```

### Phase E — old 6 input components 삭제

D.7 이후 진행.

대상:
- `frontend/lib/registry/components/date-input/`
- `frontend/lib/registry/components/text-input/`
- `frontend/lib/registry/components/number-input/`
- `frontend/lib/registry/components/select-basic/`
- `frontend/lib/registry/components/checkbox-basic/`
- `frontend/lib/registry/components/textarea-basic/`

전제:
- `webTypeMapping`, `ScreenSettingModal`, `ComponentsPanel`, `components/index.ts`, config panel alias가 모두 canonical `input`으로 정리되어야 한다.
- `DateInputComponent.tsx` 기존 타입 오류는 삭제 시 자연 해소될 가능성이 높다.

---

## 5. 금지 사항

- `v2-input`, `v2-select` 문자열 재생성 금지
- `V2InputRenderer`, `V2SelectRenderer` 복구 금지
- `V2Input.tsx`, `V2Select.tsx` 복구 금지
- `EntityPicker` / `EntitySearchModal`을 canonical input에 넣지 말 것
- old file/media 본체 복구 금지
- DB layout JSON 변환 SQL 작성 금지
- FieldConfig / DataPort 계약 축소 금지

---

## 6. 진행 완료 요약 (2026-05-13, Phase F.4)

### 6.1 완료된 Phase

| Phase | 내용 | 상태 |
|---|---|---|
| D.7 | canonical `input` 에 `mask` / `slider` / `color` 흡수 | ✅ 완료 |
| E   | 옛 입력 6종 폴더 삭제 (text/number/date/select/checkbox/textarea) | ✅ 완료 |
| F.1 | `radio-basic` · `toggle-switch` 폴더 삭제 | ✅ 완료 |
| F.2 | `test-input` 폴더 삭제, 기타 input-adjacent 후보 분류/보존 | ✅ 완료 |
| F.3 | orphan `category-manager.tsx` 삭제, `v2-numbering-rule` stale schema 정리 | ✅ 완료 |
| F.4 | 최종 grep audit + 본 노트 업데이트 | ✅ 완료 |

병합 커밋: `7bd08dcf9 refactor(components): consolidate canonical input cleanup`

### 6.2 삭제된 컴포넌트 폴더/파일

- 옛 입력 6종 (Phase E): `text-input/`, `number-input/`, `date-input/`, `select-basic/`, `checkbox-basic/`, `textarea-basic/`
- 슬라이더 (Phase D.7): `slider-basic/`
- 라디오/토글 (Phase F.1): `radio-basic/`, `toggle-switch/`
- CLI demo 잔재 (Phase F.2): `test-input/`
- orphan 정의 파일 (Phase F.3): `lib/registry/components/category-manager.tsx` (standalone, never imported)

### 6.3 의도적 보존 (explicit / domain)

| 폴더 | 분류 | 보존 이유 |
|---|---|---|
| `entity-search-input/` | explicit 검색 모달 | canonical input 의 `entity` 는 code-name option source 전용. 명시적 검색 UI 가 필요한 케이스는 별도 계열로 유지. `useEntitySearch` hook 은 modal-repeater-table / autocomplete-search-input 에서도 공유. |
| `autocomplete-search-input/` | explicit autocomplete | demo 페이지 (`app/test-autocomplete-mapping/page.tsx`) 와 runtime 분기 (`DynamicComponentRenderer`) 가 살아있음. |
| `selected-items-detail-input/` | explicit 선택항목 상세 입력 | `screenGroup.ts` 의 `parentDataMapping`, `V2PropertiesPanel` 테이블 로딩, `V2SelectedItemsDetailInputConfigPanel` 등 다지점 의존. |
| `domain/v2-location-swap-selector/` | domain 컴포넌트 | 도메인 별 출발/도착 swap UI. 추후 domain phase 에서 재평가. |
| `v2-category-manager/` | domain 컴포넌트 | 카테고리 관리. 추후 domain phase 에서 재평가. |
| `category-manager/` (폴더) | explicit category manager | "공통코드관리" 통합 phase 에서 일괄 처리 예정. |
| `mail-recipient-selector/` | explicit 메일 수신자 선택 | 내부 인원 + 외부 이메일 선택 기능 유지. |

### 6.4 보존 인접 시스템 (Phase F 범위 밖, 별도 서브시스템)

- `frontend/lib/api/numberingRule.ts`, `components/numbering-rule/`, `app/(main)/admin/systemMng/numberingRuleList/`, `types/numbering-rule.ts`: 채번관리 admin UI + API 클라이언트. canvas 컴포넌트 (v2-numbering-rule) 와 무관.
- `frontend/lib/registry/components/input/numbering-picker.tsx`: canonical input 의 autonum 진입점. 채번 admin API 호출.
- `frontend/lib/registry/pop-components/`: POP 카드 셀 타입 시스템 (`number-input` 등의 셀 이름). canvas input 컴포넌트와 동일 문자열이지만 별개 도메인. 절대 건드리지 말 것.

### 6.5 검증 명령 + 기대 결과

```bash
# 1. 작업 디렉터리 검사
git diff --check
git diff --cached --check

# 2. 금지 패턴 검사 (0 matches 기대)
rg "v2-input|v2-select|V2InputRenderer|V2SelectRenderer" \
  frontend/lib frontend/components frontend/app frontend/types frontend/styles

rg 'componentType: "v2-file-upload"|file: "v2-file-upload"|image: "v2-file-upload"|img: "v2-file-upload"' \
  frontend/lib frontend/components frontend/app frontend/types

rg "EntityPicker|entity-picker|EntitySearchModal" \
  frontend/lib/registry/components/input \
  frontend/components/v2/config-panels/InvFieldConfigPanel.tsx

# 3. 삭제된 입력 컴포넌트 (history comment 만 남아야 함)
rg "slider-basic|radio-basic|toggle-switch|test-input" \
  frontend/lib frontend/components frontend/app frontend/types frontend/styles
# → comment 만 12건 정도, 활성 코드 0건

rg "date-input|text-input|number-input|select-basic|checkbox-basic|textarea-basic" \
  frontend/lib frontend/components frontend/app frontend/types frontend/styles
# → comment + POP cell-type 만, 활성 입력 컴포넌트 코드 0건

# 4. 보존 컴포넌트 (활성 wiring 존재)
rg "entity-search-input|autocomplete-search-input|selected-items-detail-input|v2-location-swap-selector|v2-category-manager|category-manager|mail-recipient-selector" \
  frontend/lib frontend/components frontend/app frontend/types frontend/styles
# → 각 컴포넌트의 자체 폴더 + 활성 wiring 만 나와야 함
```

### 6.6 tsc 상태

- `frontend/package.json` 에서 직접 의존성으로 박혀있던 `lightningcss-linux-x64-gnu` 를 제거하여 Windows 에서 `npm install` 및 `tsc` 실행 가능.
- `./node_modules/.bin/tsc.cmd --noEmit --pretty false` → 2806개의 기존 전역 에러 (snake_case/camelCase, BlockRole). Phase D.7~F.3 은 새 에러를 만들지 않았으며, 삭제 모듈 관련 orphan import 도 0건.
- 전역 tsc 정리는 본 phase 의 책임이 아님.

### 6.7 다음 권장 작업

- 입력 canonical 정리는 **종결**. 추가 폴더 삭제는 새 plan/phase 가 필요.
- 다음 line of work 후보 (각각 별도 plan 필요):
  - `entity-search-input` / `autocomplete-search-input` 의 explicit UX 재평가 (canonical input 의 entity option source 와 진짜 search modal 의 경계 재확정)
  - `v2-category-manager` / `category-manager/` 의 "공통코드관리" 통합 phase
  - domain 컴포넌트 phase (`domain/v2-location-swap-selector`, `domain/v2-rack-structure`, `domain/v2-bom-*` 등)
  - 전역 snake_case ↔ camelCase 일관성 정리 (현재 tsc 에러 대부분의 원인)
