# Phase 2 Roadmap: Typed Fields & Pinia Stores **Duration**: Week 3-4 (2026-08-12 → 2026-08-26) **Goal**: Build Layer 2 (Typed Fields) + State Management (Pinia) --- ## Phase 2 Structure ### Step 1: Typed Fields (Layer 2) — Week 3 - 12 Typed Field components - Validation & Formatting utilities - 100+ Storybook stories - 70+ integration tests ### Step 2: Pinia Stores — Week 4 - 10 store modules (orders, inventory, products, etc.) - API client setup - Mock Service Worker (MSW) - State management patterns ### Step 3: API Integration — Week 4 - OpenAPI SDK auto-generation - API client wrapper - Error handling middleware - Request/response interceptors ### Step 4: Integration Testing — Week 4 - Form validation chains - API mock testing (MSW) - State mutation testing - E2E test scenarios (50+) --- ## Phase 2 Step 1: Typed Fields (Week 3) ### Completed (5/12) ✅ 1. **TextField** — Text inputs with validation - Types: text, email, password, url, tel - File: src/components/fields/typed/TextField/ - Stories: 8+ - Tests: 5+ 2. **DateField** — Date picker - Format: YYYY-MM-DD (ISO) - Min/Max validation - File: src/components/fields/typed/DateField/ - Stories: 8+ - Tests: 5+ 3. **CurrencyField** — Amount input with formatting - Locale: Korean (₩) - Decimals: configurable - File: src/components/fields/typed/CurrencyField/ - Stories: 10+ - Tests: 5+ 4. **SelectField** — Dropdown with validation - Options: typed array - Searchable: ready - File: src/components/fields/typed/SelectField/ - Stories: 8+ - Tests: 5+ 5. **StatusField** — Predefined status selector - Statuses: DRAFT, PENDING, APPROVED, ACTIVE, COMPLETED, CANCELLED, FAILED - Colors: status-based badges - File: src/components/fields/typed/StatusField/ - Stories: 8+ - Tests: 5+ ### Templates (7/12) — Ready to Implement 6. TimeField (time picker, HH:mm) 7. PercentageField (0-100%, formatted) 8. QuantityField (positive integers) 9. MultiSelectField (array of values) 10. CheckboxField (boolean) 11. SearchField (autocomplete with API) 12. PhoneField (formatted phone) ### Shared Utilities ✅ **useValidation.ts** — Validation composable ```typescript - required, email, minLength, maxLength - min, max, pattern, numeric - positiveInteger, percentage, url - Chainable: validator.validate(value, [rule1, rule2]) ``` **useFormatting.ts** — Formatting composable ```typescript - formatCurrency, parseCurrency - formatDate, parseDate, formatTime, parseTime - formatPhone, parsePhone - formatNumber, truncate, capitalize ``` ### Testing (Phase 2 Step 1) **Unit Tests**: 5-8 per field × 12 = 60-96 tests - Props validation - Event emissions - Error handling - Formatting/parsing **Storybook**: 8-12 stories per field × 12 = 96-144 stories - Default state - Disabled state - With error - With help text - With validation - Edge cases **Target**: All stories render, all tests PASS by 2026-08-19 --- ## Phase 2 Step 2: Pinia Stores (Week 4) ### 10 Store Modules ``` src/stores/modules/ ├── orders.ts (OMS: Order management) ├── inventory.ts (WMS: Stock levels) ├── products.ts (ERP: Product master) ├── customers.ts (OMS: Customer master) ├── suppliers.ts (ERP: Supplier master) ├── stockTransfers.ts (WMS: Stock movements) ├── glAccounts.ts (ERP: GL accounting) ├── vouchers.ts (ERP: Journal entries) ├── users.ts (Admin: User management) └── warehouses.ts (WMS: Warehouse master) ``` ### Store Structure (Composition API) ```typescript // Each store follows this pattern: export const useOrderStore = defineStore('orders', () => { // State const orders = ref([]) const selectedOrder = ref(null) const loading = ref(false) const error = ref(null) const filters = ref({...}) // Computed const orderCount = computed(() => orders.value.length) const filteredOrders = computed(() => {...}) const totalAmount = computed(() => {...}) // Actions (async) const fetchOrders = async () => {...} const createOrder = async (payload) => {...} const updateOrder = async (id, payload) => {...} const deleteOrder = async (id) => {...} // Mutations const setFilter = (key, value) => {...} const clearFilters = () => {...} return { // State orders, selectedOrder, loading, error, filters, // Computed orderCount, filteredOrders, totalAmount, // Actions fetchOrders, createOrder, updateOrder, deleteOrder, // Mutations setFilter, clearFilters } }) ``` ### Example: Orders Store ```typescript // State - orders: Order[] - selectedOrder: Order | null - loading: boolean - error: string | null - filters: {status, dateRange, customerId} // Computed - orderCount: number - filteredOrders: Order[] - totalAmount: number // Actions - fetchOrders(limit, offset) - fetchOrderById(orderId) - createOrder(payload) - updateOrder(orderId, payload) - deleteOrder(orderId) // Mutations - setFilter(key, value) - clearFilters() ``` ### Store Setup (src/stores/index.ts) ```typescript export { useOrderStore } from './modules/orders' export { useInventoryStore } from './modules/inventory' export { useProductStore } from './modules/products' export { useCustomerStore } from './modules/customers' // ... etc ``` ### Usage in Components ```vue ``` --- ## Phase 2 Step 3: API Client Integration ### OpenAPI SDK Generation ```bash # From spec/63_oms_wms_erp_api_openapi.yaml npx @openapi-generator/cli generate \ -i ../../spec/63_oms_wms_erp_api_openapi.yaml \ -g typescript-axios \ -o src/services/api/generated ``` ### Generated Files ``` src/services/api/generated/ ├── models/ │ ├── Order.ts │ ├── OrderLine.ts │ ├── Inventory.ts │ └── ... (all 15 models) ├── apis/ │ ├── OrdersApi.ts │ ├── InventoryApi.ts │ ├── ProductsApi.ts │ └── ... (all 11 resources) └── index.ts ``` ### API Client Wrapper (src/services/api/client.ts) ```typescript import axios from 'axios' import { Configuration, OrdersApi, InventoryApi, ... } from './generated' const apiConfig = new Configuration({ basePath: process.env.VITE_API_BASE_URL || 'http://localhost:3000/api' }) export const ordersApi = new OrdersApi(apiConfig) export const inventoryApi = new InventoryApi(apiConfig) export const productsApi = new ProductsApi(apiConfig) // ... etc ``` ### Pinia Integration ```typescript // In store: const response = await ordersApi.listOrders({ limit, offset }) export const useOrderStore = defineStore('orders', () => { const fetchOrders = async () => { try { const response = await ordersApi.listOrders({ limit: 100, offset: 0 }) orders.value = response.data } catch (err) { error.value = (err as Error).message } } // ... }) ``` --- ## Phase 2 Step 4: Integration Testing ### Mock Service Worker (MSW) Setup ```typescript // tests/mocks/handlers.ts import { http, HttpResponse } from 'msw' export const handlers = [ http.get('/api/orders', () => { return HttpResponse.json([ { orderId: '1', orderNo: 'ORD-001', status: 'DRAFT', ... } ]) }), http.post('/api/orders', ({ request }) => { return HttpResponse.json( { orderId: '2', orderNo: 'ORD-002', ... }, { status: 201 } ) }), // ... more handlers ] ``` ### Integration Test Example ```typescript // tests/integration/orders.spec.ts describe('Orders Store with API', () => { beforeEach(() => { server.listen() }) afterEach(() => { server.close() }) it('fetches orders from API', async () => { const store = useOrderStore() await store.fetchOrders() expect(store.orders).toHaveLength(1) expect(store.orders[0].orderNo).toBe('ORD-001') }) it('creates new order', async () => { const store = useOrderStore() const newOrder = await store.createOrder({ customerId: 'CUST-001' }) expect(newOrder.orderId).toBe('2') }) }) ``` ### E2E Test Scenarios (50+) ```typescript // tests/e2e/order-workflow.spec.ts test('Complete order workflow', async ({ page }) => { // 1. Navigate to orders await page.goto('/admin/orders') // 2. Create order await page.click('button:text("Create")') await page.fill('[name="customerId"]', 'CUST-001') await page.fill('[name="quantity"]', '100') await page.click('button:text("Submit")') // 3. Verify order created await expect(page).toContainText('Order created') // 4. Edit order await page.click('button:text("Edit")') await page.fill('[name="quantity"]', '150') await page.click('button:text("Save")') // 5. Verify audit trail await page.goto('/admin/audit-logs') await expect(page).toContainText('Order updated') }) ``` --- ## Phase 2 Completion Criteria ### By End of Week 3 (2026-08-19) - ✅ All 12 Typed Fields implemented - ✅ All Storybook stories rendering (100+ stories) - ✅ All unit tests passing (70+ tests) - ✅ Validation composable complete - ✅ Formatting composable complete ### By End of Week 4 (2026-08-26) - ✅ All 10 Pinia stores implemented - ✅ OpenAPI SDK generated - ✅ API client wrapper complete - ✅ MSW setup for testing - ✅ 50+ integration tests passing - ✅ 50+ E2E test scenarios passing --- ## Success Metrics | Metric | Target | Status | |--------|--------|--------| | Typed Fields | 12/12 | 5/12 ✅ | | Storybook Stories | 100+ | Planned | | Unit Tests | 70+ | Planned | | Integration Tests | 50+ | Planned | | E2E Tests | 50+ | Planned | | Code Coverage | 70%+ | Target | | Lighthouse Score | 90+ | Target | | Bundle Size | <500MB | Target | --- ## Timeline ``` Week 3 (2026-08-12 → 2026-08-19) ├─ Step 1.1: Generate 7 remaining Typed Fields (Mon-Tue) ├─ Step 1.2: Add Storybook stories for all 12 (Wed-Thu) ├─ Step 1.3: Add unit tests for all 12 (Fri) └─ Deliverable: 12 Typed Fields, 100+ stories, 70+ tests ✅ Week 4 (2026-08-20 → 2026-08-26) ├─ Step 2.1: Create 10 Pinia store modules (Mon-Tue) ├─ Step 2.2: Setup OpenAPI SDK + API client (Wed) ├─ Step 2.3: Implement MSW + integration tests (Thu) ├─ Step 2.4: Add E2E test scenarios (Fri) └─ Deliverable: Pinia stores, API client, 100+ tests ✅ Next: Phase 3 (Domain Fields, Week 5-6) ``` --- **Status**: 🚀 Phase 2 Started (2026-08-12) **Step 1 Progress**: 5/12 Typed Fields (42%) **Timeline**: 2 weeks (2026-08-12 → 2026-08-26)