feat: compose T01 search list workspace (V13-FE-011)

This commit is contained in:
2026-08-09 02:39:24 +09:00
parent eb59cae8e3
commit 58e8b02d33
5 changed files with 109 additions and 2 deletions
@@ -51,3 +51,4 @@ V13-FE-003,S0,Cross,UiAdapter Port 정의,COMPLETED,2026-08-09,"docs/CURRENT/V13
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."
V13-FE-006,S0,Cross,AppShell/Page layouts,COMPLETED,2026-08-09,"docs/CURRENT/V13-FE-006_LAYOUT_CONTRACT_RECONCILIATION.md; frontend/src/shared/ui/layouts/tests/layout.contract.spec.ts; frontend/src/shared/ui/layouts/AppShellLayout.vue; frontend/src/shared/ui/layouts/PageLayout.vue",UX/FE/QA/Security,"Dependency V13-FE-005 is COMPLETED. Preserved the existing slot-based layout rather than importing KBX's coupled workspace shell. Actual DOM contract evidence: 1 file / 2 tests passed, exit 0, 2026-08-09; verifies skip navigation, structural landmarks, default automation OFF boundary, and evidence/aside/footer separation. No visual/AT/E2E claim is made."
V13-FE-011,S6,Cross,T01 검색목록 화면 템플릿,IN_PROGRESS,TBD,"docs/CURRENT/V13-FE-011_T01_SEARCH_LIST_LAYOUT_SLICE_NOTE.md; frontend/src/shared/ui/screen-types/v2/SearchListCrudPage.vue; frontend/src/shared/ui/screen-types/tests/SearchListCrudPage.spec.ts; evidence/V13-FE-011/t01-search-list-layout_20260809.log",UX/FE,"2026-08-09: Scope limited to adapter-neutral T01 composition: list body plus optional detail region through CrudWorkspaceLayout. Actual execution evidence: targeted Vitest 1 file / 2 tests passed; pnpm typecheck passed. Dependency V13-FE-006 is completed. MVP-A Gate passage, visual/assistive-technology approval, and Playwright evidence are not claimed."
1 WBS_ID Sprint Slice_ID Task Status Completion_Date Evidence_Link Owner Notes
51 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.
52 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.
53 V13-FE-006 S0 Cross AppShell/Page layouts COMPLETED 2026-08-09 docs/CURRENT/V13-FE-006_LAYOUT_CONTRACT_RECONCILIATION.md; frontend/src/shared/ui/layouts/tests/layout.contract.spec.ts; frontend/src/shared/ui/layouts/AppShellLayout.vue; frontend/src/shared/ui/layouts/PageLayout.vue UX/FE/QA/Security Dependency V13-FE-005 is COMPLETED. Preserved the existing slot-based layout rather than importing KBX's coupled workspace shell. Actual DOM contract evidence: 1 file / 2 tests passed, exit 0, 2026-08-09; verifies skip navigation, structural landmarks, default automation OFF boundary, and evidence/aside/footer separation. No visual/AT/E2E claim is made.
54 V13-FE-011 S6 Cross T01 검색목록 화면 템플릿 IN_PROGRESS TBD docs/CURRENT/V13-FE-011_T01_SEARCH_LIST_LAYOUT_SLICE_NOTE.md; frontend/src/shared/ui/screen-types/v2/SearchListCrudPage.vue; frontend/src/shared/ui/screen-types/tests/SearchListCrudPage.spec.ts; evidence/V13-FE-011/t01-search-list-layout_20260809.log UX/FE 2026-08-09: Scope limited to adapter-neutral T01 composition: list body plus optional detail region through CrudWorkspaceLayout. Actual execution evidence: targeted Vitest 1 file / 2 tests passed; pnpm typecheck passed. Dependency V13-FE-006 is completed. MVP-A Gate passage, visual/assistive-technology approval, and Playwright evidence are not claimed.
@@ -0,0 +1,31 @@
# V13-FE-011 — T01 Search/List layout composition
| Item | Value |
| --- | --- |
| Requirement / API / DB / Job / UI / Test | REQ-FE-T01 / Cross / Cross / Cross / UI-T01 / T-FE-T01-01 |
| Dependency | V13-FE-006 — completed in `WBS_PROGRESS_TRACKER.csv` |
| Gate | MVP-A — implementation evidence only; Gate passage is not claimed |
| Artifact | `SearchListCrudPage.vue`; component contract test |
## Source / Assumption / Unknown / Decision Required
- **Source:** `DEC-046` approves T01~T10 standard screen types. `FE_COMPONENT.csv` defines T01 as a list screen composed from shared layouts. `UiStandardPage.vue` is the current T01 consumer.
- **Assumption:** T01 needs one responsive workspace boundary for its list body and optional detail region; `CrudWorkspaceLayout` already provides that adapter-neutral responsibility.
- **Unknown:** MVP-A Gate passage and visual/assistive-technology approval evidence are not present in the tracker.
- **Decision Required:** UX/QA approval is required before marking this WBS item completed at MVP-A.
## Scope
- Compose the existing T01 screen type with `CrudWorkspaceLayout`.
- Preserve named slots and `StandardScreenBoundary` state handling.
- Add a focused DOM contract test for the main/detail layout relationship.
## Out of scope
- Feature-page migration, new provider capabilities, API/data changes, visual approval, and Playwright evidence.
## Actual execution evidence
- `pnpm test -- --run src/shared/ui/screen-types/tests/SearchListCrudPage.spec.ts` — 1 file / 2 tests passed, exit 0.
- `pnpm typecheck``vue-tsc --noEmit`, exit 0.
- Preserved output: `evidence/V13-FE-011/t01-search-list-layout_20260809.log`.
@@ -0,0 +1,20 @@
WBS_ID: V13-FE-011
Date: 2026-08-09 (Asia/Seoul)
Command:
pnpm test -- --run src/shared/ui/screen-types/tests/SearchListCrudPage.spec.ts
Result:
Test Files 1 passed (1)
Tests 2 passed (2)
Exit code 0
Command:
pnpm typecheck
Result:
vue-tsc --noEmit
Exit code 0
Scope note:
This is component-layout contract and TypeScript evidence only. It does not claim MVP-A, visual, assistive-technology, performance, or Playwright acceptance.
@@ -0,0 +1,33 @@
import { mount } from '@vue/test-utils'
import { describe, expect, it } from 'vitest'
import SearchListCrudPage from '../v2/SearchListCrudPage.vue'
describe('SearchListCrudPage', () => {
it('keeps the T01 list body and optional detail in the shared responsive workspace', () => {
const wrapper = mount(SearchListCrudPage, {
props: {
title: '고객 목록',
state: 'READY',
evidence: { asOf: '2026-08-09T00:00:00Z', version: 'v1' }
},
slots: {
default: '<section data-test="list">목록</section>',
detail: '<section data-test="detail">상세</section>'
}
})
expect(wrapper.get('.ks-crud-workspace__body').classes()).toContain('has-aside')
expect(wrapper.get('main [data-test="list"]').text()).toBe('목록')
expect(wrapper.get('aside [data-test="detail"]').text()).toBe('상세')
})
it('does not render an empty detail region when the T01 caller has no selection', () => {
const wrapper = mount(SearchListCrudPage, {
props: { title: '고객 목록', state: 'READY' },
slots: { default: '<section>목록</section>' }
})
expect(wrapper.find('.ks-crud-workspace__body').classes()).not.toContain('has-aside')
expect(wrapper.find('.ks-crud-workspace aside').exists()).toBe(false)
})
})
@@ -1,2 +1,24 @@
<script setup lang="ts">import PageLayout from '../../layouts/PageLayout.vue'; import StandardScreenBoundary from './StandardScreenBoundary.vue'; import type { StandardScreenProps } from '../../contracts/screenContract'; const props=defineProps<StandardScreenProps>(); defineEmits<{retry:[]}>()</script>
<template><PageLayout :title="props.title" :subtitle="props.subtitle" :status="props.state" :as-of="props.evidence?.asOf" :version="props.evidence?.version"><template #actions><slot name="actions"/></template><template #summary><slot name="summary"/></template><template #filters><slot name="filters"/></template><StandardScreenBoundary :state="props.state" :warning="props.warning" :stale-at="props.evidence?.asOf" @retry="$emit('retry')"><slot/></StandardScreenBoundary><template v-if="$slots.detail" #aside><slot name="detail"/></template><template v-if="$slots.footer" #footer><slot name="footer"/></template></PageLayout></template>
<script setup lang="ts">
import PageLayout from '../../layouts/PageLayout.vue'
import CrudWorkspaceLayout from '../../layouts/CrudWorkspaceLayout.vue'
import StandardScreenBoundary from './StandardScreenBoundary.vue'
import type { StandardScreenProps } from '../../contracts/screenContract'
const props = defineProps<StandardScreenProps>()
defineEmits<{ retry: [] }>()
</script>
<template>
<PageLayout :title="props.title" :subtitle="props.subtitle" :status="props.state" :as-of="props.evidence?.asOf" :version="props.evidence?.version">
<template #actions><slot name="actions" /></template>
<template #summary><slot name="summary" /></template>
<template #filters><slot name="filters" /></template>
<StandardScreenBoundary :state="props.state" :warning="props.warning" :stale-at="props.evidence?.asOf" @retry="$emit('retry')">
<CrudWorkspaceLayout>
<slot />
<template v-if="$slots.detail" #aside><slot name="detail" /></template>
</CrudWorkspaceLayout>
</StandardScreenBoundary>
<template v-if="$slots.footer" #footer><slot name="footer" /></template>
</PageLayout>
</template>