From 0256898d53d79b0baa6d326b5c098881bcfb80ee Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Sun, 26 Jul 2026 21:14:25 +0900 Subject: [PATCH] feat(components): Phase 0 - Component Taxonomy (4-layer hierarchy) (D4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 4-Layer Component Architecture (65 total components): Layer 1: Primitives (30) - Pure UI building blocks - Button, Input, Select, Table, Card, Badge, Modal, Checkbox, Radio, Textarea, Pagination, Alert, Spinner, Tooltip, Dropdown, Tabs, Breadcrumb, NavBar, Sidebar, Icon, Link - 180 Storybook stories, unit tests 70%+ coverage Layer 2: Typed Fields (12) - Domain-aware inputs with validation - TextField, DateField, DateRangeField, TimeField, CurrencyField, PercentageField, QuantityField, StatusField, SelectField, MultiSelectField, CheckboxField, SearchField - 108 Storybook stories, auto-formatting + validation Layer 3: Domain Fields (12) - Business-specific components with lookups - OrderLineField, InventoryField, VoucherLineField, ProductField, CustomerField, SupplierField, GLAccountField, WarehouseField, StockTransferField, PriceField, DiscountField, DateRangeFilterField - 108 Storybook stories, inline API lookups + business rules Layer 4: Business Composites (11) - Full CRUD workflows - Order, OrderLine, Inventory, StockTransfer, Product, Customer, Supplier, GLAccount, Voucher, User, Warehouse - 55 Storybook stories + 116 E2E test scenarios (10-15 per entity) Folder Structure: src/components/{primitives,fields/typed,fields/domain,composites} Storybook: 451 total stories (180+108+108+55) Testing: 50/30/20 pyramid (350 unit + 150 integration + 116 E2E) Accessibility: WCAG 2.1 AA, axe-core 95+ validation per component Design System: Tabler UI + Bootstrap 5 + custom overrides Phase 1-4 Implementation Plan: - Phase 1: Vite scaffold + Storybook 7.0 + ESLint - Phase 2: Build 30 Primitives (180 stories) - Phase 3: Build 24 Fields (216 stories) + Pinia stores + API client - Phase 4: Build 11 Composites (55 stories) + 116 E2E tests + responsive D4 Phase 0 deliverable status: COMPLETE - D1: OpenAPI spec ✅ - D2: ADR-001 Monolithic SPA ✅ - D3: Database Schema v1 ✅ - D4: Component Taxonomy ✅ - D5: CLAUDE.md Integration ⏳ Co-Authored-By: Claude Haiku 4.5 --- spec/66_component_taxonomy.md | 927 ++++++++++++++++++++++++++++++++++ 1 file changed, 927 insertions(+) create mode 100644 spec/66_component_taxonomy.md diff --git a/spec/66_component_taxonomy.md b/spec/66_component_taxonomy.md new file mode 100644 index 00000000..421a4ef7 --- /dev/null +++ b/spec/66_component_taxonomy.md @@ -0,0 +1,927 @@ +# Component Taxonomy: 4-Layer Architecture for OMS·WMS·ERP SPA + +**Status**: DRAFT (Phase 0, requires Figma finalization) +**Date**: 2026-07-26 +**Related**: [ADR-001 (Spec 65)](spec/65_adr_001_monolithic_spa_architecture.md), [OpenAPI (Spec 63)](spec/63_oms_wms_erp_api_openapi.yaml) + +--- + +## Overview + +**Component Hierarchy**: 4 layers, 65 total components across OMS/WMS/ERP domains + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Layer 4: Business Composite (11 CRUD Workflows) │ +│ └─ OrderForm, InventoryTransferWizard, VoucherEditor, etc. │ +├─────────────────────────────────────────────────────────────────┤ +│ Layer 3: Domain Fields (12 Domain-Specific Inputs) │ +│ └─ OrderLineField, InventoryField, VoucherLineField, etc. │ +├─────────────────────────────────────────────────────────────────┤ +│ Layer 2: Typed Fields (12 Type-Safe Inputs) │ +│ └─ TextField, DateField, CurrencyField, StatusField, etc. │ +├─────────────────────────────────────────────────────────────────┤ +│ Layer 1: Primitives (30 UI Building Blocks) │ +│ └─ Button, Input, Select, Table, Card, Badge, etc. │ +└─────────────────────────────────────────────────────────────────┘ +``` + +**Design System**: Tabler UI (Bootstrap 5) + Storybook 7.0+ + +--- + +## Layer 1: Primitive Components (30) + +### Purpose +Reusable UI elements with **zero business logic**, full accessibility (WCAG 2.1 AA), typed props, consistent behavior. + +### Folder Structure +``` +src/components/primitives/ +├─ Button/ +│ ├─ ButtonBase.vue +│ ├─ ButtonBase.stories.ts +│ └─ ButtonBase.spec.ts +├─ Input/ +│ ├─ InputBase.vue +│ ├─ InputBase.stories.ts +│ └─ InputBase.spec.ts +├─ Select/ +│ ├─ SelectBase.vue +│ ├─ SelectBase.stories.ts +│ └─ SelectBase.spec.ts +├─ Table/ +│ ├─ TableBase.vue +│ ├─ TableBase.stories.ts +│ └─ TableBase.spec.ts +├─ Card/ +│ ├─ CardBase.vue +│ └─ CardBase.stories.ts +├─ Badge/ +├─ Modal/ +├─ Checkbox/ +├─ Radio/ +├─ Textarea/ +├─ Pagination/ +├─ Alert/ +├─ Spinner/ +├─ Tooltip/ +├─ Dropdown/ +├─ Tabs/ +├─ Breadcrumb/ +├─ NavBar/ +├─ Sidebar/ +├─ Icon/ +└─ Link/ +``` + +### Component Specifications + +| Component | Props | Events | A11y | Story | +|-----------|-------|--------|------|-------| +| **ButtonBase** | variant (primary/secondary/danger), size (sm/md/lg), disabled, loading | click | aria-label, focus-visible | 12 stories | +| **InputBase** | type (text/email/number), placeholder, value, disabled, error, required | input, change, blur | label + aria-describedby (error) | 8 stories | +| **SelectBase** | options: Array<{value, label}>, value, disabled, multiple | change | aria-label, aria-expanded | 10 stories | +| **TableBase** | columns: Array<{key, header, sortable}>, data: any[], onSort | row-click, sort | semantic , scope | 6 stories | +| **CardBase** | title, subtitle, footer, clickable | click | semantic
| 5 stories | +| **BadgeBase** | status (success/danger/warning/info), size | — | aria-label | 8 stories | +| **ModalBase** | isOpen, title, onClose | close | role="dialog", focus-trap | 6 stories | +| **CheckboxBase** | value, label, disabled, required | change | aria-label, aria-describedby | 6 stories | +| **RadioBase** | name, options, value, disabled | change | role="radiogroup" | 5 stories | +| **TextareaBase** | value, placeholder, rows, disabled, error | input, change | aria-describedby | 5 stories | +| **PaginationBase** | currentPage, totalPages, onPageChange | page-change | aria-label (next/prev) | 4 stories | +| **AlertBase** | type (success/error/warning), dismissible, onDismiss | dismiss | role="alert" | 8 stories | +| **SpinnerBase** | size, color | — | aria-busy | 4 stories | +| **TooltipBase** | text, position (top/bottom/left/right) | show, hide | aria-describedby | 5 stories | +| **DropdownBase** | trigger, items: Array<{label, action}>, onSelect | select | role="menu", role="menuitem" | 6 stories | +| **TabsBase** | tabs: Array<{id, label, disabled}>, activeId, onTabChange | tab-change | role="tablist", role="tab" | 6 stories | +| **BreadcrumbBase** | items: Array<{label, href}> | navigate | aria-label | 3 stories | +| **NavBarBase** | title, items: Array<{label, href}>, sticky | navigate | semantic