# Phase 3 Step 2: Smart Components Layer (Domain Fields) **Status**: 🚀 START **Phase**: 3 / 11 **Step**: 2 / 4 **Target Completion**: 2026-09-02 (4 days) **Overall Phase 3**: 2 weeks (2026-08-27 to 2026-09-10) --- ## Overview **Phase 3 Step 2 Goal**: Build Smart Components layer (Domain Fields) **What are Domain Fields?** - Composed from Typed Fields + business logic - Add API lookups (customer list, product catalog, etc.) - Implement domain-specific validation rules - Enable complex workflows (multi-field coordination) - Example: OrderLineField = Qty (NumberField) + Product (lookup) + Price (auto-calculated) **Architecture Transition**: ``` Layer 1: Primitives (Button, Input, Table) ↓ (composed into) Layer 2: Typed Fields (TextField, NumberField, DateField) ↓ (composed into) Layer 3: Domain Fields ← WE ARE HERE (OrderLineField, CustomerField) ↓ (composed into) Layer 4: Business Composites (OrderForm, InventoryTransfer) ``` **After Step 2**: Full Domain Fields layer ready for Composite components --- ## The 12 Domain Fields ### 1. **OrderLineField** — Order line item (qty + product + price) ```vue ``` **Features**: - Product lookup (async) - Quantity validation (available stock) - Auto-fill unit price from product - Auto-calculate line total - Emit coordinated updates --- ### 2. **CustomerField** — Customer lookup with details ```vue ⚠️ Customer approaching credit limit: {{ creditUsage }}% ``` **Features**: - Async customer search - Auto-load customer details - Display contact info - Credit limit warning - Emit coordinated data --- ### 3. **ProductField** — Product lookup with details ```vue ``` **Features**: - SKU-based lookup - Auto-load product details - Display category, price, stock - Validation (product exists) --- ### 4. **WarehouseField** — Warehouse selection with capacity ```vue {{ capacityPercent }}% ``` **Features**: - Warehouse selection - Display location, capacity - Capacity usage visualization - Color-coded status --- ### 5. **SupplierField** — Supplier lookup ```vue ``` ### 6. **StockTransferField** — From/To warehouse transfer ```vue ``` ### 7. **DateRangeField** — Start + End date pair ```vue ``` ### 8. **AddressField** — Full address with country ```vue ``` ### 9. **BankAccountField** — Account + Bank code ```vue ``` ### 10. **TaxIDField** — Country-specific tax ID ```vue ``` ### 11. **RoleField** — User role with permissions ```vue ``` ### 12. **ApprovalField** — Approval with comments ```vue ``` --- ## Implementation Strategy ### Step 2.1: Core Domain Fields (2 days) Implement 3 "must-have" fields: 1. **OrderLineField** — Most complex, demonstrates patterns 2. **CustomerField** — Async search pattern 3. **ProductField** — SKU lookup pattern ### Step 2.2: Supporting Domain Fields (1 day) 4. **WarehouseField** — Selection + info display 5. **DateRangeField** — Date pair validation 6. **AddressField** — Multi-field composite ### Step 2.3: Specialized Domain Fields (1 day) 7-12. Remaining 6 fields (simpler patterns) --- ## API Integration Pattern **For each Domain Field**: 1. **Define API endpoint** (in MockServiceWorker) ```typescript // tests/mocks/handlers.ts http.get('*/api/products/search', async ({request}) => { const url = new URL(request.url) const query = url.searchParams.get('q') return HttpResponse.json(searchResults) }) ``` 2. **Create API client method** ```typescript // src/services/api/client.ts class ProductsApiClient extends ApiClient { async searchProducts(query: string) { return this.get('/products/search', { params: { q: query } }) } } ``` 3. **Use in Domain Field** ```typescript // src/components/fields/domain/ProductField/ProductField.vue import { productsApi } from '@/services/api/client' const handleSkuChange = async (sku: string) => { const product = await productsApi.getProductBySku(sku) // ... } ``` --- ## Component Structure **Each Domain Field** (3 files): ``` src/components/fields/domain/OrderLineField/ ├── OrderLineField.vue (component implementation) ├── OrderLineField.stories.ts (5+ Storybook stories) └── OrderLineField.spec.ts (10+ integration tests) ``` **Folder structure**: ``` src/components/fields/ ├── primitives/ (30 components - Phase 1) ✅ ├── typed/ (12 components - Phase 2+3.1) ✅ └── domain/ (12 components - Phase 3.2) ← START HERE ├── OrderLineField/ ├── CustomerField/ ├── ProductField/ ├── WarehouseField/ ├── SupplierField/ ├── StockTransferField/ ├── DateRangeField/ ├── AddressField/ ├── BankAccountField/ ├── TaxIDField/ ├── RoleField/ ├── ApprovalField/ └── index.ts (central export) ``` --- ## State Management Pattern **For Domain Fields with complex state**: Use Pinia store module or local state? **Recommended**: Local state (with emit pattern) for Step 2 - Keep fields composable - Avoid store bloat - Parent form manages state via Pinia **Example**: ```typescript // OrderLineField (local state) const line = ref({...modelValue}) watch(() => line.value, () => { emit('update:modelValue', line.value) }, { deep: true }) // Parent OrderForm (Pinia store) const lineStore = useOrderLinesStore() // Pinia store ``` --- ## Testing Strategy ### Unit Tests (Per Field: 15-20 tests) ```typescript // OrderLineField.spec.ts example describe('OrderLineField', () => { it('loads product details on SKU change') it('validates quantity against available stock') it('calculates line total correctly') it('emits update:modelValue on changes') it('handles product not found error') it('disables fields when loading') it('shows loading spinner during API call') }) ``` ### Integration Tests (New) ```typescript // tests/integration/domain-fields.spec.ts describe('Domain Fields with API', () => { it('OrderLineField full workflow (search → select → calculate)') it('CustomerField async search + credit check') it('ProductField SKU lookup + stock validation') }) ``` ### Storybook Stories (Per Field: 5+ stories) ```typescript // OrderLineField.stories.ts export const Default = {...} export const WithProductLookup = {...} export const WithValidationError = {...} export const Loading = {...} export const Disabled = {...} ``` --- ## API Requirements **New API endpoints needed** (for MSW mocking): ``` Products: GET /api/products/search?q={query} GET /api/products/{id} GET /api/products/sku/{sku} Customers: GET /api/customers/search?q={query} GET /api/customers/{id} POST /api/customers/{id}/credit-check Warehouses: GET /api/warehouses GET /api/warehouses/{id} Suppliers: GET /api/suppliers/search?q={query} GET /api/suppliers/{id} Orders: GET /api/orders/{id}/lines POST /api/orders/{id}/lines (line validation) ``` **Update MSW handlers** (tests/mocks/handlers.ts): - [ ] Product search endpoint - [ ] Product by SKU endpoint - [ ] Customer search endpoint - [ ] Customer credit check endpoint - [ ] Warehouse list/get endpoints - [ ] Supplier search endpoint --- ## Exit Criteria (Step 2 Complete) - ✅ 12 Domain Fields implemented - ✅ 60+ Storybook stories created - ✅ 150+ integration tests passing - ✅ API endpoints mocked (MSW) - ✅ All async patterns tested - ✅ Error handling verified - ✅ Loading states implemented - ✅ TypeScript strict: 0 errors - ✅ WCAG accessibility compliance --- ## Timeline | Task | Duration | Status | |------|----------|--------| | OrderLineField | 6 hours | ⏳ Start | | CustomerField | 4 hours | ⏳ After OrderLineField | | ProductField | 4 hours | ⏳ After CustomerField | | WarehouseField | 3 hours | ⏳ Parallel | | DateRangeField | 2 hours | ⏳ Parallel | | AddressField | 3 hours | ⏳ Parallel | | Remaining 6 fields | 6 hours | ⏳ Day 2 | | Testing + Storybook | 4 hours | ⏳ Day 3 | | **Total** | **~32 hours / 4 days** | ⏳ 2026-08-28 → 2026-09-02 | --- ## Quality Checklist (Per Field) - [ ] Component renders correctly - [ ] Props are typed (no `any`) - [ ] Emits work (update:modelValue) - [ ] API calls mocked (MSW) - [ ] Loading state shows spinner - [ ] Error state shows message - [ ] Validation rules enforced - [ ] Accessible (labels, ARIA, keyboard) - [ ] 5+ Storybook stories - [ ] 15+ integration tests - [ ] TypeScript strict: 0 errors - [ ] No console warnings --- ## Known Patterns to Implement ### 1. **Async Search** ```typescript const searchQuery = ref('') const searchResults = ref([]) const isSearching = ref(false) const handleSearch = async (query: string) => { isSearching.value = true searchResults.value = await api.search(query) isSearching.value = false } ``` ### 2. **Auto-fill Details** ```typescript const handleSelect = async (id: string) => { const details = await api.getDetails(id) Object.assign(model, details) emit('update:modelValue', model) } ``` ### 3. **Multi-field Validation** ```typescript const validateLineTotal = () => { if (line.quantity * line.unitPrice !== line.lineTotal) { error.value = 'Line total mismatch' } } ``` ### 4. **Loading State** ```typescript const isLoading = ref(false) const handleAsyncAction = async () => { isLoading.value = true try { // async work } finally { isLoading.value = false } } ``` --- ## Next Phase (After Step 2) **Phase 3 Step 3**: Complete remaining Pinia stores (7/10 stores) - Customers, Suppliers, StockTransfers, etc. - Integration with Domain Fields **Phase 3 Step 4**: Business Composite Components (11 components) - OrderForm (uses OrderLineField, CustomerField, etc.) - InventoryTransfer, VoucherEditor, etc. --- ## Files to Create ``` Phase 3 Step 2 Deliverables: src/components/fields/domain/ ├── index.ts (12 field exports) ├── OrderLineField/ │ ├── OrderLineField.vue │ ├── OrderLineField.stories.ts │ └── OrderLineField.spec.ts ├── CustomerField/ ├── ProductField/ ├── WarehouseField/ ├── SupplierField/ ├── StockTransferField/ ├── DateRangeField/ ├── AddressField/ ├── BankAccountField/ ├── TaxIDField/ ├── RoleField/ └── ApprovalField/ tests/mocks/ └── handlers.ts (UPDATED: new API endpoints) tests/integration/ └── domain-fields.spec.ts (NEW: 150+ tests) Documentation/ └── PHASE3-STEP2-COMPLETION.md ``` --- **Ready to implement Phase 3 Step 2?** ✅ Starting with **OrderLineField** (most complex, demonstrates patterns) Estimated time: 4 days → 2026-09-02 **Proceed with OrderLineField implementation?** ✅ Yes