feat: add design system platform
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
# VD-05: Semantic icon facade와 native-first interaction
|
||||
|
||||
- 상태: Accepted
|
||||
- 결정일: 2026-07-26
|
||||
- 적용 브랜치: `feature-frontend-design-system-platform`
|
||||
- 재검토: native 계약으로 충족할 수 없는 widget 요구가 확인될 때
|
||||
|
||||
## 배경
|
||||
|
||||
앱 셸과 공통 UI는 문자 glyph, raw button/select와 페이지별 focus 처리를
|
||||
사용했다. 아이콘 공급자와 복합 interaction을 제품 코드에 직접 노출하면 번들,
|
||||
접근성, vendor type과 교체 비용이 모든 feature로 전파된다. 반대로 실제 요구가
|
||||
없는 두 개의 headless vendor를 기본 설치하면 skeleton 소비자가 제거해야 할
|
||||
의존성과 중복 interaction 모델이 생긴다.
|
||||
|
||||
## 결정
|
||||
|
||||
1. 아이콘 공급자는 lockfile 최소 게시 유예를 통과한 `lucide-react@1.25.0`으로
|
||||
고정한다.
|
||||
2. `lucide-react`의 static named import는
|
||||
`design-system/icons/vendors/lucide.tsx` 한 파일에서만 허용한다.
|
||||
3. public API는 `MenuIcon`, `CloseIcon`, `WarningIcon` 같은 의미 이름만
|
||||
노출한다. vendor component type, icon name, stroke API와 dynamic icon
|
||||
registry는 노출하지 않는다.
|
||||
4. 장식 아이콘은 accessibility tree에서 제외한다. 정보를 단독 전달하는
|
||||
아이콘은 `label`, icon-only action은 필수 `accessibleName`을 사용한다.
|
||||
5. 현재 복합 control은 native `dialog`, form control, `details`와 local
|
||||
TypeScript state model로 구현한다. Menu는 roving focus/typeahead/Escape,
|
||||
Tabs는 manual/automatic activation, Drawer는 modal/background
|
||||
비활성화/focus restore 계약을 가진다.
|
||||
6. React Aria와 Radix는 기본 dependency로 추가하지 않는다. native platform이
|
||||
collision, nested overlay, virtualized collection 또는 복합 select 요구를
|
||||
충족하지 못한다는 재현 가능한 요구가 생길 때 prototype과 ADR로 다시
|
||||
평가한다.
|
||||
7. Storybook과 pinned visual baseline은 VD-08/RP-10에서 도입한다. RP-07의
|
||||
runtime gallery와 browser interaction test는 해당 workshop을 대체한다고
|
||||
주장하지 않는다.
|
||||
|
||||
## 경계와 검증
|
||||
|
||||
- 제품 코드는 `presentation/design-system/index`만 import한다.
|
||||
- design-system 검사기는 direct icon/headless import, deep import, raw palette,
|
||||
undefined token과 tooltip-only required information fixture를 거절한다.
|
||||
- type negative fixture는 accessible name 없는 `IconButton`을 거절한다.
|
||||
- component test는 decorative icon, form control, Menu, Tabs, Drawer와 Toast를
|
||||
검증한다.
|
||||
- Chromium/Firefox E2E는 compact Drawer의 native modal 상태, Escape, focus
|
||||
restore, gallery keyboard interaction과 axe를 검증한다.
|
||||
- 로컬 WebKit 실행은 host `libevent-2.1.so.7` 부재로 환경 검증이 남아 있으며
|
||||
공급자 선택이나 product behavior의 PASS로 숨기지 않는다.
|
||||
|
||||
## Rollback
|
||||
|
||||
기존 `presentation/components/ui/*` 경로는 canonical TypeScript primitive를
|
||||
재수출하므로 소비 코드를 즉시 되돌릴 수 있다. Lucide 제거 시 vendor facade와
|
||||
semantic icon 구현만 교체하고 제품 API는 유지한다. headless vendor를 나중에
|
||||
도입해도 public props와 interaction test를 유지한다.
|
||||
@@ -73,11 +73,11 @@ recovery 계약, 제거 가능한 reference 수직 슬라이스는 구현됐다.
|
||||
| 클라이언트 상태 | 부분 준비 | 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 복원 |
|
||||
| 페이지 템플릿 | 준비됨 | 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 뒤에서 사용 |
|
||||
| 앱 셸·반응형 | 준비됨 | native modal Drawer, compact/desktop layout, Escape/link dismiss와 focus restore | RP-08에서 RTL/direction 검증 |
|
||||
| 페이지 템플릿 | 준비됨 | Standard/Collection/Detail/Form/Status와 public design-system entry | feature별 slot 조합 유지 |
|
||||
| 디자인 토큰 | 준비됨 | primitive/semantic/component CSS, 48-token 자동 계약, dark/forced-colors/reduced-motion | 제품 brand token은 외부 프로젝트에서 확장 |
|
||||
| 공통 UI | 준비됨 | action/form/feedback/overlay/navigation primitive와 pattern, compatibility export | Storybook/visual은 RP-10 |
|
||||
| 아이콘 | 준비됨 | Lucide static vendor facade와 semantic icon/IconButton 접근성 계약 | 의미 icon 추가 시 bundle/접근성 기준 적용 |
|
||||
| 폼 | 준비됨 | 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 경계 |
|
||||
|
||||
@@ -588,6 +588,22 @@ RP-07은 compatibility export로 기존 primitive import를 복구할 수 있어
|
||||
token rename은 alias/migration 기간을 두고, vendor adapter와 local API commit을
|
||||
분리한다.
|
||||
|
||||
**구현 증거 (2026-07-26)**
|
||||
|
||||
- VD-05에서 `lucide-react@1.25.0` static semantic facade와 native-first
|
||||
interaction을 채택하고 headless vendor 재평가 조건을 닫았다.
|
||||
- `src/presentation/design-system`이 48개 필수 token, public TypeScript barrel,
|
||||
action/form/feedback/overlay/navigation primitive와 공통 pattern을 제공한다.
|
||||
- 기존 `components/ui` 경로는 compatibility export로 유지하고 앱 셸, gallery와
|
||||
reference feature는 public entry를 소비한다.
|
||||
- 모바일 navigation은 native modal Drawer로 전환되어 배경 비활성화, Escape,
|
||||
route dismiss와 trigger focus restore를 제공한다.
|
||||
- source/negative fixture gate가 undefined token, raw palette, direct vendor,
|
||||
deep import, tooltip-only 정보와 accessible name 누락을 거절한다.
|
||||
- component/browser test가 Menu typeahead, Tabs activation, Toast queue,
|
||||
form controls, compact reflow와 open-dialog axe를 실행한다. 로컬 WebKit은 host
|
||||
`libevent-2.1.so.7` 부재로 환경 검증 상태를 유지한다.
|
||||
|
||||
### 08. `feature-frontend-i18n-message-formatting-contract`
|
||||
|
||||
**목표**
|
||||
|
||||
@@ -171,6 +171,13 @@ query vendor import는 architecture gate가 거절한다. reference feature의
|
||||
list/detail/create/status route가 각각 Collection/Detail/Form/Status template의
|
||||
실제 consumer다.
|
||||
|
||||
RP-07에서 React inbound adapter 안의 UI 공급자 경계도 닫혔다.
|
||||
`src/presentation/design-system/index.ts`는 token → primitive → pattern →
|
||||
template public API이며 feature와 shell은 이 entry만 소비한다. Lucide는
|
||||
`icons/vendors/lucide.tsx`에 격리된 inbound vendor facade이므로 application
|
||||
port가 아니다. native Dialog/Drawer/Menu/Tabs의 focus·keyboard 상태도
|
||||
presentation이 소유하고 use case나 outbound adapter로 올리지 않는다.
|
||||
|
||||
이 문서의 목표 구조는 기존 기반을 폐기하는 것이 아니라 이러한
|
||||
불일치를 제거하는 것이다.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user