Decision: ACCEPT Monolithic SPA (Vue 3 + TypeScript + Pinia) - Single Vite build, fast delivery (18-week timeline feasible) - 7-layer architecture: Presentation → State → API Client → Domain → Repository → Infrastructure → External - 4-layer component hierarchy: Primitive → Typed Field → Domain Field → Business Composite - 11 CRUD templates standardized for all entities - Alternatives rejected: Micro-Frontend (too complex), Separate Frontends (scope creep), Low-Code (vendor lock-in) - Consequences: Fast delivery, unified codebase, maintainability vs monolith brittleness (mitigated by blue-green deployment) - Phase 1-4 implementation plan: Dev env → Primitives → Smart Components → Full CRUD + E2E (116 test scenarios) - Bundle target: <500KB (gzip), Lighthouse 90+, P95 response <250ms - Team: 13 FTE (4 FE, 2 BE, 1 UX, 2 QA, 1 DevOps, 0.5 security, 0.5 docs) - Validation: Stakeholder sign-off, component taxonomy, API contract lock-down before Phase 1 D2 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 <noreply@anthropic.com>
17 KiB
ADR-001: Monolithic SPA Architecture for OMS·WMS·ERP Platform
Status: ACCEPTED (2026-07-26)
Date: 2026-07-26
Deciders: Product Manager, Technical Lead, Architecture Team
Related Decisions: Strategic Execution Framework (Spec 61), OpenAPI (Spec 63), Database Schema (Spec 64)
Context
OMS·WMS·ERP commercialization requires unified platform architecture decision to balance:
- Time-to-Market: 18-week Phase 0-11 roadmap (4.5 months)
- Team Capacity: 13 FTE (4 frontend devs, 2 backend, 1 UX, 2 QA, infrastructure)
- Maintenance Burden: Long-term operational cost
- Scalability: Peak load (100 concurrent users during peak hours, future 1000+)
- Team Skill Set: Experienced Vue 2 team, transitioning to Vue 3 + TypeScript
- Feature Complexity: 11 CRUD templates, 5 user roles, audit/compliance requirements
Problem Statement
"Should we build a single monolithic SPA or adopt micro-frontend architecture?"
Tradeoff Matrix:
| Factor | Monolithic | Micro-Frontend |
|---|---|---|
| Time-to-Market | ✅ Fast (single build, shared state) | ❌ Slower (coordination, build complexity) |
| Team Efficiency | ✅ Shared code/patterns | ❌ Potential duplication |
| Deployment Risk | ⚠️ Full redeploy | ✅ Independent deploys (but coordination complexity) |
| Complexity (Initial) | ✅ Simple (one codebase) | ❌ Complex (module federation, routing) |
| State Management | ✅ Centralized (Pinia) | ⚠️ Distributed (synchronization overhead) |
| Learning Curve | ✅ Single pattern | ❌ Multiple architectural patterns |
| Future Modularity | ⚠️ Refactoring cost | ✅ Already isolated |
Decision
ADOPT: Monolithic SPA Architecture
Rationale
-
Time-to-Market (P0 Priority)
- Single Vite build pipeline → faster CI/CD turnaround
- Shared Pinia store eliminates cross-module synchronization
- No module federation complexity (can add in Phase 12+ if needed)
- Team can move fast on core 11 CRUD templates without coordination overhead
-
Team Efficiency (13 FTE Constraint)
- 4 frontend devs work on unified codebase (not split into silos)
- Shared component library reduces duplication
- PR reviews simpler (single review standard)
- Onboarding new devs easier (one architectural pattern)
-
Scalability Headroom
- 100 concurrent users = 50-100 backend requests/sec (well within SPA capacity)
- PostgreSQL backend can handle 10K+ concurrent connections
- Browser memory: Pinia store + Vue tree ~5-10MB even at 1000 concurrent
- Future scale-out: Independent microservices backend (no frontend change needed)
-
Data Consistency (Principle 3)
- Centralized Pinia store = single source of truth for all entities
- No client-side replication or sync logic
- Audit trail via PostgreSQL audit_logs (all mutations captured)
- JWT tokens + RBAC enforced server-side (client trusted for UX only)
-
Cost Efficiency
- Single deployment pipeline = lower ops cost
- Monolithic codebase = faster debugging and troubleshooting
- No microservices orchestration overhead (Kubernetes, service mesh)
Architectural Layers (7-Layer Model)
┌─────────────────────────────────────────────────────┐
│ 1. Presentation Layer (Vue 3 SPA) │
│ - 4-layer component hierarchy │
│ - Tabler UI + Bootstrap 5 + Storybook │
│ - Responsive + WCAG 2.1 AA │
├─────────────────────────────────────────────────────┤
│ 2. State Management (Pinia) │
│ - Entity stores (orders, inventory, products) │
│ - UI state (modals, notifications, routing) │
│ - Auth store (user, roles, permissions) │
├─────────────────────────────────────────────────────┤
│ 3. API Client Layer (Axios + Auto-Generated) │
│ - Type-safe: OpenAPI → TypeScript SDK │
│ - Interceptors: JWT refresh, error handling │
│ - Offline support: Request queue (Phase 12+) │
├─────────────────────────────────────────────────────┤
│ 4. Domain Layer (Business Logic) │
│ - Computed properties (qty_available, totals) │
│ - Validation rules (duplicate checks, constraints) │
│ - Formatters (currency, date, status labels) │
├─────────────────────────────────────────────────────┤
│ 5. Repository Layer (Data Access Patterns) │
│ - Cache strategies (LRU, TTL) │
│ - Optimistic updates (e.g., reorder lines) │
│ - Pagination (lazy load, infinite scroll) │
├─────────────────────────────────────────────────────┤
│ 6. Infrastructure (Routing, Navigation, Config) │
│ - Vue Router (lazy-loaded per route) │
│ - Global error boundaries │
│ - Feature flags (Phase 12+) │
├─────────────────────────────────────────────────────┤
│ 7. External Services (Backend APIs + 3P) │
│ - REST APIs (OpenAPI 3.0) │
│ - JWT authentication │
│ - Real-time updates (WebSocket Phase 12+) │
└─────────────────────────────────────────────────────┘
4-Layer Component Hierarchy
Layer 1: Primitive Components
├─ ButtonBase, InputBase, SelectBase, TextBase
└─ Reusable, no business logic, full a11y
Layer 2: Typed Field Components
├─ TextField, DateField, CurrencyField, StatusField
└─ Domain-aware validation, formatting, labels
Layer 3: Domain Field Components
├─ OrderLineField, InventoryField, VoucherLineField
└─ Business rules, inline lookups, multi-field composition
Layer 4: Business Composite Components
├─ OrderForm, InventoryTransferWizard, VoucherEditor
└─ Full workflows, state orchestration, audit trail
11 CRUD Templates Standardization
All 11 entity CRUD flows follow uniform pattern (List → Create → Read → Edit → Delete):
| Entity | API Endpoints | UI Components | Test Coverage |
|---|---|---|---|
| Order | 6 (GET, POST, PUT, DELETE + list, detail) | OrderList, OrderDetail, OrderForm | 30 E2E scenarios |
| OrderLine | Nested CRUD (in order context) | LineEditor (inline in form) | 10 E2E |
| Inventory | 6 | InventoryList, TransferWizard | 15 E2E |
| StockTransfer | 6 | TransferForm, ApprovalMatrix | 12 E2E |
| Product | 6 | ProductList, ProductForm | 10 E2E |
| Supplier | 6 | SupplierList, SupplierForm | 8 E2E |
| Customer | 6 | CustomerList, CustomerForm | 8 E2E |
| GLAccount | 6 | AccountList, AccountForm | 8 E2E |
| Voucher | 6 | VoucherEditor (line-by-line) | 15 E2E |
| User | 6 | UserList, UserForm, PermissionMatrix | 12 E2E |
| Warehouse | 6 | WarehouseList, WarehouseForm | 8 E2E |
Total E2E Coverage: 116 test scenarios (Phase 4 milestone)
Consequences
✅ Positive
-
Faster Delivery
- Single build pipeline: ~3 min build time
- CI/CD simpler: No cross-module coordination
- Feature complete by Phase 4 (week 8) for UAT
-
Maintainability
- Unified codebase = easier debugging
- All devs understand full system
- Refactoring easier (no hidden dependencies)
-
Data Consistency
- Pinia store = single source of truth
- No sync issues between independent UIs
- Audit trail via PostgreSQL (not client-side)
-
User Experience
- Instant navigation (no full-page reloads)
- Smooth transitions between modules
- Consistent look & feel (unified design system)
-
Test Coverage
- 50/30/20 pyramid: unit (50%) → integration (30%) → E2E (20%)
- All 116 E2E scenarios in single test suite
- Deterministic tests (single state source)
⚠️ Negative (Mitigations)
-
Monolith Brittleness
- Problem: One bad release breaks entire app
- Mitigation: Strict pre-deployment checklist (Phase 5+), blue-green deployment, 6-point health checks
-
Large Bundle Size
- Problem: Initial load time if all code bundled
- Mitigation: Lazy-load routes per module, code split at route level, target <500KB main chunk (Lighthouse 90+)
-
Shared State Complexity
- Problem: Pinia store grows as features added
- Mitigation: Modular stores (orders, inventory, users modules), clear naming, documentation
-
Scaling to 1000+ Users
- Problem: Browser memory, server load
- Mitigation: Pagination (not all records in memory), connection pooling (PostgreSQL), infrastructure scale-out (Phase 12+)
-
Future Microfront-End Transition
- Problem: If modularity needed later, refactoring cost
- Mitigation: Component library + API contracts locked down early, can extract UI module → separate SPA in Phase 13+
Alternatives Considered
1. Micro-Frontend Architecture (Module Federation)
Approach: Each CRUD entity (Order, Inventory, etc.) as independent webpack Module Federation remote
Pros:
- Independent deployments per module
- Teams can work in parallel without merge conflicts
- Better long-term modularity
Cons:
- ❌ Shared state synchronization complexity (events, bus, sync failures)
- ❌ Build time: 9-12 min (multiple builds + federation setup)
- ❌ 18-week timeline NOT feasible (needs 20+ weeks for coordination overhead)
- ❌ Learning curve (few devs experienced in Module Federation)
- ❌ CI/CD complexity (version matrix: Order v1-v3 × Inventory v2-v5)
Decision: REJECTED — Too risky for 18-week timeline with 4 frontend devs
2. Headless Backend + Separate Frontends (Web + Mobile)
Approach: Unified .NET backend + Vue SPA (web) + React Native (mobile)
Pros:
- Native mobile experience
- Backend shared code reuse
Cons:
- ❌ Scope creep (mobile adds 4-6 weeks)
- ❌ Double maintenance (Vue + React Native)
- ❌ Mobile not in Phase 0-11 scope (can add in Phase 13+)
Decision: REJECTED — Out of scope. Mobile deferred to Phase 13+
3. Low-Code Platform (OutSystems, Mendix)
Approach: Rapid CRUD generation, visual development
Pros:
- Fastest CRUD generation
- Less boilerplate code
Cons:
- ❌ Vendor lock-in
- ❌ Limited customization for complex workflows (approval matrix, audit trail)
- ❌ Higher TCO (licensing)
- ❌ Team skill atrophy (no real engineering)
Decision: REJECTED — Does not meet control + compliance requirements
4. Separate Microservices UIs (One SPA per domain: OMS, WMS, ERP)
Approach: 3 independent SPAs (micro-frontends without Module Federation)
Pros:
- Clear domain separation
- Smaller bundles per SPA
Cons:
- ❌ Cross-domain navigation complex (not SPA-like experience)
- ❌ Duplicate components (auth, common UI)
- ❌ Harder to reorder across domains (OMS order → WMS allocation → ERP GL)
- ❌ 3 CI/CD pipelines vs 1
Decision: REJECTED — Poor user experience for cross-domain workflows
Implementation Plan (Phases 1-4)
Phase 1: Dev Environment & CI/CD (Week 1-2)
- Vite SPA scaffold + TypeScript strict mode
- Pinia stores structure (orders, inventory, users modules)
- Axios API client + OpenAPI SDK auto-generation
- ESLint + Prettier + pre-commit hooks
- GitHub Actions CI/CD (lint → test → build)
- Storybook setup (6.0+, TypeScript support)
Exit Criteria: All devs can build locally, CI green, Storybook runs
Phase 2: Primitive & Composite Layers (Week 3-4)
- Layer 1: 30 Primitive components (Button, Input, Select, etc.)
- Layer 2: 12 Typed Field components (TextField, DateField, etc.)
- Storybook documentation for all components
- WCAG 2.1 AA accessibility audit (axe-core)
- Unit tests: 70%+ coverage
Exit Criteria: Storybook published, all primitives tested, accessibility passed
Phase 3: Smart Components & State (Week 5-6)
- Layer 3: 12 Domain Field components
- Layer 4: 4 Business Composite components (Order, Inventory, Voucher, User)
- Pinia stores + API integration
- Integration tests (Vitest + MSW mocks)
- Real-time data binding
Exit Criteria: State management tested, API mocks working, 50 integration tests pass
Phase 4: CRUD Templates & E2E (Week 7-8)
- 11 full CRUD forms (List, Create, Read, Edit, Delete)
- Approval workflows (supervisor sign-off for high-value orders)
- Pagination + lazy loading
- 116 E2E test scenarios (Playwright)
- Responsive design (mobile, tablet, desktop)
Exit Criteria: All 11 CRUD screens tested, 116 E2E scenarios pass, Lighthouse 90+
Related Decisions
- ADR-002 (TBD): Authentication & Authorization (JWT + RBAC)
- ADR-003 (TBD): State Management Strategy (Pinia module organization)
- ADR-004 (TBD): Component Library Versioning (npm @quantengine/ui)
- Strategic Execution Framework (Spec 61): 30 principles applied
- OpenAPI Specification (Spec 63): 30 REST endpoints defined
- Database Schema (Spec 64): PostgreSQL 3NF design
Validation Checklist (Phase 0 → Phase 1)
Before proceeding to Phase 1 development:
- All stakeholders agree on monolithic SPA approach
- Component taxonomy approved (4-layer hierarchy)
- 11 CRUD templates mapped to API endpoints
- OpenAPI spec validated by backend team
- Database schema approved by DBA
- Vite scaffold created with TypeScript strict mode
- CI/CD pipeline (GitHub Actions) functional
- Team training: Vue 3 Composition API + Pinia + TypeScript
- Design system finalized (Tabler + custom components)
Appendix A: Bundle Size Strategy
Target: Main chunk <500KB (gzip), total <1MB
Strategy:
- Route-level code splitting: Lazy-load each CRUD module (orders, inventory, etc.)
- Dynamic imports:
import('./orders/OrderForm.vue') - Library externalization: Vue, Pinia, Axios in separate chunks
- Tree-shaking: Remove unused Tabler components at build time
- Compression: Gzip (server) + Brotli (CDN)
Monitoring: Bundle analyzer in CI (Phase 5+)
Appendix B: Performance Targets
| Metric | Target | Rationale |
|---|---|---|
| First Contentful Paint (FCP) | <2s | Initial render speed |
| Time to Interactive (TTI) | <3s | User can interact |
| Largest Contentful Paint (LCP) | <2.5s | Main content visible |
| Cumulative Layout Shift (CLS) | <0.1 | Visual stability |
| API response time (P95) | <250ms | Backend performance |
| Database query (P95) | <100ms | Query optimization |
| Concurrent users (initial) | 100 | Phase 0-8 capacity |
| Concurrent users (future) | 1000+ | Phase 12+ infrastructure scale |
Appendix C: Team Structure (13 FTE)
Product Manager (1)
├─ Requirements gathering, stakeholder communication
│
Technical Lead / Architect (1)
├─ Architecture decisions, code review
│
Frontend Development Team (4)
├─ Lead FE Dev (1): Component library, design system
├─ Senior FE Dev (1): State management, API integration
├─ Mid-Level FE Dev (2): CRUD templates, E2E tests
│
Backend Development Team (2)
├─ API development (.NET)
├─ Database optimization
│
UX/UI Designer (1)
├─ Figma designs, accessibility audit
│
QA Team (2)
├─ Automation (Playwright)
├─ Manual testing + UAT coordination
│
DevOps/SRE (1)
├─ CI/CD pipeline, monitoring, deployment
│
Security Specialist (0.5 contractor)
├─ Security audit, OWASP validation
│
Technical Writer (0.5)
├─ API docs, user guides, wiki
Sign-Off
- Product Manager: _________________ Date: _______
- Technical Lead: _________________ Date: _______
- Backend Lead: _________________ Date: _______
- Frontend Lead: _________________ Date: _______
- QA Lead: _________________ Date: _______
Document Version: 1.0
Last Updated: 2026-07-26
Next Review: Phase 1 completion (2026-08-09)