feat: add form and page platform
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
# VD-04: Native form controller와 local facade
|
||||
|
||||
- 상태: Accepted
|
||||
- 결정일: 2026-07-26
|
||||
- 적용 브랜치: `feature-frontend-form-page-platform`
|
||||
|
||||
## 배경
|
||||
|
||||
플랫폼에는 Zod가 이미 설치돼 있지만 form state, field error, dirty navigation과
|
||||
page template 계약은 없었다. React Hook Form과 resolver를 바로 추가하면
|
||||
dependency와 lockfile이 바뀌고, 현재 reference form에 필요하지 않은 복합 비동기
|
||||
field orchestration까지 플랫폼 기본값으로 고정하게 된다.
|
||||
|
||||
## 결정
|
||||
|
||||
1. RP-06은 React native form event와 controlled value를 사용하는 local
|
||||
`useAppForm` facade를 기본 엔진으로 채택한다.
|
||||
2. Zod presentation schema, application command mapper와 domain invariant는 서로
|
||||
다른 소유물로 유지한다.
|
||||
3. page와 feature는 `useAppForm`, `Form`, `FormField`, `ErrorSummary`,
|
||||
`mapValidationFailureToFields`, `useDirtyNavigationGuard`만 사용한다.
|
||||
4. 422 details는 승인된 `path`와 `code`만 HTTP 경계에서 투영한다. backend
|
||||
message와 알 수 없는 field는 field에 전달하지 않고 안전한 form-level
|
||||
error로 이동한다.
|
||||
5. 409 conflict는 validation으로 바꾸지 않으며 입력과 dirty 상태를 보존한다.
|
||||
6. pending submit은 동일 controller에서 한 번만 실행하고 success/reset 이후
|
||||
dirty 상태를 해제한다.
|
||||
7. `StandardPage`, `CollectionPage`, `DetailPage`, `FormPage`, `StatusPage`는
|
||||
layout과 state slot만 소유하며 application/query/HTTP를 import하지 않는다.
|
||||
|
||||
## React Hook Form 도입 조건
|
||||
|
||||
다음 중 하나가 실제 제품 요구로 확인되면 local facade 내부 adapter로
|
||||
React Hook Form과 Zod resolver를 평가한다.
|
||||
|
||||
- 동적 field array와 중첩 object를 함께 다루는 복합 form
|
||||
- field 단위 비동기 validation 취소와 의존 validation
|
||||
- 수백 개 field의 render isolation이 측정 가능한 병목인 경우
|
||||
- uncontrolled input 또는 vendor extension이 필요한 경우
|
||||
|
||||
도입하더라도 이 문서의 public API와 component/application tests를 유지해야
|
||||
한다. vendor package를 feature/page에서 직접 import하는 것은 허용하지 않는다.
|
||||
|
||||
## 검증과 rollback
|
||||
|
||||
- client validation, transform/default, 422 allowlist, conflict, duplicate submit,
|
||||
reset, dirty guard와 focus를 component test로 검증한다.
|
||||
- template 최소/전체 slot과 async/status variation을 component test로 검증한다.
|
||||
- architecture gate가 template의 application/HTTP/query vendor import를
|
||||
거절한다.
|
||||
- secret-like input이 URL, storage, diagnostics에 복제되지 않는지 검증한다.
|
||||
|
||||
rollback 시 reference page는 이전 직접 form/layout으로 돌아갈 수 있다.
|
||||
application input과 outbound gateway 계약은 유지되며, form facade와 template
|
||||
commit은 독립적으로 되돌릴 수 있다.
|
||||
@@ -67,18 +67,18 @@ recovery 계약, 제거 가능한 reference 수직 슬라이스는 구현됐다.
|
||||
| HTTP client | 준비됨 | path/search/body projection, runtime timeout/retry, abort/cleanup test | feature gateway 뒤에서 사용 |
|
||||
| retry | 준비됨 | HTTP 단일 소유, runtime max attempts, Query retry off | RP-09에서 telemetry 연결 |
|
||||
| 오류 모델 | 부분 준비 | error registry와 normalization 존재 | typed discriminated union과 계층별 mapper |
|
||||
| 검증 | 부분 준비 | runtime/API Zod parse 결과를 실제 request에 사용 | route/form/domain 경계를 추가 |
|
||||
| 검증 | 준비됨 | runtime/API/route/form Zod parse 결과를 실행 경계에서 사용하고 domain invariant와 분리 | feature별 schema 소유권 유지 |
|
||||
| 인증 연동 | 준비됨/프로젝트 선택 | opaque auth owner와 demo seam 존재 | 인증 방식별 recipe; 기본 token 저장소는 추가하지 않음 |
|
||||
| 서버 상태 | 준비됨 | reference route의 query/mutation, cancellation, stale, optimistic/conflict/rollback | feature별 query contribution recipe 유지 |
|
||||
| 클라이언트 상태 | 부분 준비 | local state, theme context, session external store | 상태 소유권 표와 typed external-store 예제 |
|
||||
| 범용 global store | 프로젝트 선택 | 별도 라이브러리 없음 | 필요 조건에 따라 Zustand/Redux Toolkit/state machine 선택 |
|
||||
| 라우팅 | 준비됨 | Data Router, typed runtime map, codec, metadata consumer, bounded chunk recovery | reference feature route와 release E2E로 사용 범위 확장 |
|
||||
| 앱 셸·반응형 | 부분 준비 | header/sidebar/content/theme 구현 | 접근 가능한 mobile drawer와 focus 복원 |
|
||||
| 페이지 템플릿 | 미제공 | 각 페이지가 직접 레이아웃 조립 | list/detail/form/status 등 슬롯 기반 템플릿 |
|
||||
| 페이지 템플릿 | 준비됨 | Standard/Collection/Detail/Form/Status slot 계약과 reference 소비 화면 | RP-07 public design-system entry로 이동 |
|
||||
| 디자인 토큰 | 부분 준비 | semantic color/theme 토큰 존재 | typography, spacing, motion, layer 등 3단계 토큰 |
|
||||
| 공통 UI | 부분 준비 | Button, TextField, Card, Alert, Badge, Dialog | form/navigation/overlay/data/layout primitives 확장 |
|
||||
| 아이콘 | 미제공 | 문자 기호를 직접 사용 | Lucide를 로컬 icon facade 뒤에서 사용 |
|
||||
| 폼 | 미제공 | 수동 문자열 검증 예제만 존재 | schema 기반 form facade와 422/dirty/pending 정책 |
|
||||
| 폼 | 준비됨 | Zod 기반 local facade, error summary/focus, 422 allowlist, dirty/pending/conflict 정책 | 복합 form 요구가 생기면 VD-04 조건으로 vendor adapter 평가 |
|
||||
| 국제화 | 미제공 | 한국어 문자열·locale이 하드코딩 | typed message/formatter/locale/RTL 경계 |
|
||||
| logging/diagnostics | 미제공 | telemetry port는 있으나 logger 없음 | redaction이 적용된 diagnostics/logging 경계 |
|
||||
| telemetry | 부분 준비 | registry, queue, redaction 존재 | HTTP·boot·cache·storage·route 사건에 실제 연결 |
|
||||
@@ -236,8 +236,8 @@ known vulnerability, license policy, SBOM/provenance를 pinned tool로 검사해
|
||||
|
||||
### 5.2 P1: 공통 플랫폼 기본 제공 항목
|
||||
|
||||
- schema 기반 form facade와 field/error/pending/dirty/422 정책
|
||||
- standard, collection, detail, form, status page template
|
||||
- RP-06에서 완료한 schema 기반 form facade와 field/error/pending/dirty/422 정책 유지
|
||||
- RP-06에서 완료한 standard, collection, detail, form, status page template의 public entry 정리
|
||||
- 접근 가능한 drawer, menu, popover, select 같은 interaction primitive
|
||||
- token → primitive → pattern → template로 이어지는 디자인 시스템
|
||||
- Lucide를 감싼 local icon registry와 `IconButton`
|
||||
|
||||
@@ -508,6 +508,22 @@ RP-06은 기존 reference controls/layout으로 돌아가도 controller/applicat
|
||||
경계가 유지돼야 한다. vendor adapter, form contract와 template commit을 구분해
|
||||
부분 revert가 가능하게 한다.
|
||||
|
||||
**구현 증거 (2026-07-26)**
|
||||
|
||||
- VD-04에서 dependency 추가 없는 native controller + Zod local facade를
|
||||
채택했고 vendor 도입 조건을 문서화했다.
|
||||
- `src/presentation/forms`가 field registration, parse/error map,
|
||||
dirty/touched/reset/pending/result, 422 allowlist, first-error focus,
|
||||
duplicate submit과 dirty navigation을 제공한다.
|
||||
- `src/presentation/templates`가 다섯 page 유형의 slot/landmark/responsive
|
||||
계약을 제공하며 architecture negative fixture가 application/vendor import를
|
||||
거절한다.
|
||||
- reference list/detail/create/status route가 네 구체 template를 사용하고
|
||||
production composition test가 list → form → command → HTTP → invalidation →
|
||||
list 경로를 실행한다.
|
||||
- component/integration/E2E test가 validation, transform, 422, conflict,
|
||||
secret 비노출, navigation focus와 320px reflow를 검증한다.
|
||||
|
||||
### 07. `feature-frontend-design-system-platform`
|
||||
|
||||
**목표**
|
||||
|
||||
@@ -163,6 +163,14 @@ contract/presentation은 `src/features/reference-feature`가 소유하고, gener
|
||||
installed catalog만 bootstrap과 router에 노출된다. 제거 gate는 feature와 test를
|
||||
삭제한 복제본에서 전체 P0 경로를 다시 실행한다.
|
||||
|
||||
RP-06에서 inbound form/page 경계도 실행됐다. `src/presentation/forms`는 Zod
|
||||
presentation schema, controlled field state, error focus, 422 allowlist,
|
||||
pending/deduplication과 dirty navigation을 local facade로 감싼다.
|
||||
`src/presentation/templates`는 slot과 landmark만 소유하고 application, HTTP,
|
||||
query vendor import는 architecture gate가 거절한다. reference feature의
|
||||
list/detail/create/status route가 각각 Collection/Detail/Form/Status template의
|
||||
실제 consumer다.
|
||||
|
||||
이 문서의 목표 구조는 기존 기반을 폐기하는 것이 아니라 이러한
|
||||
불일치를 제거하는 것이다.
|
||||
|
||||
@@ -1249,8 +1257,8 @@ contract와 실패 분기를 우선한다.
|
||||
|
||||
### P1: 기본 플랫폼 완성도
|
||||
|
||||
1. error/result/validation/form kernel
|
||||
2. 배타적인 async 상태와 page template
|
||||
1. 완료: error/result/validation/form kernel
|
||||
2. 완료: 배타적인 async 상태와 page template
|
||||
3. Logger와 telemetry 실제 wiring
|
||||
4. design-system public API, icon wrapper와 headless interaction
|
||||
5. locale/message/formatter와 pseudo-locale/RTL 경계
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
- page controller와 application input use case의 연결
|
||||
- 프론트엔드에서 반복 사용하는 설계 패턴
|
||||
|
||||
## 2. 현재 상태와 문제
|
||||
## 2. 현재 상태와 구현 기준
|
||||
|
||||
RP-04 이후 현재 구현에는 다음 장점이 있다.
|
||||
RP-04 이후 route runtime과 RP-06 page/form platform에는 다음 장점이 있다.
|
||||
|
||||
- route registry가 path와 access policy를 소유한다.
|
||||
- contract에서 Data Router route object와 navigation을 생성한다.
|
||||
@@ -22,6 +22,12 @@ RP-04 이후 현재 구현에는 다음 장점이 있다.
|
||||
- 앱 셸과 보호 route, not-found surface가 있다.
|
||||
- route heading focus와 비동기/render error boundary가 있다.
|
||||
- redirect loop와 chunk recovery가 bounded production call graph에 연결돼 있다.
|
||||
- `src/presentation/templates`가 standard/collection/detail/form/status slot,
|
||||
landmark와 responsive layout을 제공한다.
|
||||
- `src/presentation/forms`가 첫 오류 focus, error summary, 422 mapping,
|
||||
duplicate submit과 dirty route blocker를 소유한다.
|
||||
- reference feature의 list/detail/create/status route가 네 template variation을
|
||||
production composition에서 실행한다.
|
||||
|
||||
platform route 계약, `src/features/installed-feature-contracts.js`,
|
||||
`src/features/installed-feature-runtimes.tsx`의 완전성은 TypeScript와 registry
|
||||
@@ -31,9 +37,11 @@ access, title, navigation, chunk ID는
|
||||
manifest의 dynamic entry는 release manifest route chunk map과 검증되며,
|
||||
`ChunkRecoveryBoundary`는 일반 render error와 chunk rejection을 분리한다.
|
||||
|
||||
페이지도 공통 `PageHeader` 외에는 각자 section과 class를 직접 조립한다. 목록,
|
||||
상세, 편집, 오류 페이지의 반복되는 접근성·반응형·상태 표면을 기능 팀이 다시
|
||||
구현해야 한다.
|
||||
template는 데이터를 가져오지 않는다. reference page controller가 route input과
|
||||
application input을 query/form facade에 연결하고, template에는 render할 slot과
|
||||
안전한 callback만 전달한다. 이 분리는
|
||||
`page-templates-own-layout-only` dependency rule과 forbidden import fixture가
|
||||
검증한다.
|
||||
|
||||
## 3. React Router mode 결정
|
||||
|
||||
|
||||
@@ -487,8 +487,12 @@ raw response body, stack, token, URL query, PII를 사용자 copy나 일반 log
|
||||
|
||||
## 8. 폼 표준
|
||||
|
||||
form vendor는 React Hook Form 또는 TanStack Form 등을 평가하되 local facade 뒤에
|
||||
둔다. vendor 선택과 무관하게 다음 API를 제공한다.
|
||||
VD-04에 따라 현재 기본 엔진은 React native form event와 controlled value이며
|
||||
Zod를 local facade 뒤에서 사용한다. 동적 field array, 비동기 field validation,
|
||||
대규모 render isolation 요구가 실제로 생기면 public API를 유지한 채 React Hook
|
||||
Form 또는 TanStack Form adapter를 평가한다.
|
||||
|
||||
현재 public API는 다음과 같다.
|
||||
|
||||
- `Form`
|
||||
- `FormField`
|
||||
@@ -500,6 +504,18 @@ form vendor는 React Hook Form 또는 TanStack Form 등을 평가하되 local fa
|
||||
- `mapValidationFailureToFields`
|
||||
- `useDirtyNavigationGuard`
|
||||
|
||||
구현 위치:
|
||||
|
||||
- controller와 mapping: `src/presentation/forms`
|
||||
- layout-only template: `src/presentation/templates`
|
||||
- feature form schema/command mapper:
|
||||
`src/features/reference-feature/presentation/reference-resource-form.ts`
|
||||
- 실제 create page:
|
||||
`src/features/reference-feature/presentation/reference-resource-form-page.tsx`
|
||||
|
||||
`ApiFailure.validationIssues`는 HTTP 경계가 투영한 `path`와 `code`만 담는다.
|
||||
backend message와 알 수 없는 path는 field copy로 사용하지 않는다.
|
||||
|
||||
필수 동작:
|
||||
|
||||
1. label, description, error를 stable ID와 `aria-describedby`로 연결
|
||||
|
||||
Reference in New Issue
Block a user