b34b0dd7d6
Validators (Pushes and Pull Requests) / UI & Storage Validation (pull_request) Failing after 12s
Validators (Pushes and Pull Requests) / Database & Schema Validation (pull_request) Successful in 13s
Validators (Pushes and Pull Requests) / Core Validators & Database Setup (pull_request) Failing after 28s
Validators (Pushes and Pull Requests) / WBS & Audit Validations (pull_request) Has been skipped
Validators (Pushes and Pull Requests) / .NET Contracts (pull_request) Has been skipped
Validators (Pushes and Pull Requests) / Calibration & Performance (pull_request) Has been skipped
Validators (Pushes and Pull Requests) / Operational Report & Decision Packet (pull_request) Has been skipped
Validators (Pushes and Pull Requests) / CI Workflow Lint (pull_request) Failing after 10s
Validators (Pushes and Pull Requests) / Security & Secrets (pull_request) Successful in 12s
Validators (Pushes and Pull Requests) / Notify PR Results (pull_request) Successful in 2s
Frontend CI Pipeline / ci-frontend-8-steps (pull_request) Failing after 2m50s
11 KiB
11 KiB
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) ✅
-
TextField — Text inputs with validation
- Types: text, email, password, url, tel
- File: src/components/fields/typed/TextField/
- Stories: 8+
- Tests: 5+
-
DateField — Date picker
- Format: YYYY-MM-DD (ISO)
- Min/Max validation
- File: src/components/fields/typed/DateField/
- Stories: 8+
- Tests: 5+
-
CurrencyField — Amount input with formatting
- Locale: Korean (₩)
- Decimals: configurable
- File: src/components/fields/typed/CurrencyField/
- Stories: 10+
- Tests: 5+
-
SelectField — Dropdown with validation
- Options: typed array
- Searchable: ready
- File: src/components/fields/typed/SelectField/
- Stories: 8+
- Tests: 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
- TimeField (time picker, HH:mm)
- PercentageField (0-100%, formatted)
- QuantityField (positive integers)
- MultiSelectField (array of values)
- CheckboxField (boolean)
- SearchField (autocomplete with API)
- PhoneField (formatted phone)
Shared Utilities ✅
useValidation.ts — Validation composable
- required, email, minLength, maxLength
- min, max, pattern, numeric
- positiveInteger, percentage, url
- Chainable: validator.validate(value, [rule1, rule2])
useFormatting.ts — Formatting composable
- 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)
// Each store follows this pattern:
export const useOrderStore = defineStore('orders', () => {
// State
const orders = ref<Order[]>([])
const selectedOrder = ref<Order | null>(null)
const loading = ref(false)
const error = ref<string | null>(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
// 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)
export { useOrderStore } from './modules/orders'
export { useInventoryStore } from './modules/inventory'
export { useProductStore } from './modules/products'
export { useCustomerStore } from './modules/customers'
// ... etc
Usage in Components
<script setup lang="ts">
import { useOrderStore } from '@/stores'
const orderStore = useOrderStore()
// Access state
const orders = orderStore.orders
const loading = orderStore.loading
// Access computed
const filteredOrders = orderStore.filteredOrders
// Call actions
await orderStore.fetchOrders(100, 0)
await orderStore.createOrder({...})
</script>
Phase 2 Step 3: API Client Integration
OpenAPI SDK Generation
# 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)
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
// 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
// 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
// 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+)
// 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)