diff --git a/docs/CURRENT/CATALOGS/WBS_PROGRESS_TRACKER.csv b/docs/CURRENT/CATALOGS/WBS_PROGRESS_TRACKER.csv index 545f7b93..3e543f9a 100644 --- a/docs/CURRENT/CATALOGS/WBS_PROGRESS_TRACKER.csv +++ b/docs/CURRENT/CATALOGS/WBS_PROGRESS_TRACKER.csv @@ -42,3 +42,4 @@ PHASE-1-SHADOW-RUN,S0-S5,Cross,252+ Trading Day Shadow Run,BLOCKED,TBD,"docs/CUR V13-FE-001,S0,Cross,UI Vendor import boundary,COMPLETED,2026-08-09,"docs/CURRENT/V13-FE-001_KBX_V36_DESIGN_HARNESS_PROPOSAL.md; tools/validate_v16.py",FE Architect/QA,"Dependency AEG-X-003 is COMPLETED. KBX v36 was translated as a non-vendor design-evidence harness: preserve the shared UI adapter boundary, keep feature direct PrimeVue/AG Grid imports at zero, and defer token/recipe implementation to separately approved slices. Actual evidence: python tools/validate_v16.py exited 0 with PASS=1 WARN=2 FAIL=0 on 2026-08-09. Warnings are retained (no full source archive; approved runtime evidence absent); no runtime test/build/migration claim is made." V13-FE-003,S0,Cross,UiAdapter Port 정의,COMPLETED,2026-08-09,"docs/CURRENT/V13-FE-003_UI_ADAPTER_PORT_RECONCILIATION.md; frontend/src/shared/ui/adapter/contracts.ts; frontend/src/shared/ui/adapter/tests/uiAdapter.contract.spec.ts",FE Architect/QA,"Dependency V13-FE-001 is COMPLETED. Existing adapter v4 contract explicitly verifies 14 capabilities (stronger than the WBS minimum wording of 8) without feature vendor imports. Actual targeted Vitest evidence: 2 files / 4 tests passed, exit 0, 2026-08-09. KBX-derived components remain provider-neutral reimplementations only; no KBX package, contract, router, store, or permission host was imported." V13-FE-004,S0,Cross,PrimeVue/AG Grid Adapter 구현,COMPLETED,2026-08-09,"docs/CURRENT/V13-FE-004_ADAPTER_IMPLEMENTATION_RECONCILIATION.md; frontend/src/shared/ui/adapter/primevue; frontend/src/shared/ui/adapter/tests/uiAdapter.contract.spec.ts",FE Architect/QA,"Dependency V13-FE-003 is COMPLETED. PrimeVue/AG Grid remain confined behind adapter v4. Actual targeted Vitest evidence: 2 files / 4 tests passed, exit 0, 2026-08-09. This is contract/accessibility-attribute evidence only; no visual/AT/runtime claim is made." +V13-FE-005,S0,Cross,Ks* vendor-neutral components,COMPLETED,2026-08-09,"docs/CURRENT/V13-FE-005_KBX_FORM_COMPONENT_ADOPTION.md; frontend/src/shared/ui/components/KsFormGrid.vue; frontend/src/shared/ui/components/KsFormSection.vue; frontend/src/shared/ui/components/KsFormSpan.vue; frontend/src/shared/ui/components/KsValidationSummary.vue; frontend/src/shared/ui/components/tests/KsFormLayouts.spec.ts",FE Architect/QA,"Dependency V13-FE-004 is COMPLETED. Reimplemented only KBX presentation-only form components against existing K-ArtSell tokens; no KBX package, contracts, provider dependency, routing, permissions, or business policy imported. Actual evidence: targeted Vitest 2 files / 6 tests passed and pnpm typecheck exit 0 on 2026-08-09. Visual/AT/performance baseline remains outside this Slice." diff --git a/docs/CURRENT/V13-FE-005_KBX_FORM_COMPONENT_ADOPTION.md b/docs/CURRENT/V13-FE-005_KBX_FORM_COMPONENT_ADOPTION.md new file mode 100644 index 00000000..bdd7d141 --- /dev/null +++ b/docs/CURRENT/V13-FE-005_KBX_FORM_COMPONENT_ADOPTION.md @@ -0,0 +1,30 @@ +# V13-FE-005 — KBX 폼 컴포넌트 선별 이식 + +| 항목 | 값 | +| --- | --- | +| Requirement / API / DB / Job / UI / Test | REQ-FE-COMP / Cross / Cross / Cross / UI-FOUND-05 / T-FE-COMP-01 | +| Dependency / Gate | V13-FE-004 (COMPLETED) / G0 | +| Artifact | `frontend/src/shared/ui/components/KsForm*.vue`, `KsValidationSummary.vue` | +| 목적 | provider-neutral form layout과 validation presentation 표준화 | + +## Source / Assumption / Unknown / Decision Required + +- **Source:** KBX v36의 `KbxFormGrid`, `KbxFormSection`, `KbxFormSpan`, `KbxValidationSummary`는 Vue/CSS presentation-only 구성이다. +- **Assumption:** K-ArtSell token (`--ks-*`)과 기존 `FieldShell`/Zod 경계를 유지하면 같은 layout pattern을 안전하게 재구현할 수 있다. +- **Unknown:** 각 feature의 오류를 어느 field로 focus할지와 visual/AT baseline은 화면별 evidence가 필요하다. +- **Decision Required:** 오류 클릭 시 field focus/navigation, density variant, 새로운 token은 실제 3회 이상 반복 및 ADR/QA 기준 승인 후에만 추가한다. + +## 구현 경계 + +- `KsFormGrid`, `KsFormSection`, `KsFormSpan`, `KsValidationSummary`만 추가했다. +- KBX package, `@kbx/contracts`, provider peer dependency, router, store, permission host, 업무 규칙을 복사하지 않았다. +- validation summary는 오류를 숨기기 위한 임의 최대 개수를 두지 않고 전달받은 오류를 모두 표시한다. +- 색상/spacing은 기존 semantic token만 사용한다. + +## 실제 증거 + +- `pnpm vitest run src/shared/ui/components/tests/KsFormLayouts.spec.ts src/shared/ui/components/tests/accessibility.contract.spec.ts`: 2 files / 6 tests passed, exit 0. +- `pnpm typecheck`: exit 0. +- 실행일: 2026-08-09. + +위 증거는 component contract/typecheck에 한정된다. browser visual, AT, performance, server/API/DB/migration 통과는 주장하지 않는다. diff --git a/frontend/src/shared/ui/components/KsFormGrid.vue b/frontend/src/shared/ui/components/KsFormGrid.vue new file mode 100644 index 00000000..231ddbb0 --- /dev/null +++ b/frontend/src/shared/ui/components/KsFormGrid.vue @@ -0,0 +1,16 @@ + + + + + diff --git a/frontend/src/shared/ui/components/KsFormSection.vue b/frontend/src/shared/ui/components/KsFormSection.vue new file mode 100644 index 00000000..b23d2662 --- /dev/null +++ b/frontend/src/shared/ui/components/KsFormSection.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/frontend/src/shared/ui/components/KsFormSpan.vue b/frontend/src/shared/ui/components/KsFormSpan.vue new file mode 100644 index 00000000..775557a8 --- /dev/null +++ b/frontend/src/shared/ui/components/KsFormSpan.vue @@ -0,0 +1,10 @@ + + + + + diff --git a/frontend/src/shared/ui/components/KsValidationSummary.vue b/frontend/src/shared/ui/components/KsValidationSummary.vue new file mode 100644 index 00000000..8457ea7d --- /dev/null +++ b/frontend/src/shared/ui/components/KsValidationSummary.vue @@ -0,0 +1,16 @@ + + + + + diff --git a/frontend/src/shared/ui/components/index.ts b/frontend/src/shared/ui/components/index.ts index c10745f8..a305737e 100644 --- a/frontend/src/shared/ui/components/index.ts +++ b/frontend/src/shared/ui/components/index.ts @@ -15,3 +15,7 @@ export { default as KsDataGrid } from './KsDataGrid.vue' export { default as FieldShell } from './FieldShell.vue' export { default as KsDataContextHeader } from './KsDataContextHeader.vue' export { default as KsCommandBar } from './KsCommandBar.vue' +export { default as KsFormGrid } from './KsFormGrid.vue' +export { default as KsFormSection } from './KsFormSection.vue' +export { default as KsFormSpan } from './KsFormSpan.vue' +export { default as KsValidationSummary } from './KsValidationSummary.vue' diff --git a/frontend/src/shared/ui/components/tests/KsFormLayouts.spec.ts b/frontend/src/shared/ui/components/tests/KsFormLayouts.spec.ts new file mode 100644 index 00000000..8ae96fba --- /dev/null +++ b/frontend/src/shared/ui/components/tests/KsFormLayouts.spec.ts @@ -0,0 +1,31 @@ +import { mount } from '@vue/test-utils' +import { describe, expect, it } from 'vitest' +import KsFormGrid from '../KsFormGrid.vue' +import KsFormSection from '../KsFormSection.vue' +import KsFormSpan from '../KsFormSpan.vue' +import KsValidationSummary from '../KsValidationSummary.vue' + +describe('KBX-derived vendor-neutral form components', () => { + it('keeps grid semantics and collapses its layout by tokenized CSS', () => { + const wrapper = mount(KsFormGrid, { props: { columns: 2, ariaLabel: '고객 정보' }, slots: { default: '' } }) + expect(wrapper.attributes('role')).toBe('group') + expect(wrapper.attributes('aria-label')).toBe('고객 정보') + expect(wrapper.attributes('data-columns')).toBe('2') + }) + + it('allows a field to span the full form row', () => { + expect(mount(KsFormSpan, { props: { span: 'full' } }).attributes('data-span')).toBe('full') + }) + + it('provides an explicit heading and optional actions without a provider dependency', () => { + const wrapper = mount(KsFormSection, { props: { title: '주문 조건', labelledBy: 'order-condition' }, slots: { actions: '' } }) + expect(wrapper.find('h2').attributes('id')).toBe('order-condition') + expect(wrapper.get('button').text()).toBe('초기화') + }) + + it('announces every supplied validation error', () => { + const wrapper = mount(KsValidationSummary, { props: { errors: [{ field: 'amount', message: '금액을 입력하세요.' }, { field: 'date', message: '일자를 확인하세요.' }] } }) + expect(wrapper.attributes('role')).toBe('alert') + expect(wrapper.findAll('li')).toHaveLength(2) + }) +})