|
| 1 | +# Angular State Architecture and Data Flow |
| 2 | + |
| 3 | +> This document provides detailed architectural guidance for state management. For quick reference, see the [Angular Cheat Sheet](./angular-cheat-sheet.md). For implementation rules, see [Angular Coding Standards](./angular_coding_standards.md). |
| 4 | +
|
| 5 | +## Overview |
| 6 | + |
| 7 | +This document outlines our application's state management architecture and the recommended data flow patterns. Following these patterns ensures consistent, maintainable, and predictable state management across the application. |
| 8 | + |
| 9 | +## Architecture Layers |
| 10 | + |
| 11 | +Our application state architecture consists of three primary layers: |
| 12 | + |
| 13 | +1. **Global State Layer** - Central, shared application state |
| 14 | +2. **Service Layer** - Business logic and state mutation |
| 15 | +3. **Component Layer** - UI components with local state |
| 16 | + |
| 17 | +## Data Flow Pattern |
| 18 | + |
| 19 | +[CS-S01] Our application follows a bi-directional data flow pattern: |
| 20 | + |
| 21 | +``` |
| 22 | + READ (Direct) |
| 23 | + ┌─────────────────────────┐ |
| 24 | + │ │ |
| 25 | + ▼ │ |
| 26 | +┌───────────────────┐ ┌───────────────────┐ |
| 27 | +│ │ │ │ |
| 28 | +│ Components │ │ Global State │ |
| 29 | +│ (Consumers) │ │ (Storage) │ |
| 30 | +│ │ │ │ |
| 31 | +└───────────────────┘ └───────────────────┘ |
| 32 | + │ ▲ |
| 33 | + ▼ │ |
| 34 | +┌───────────────────┐ │ |
| 35 | +│ │ │ |
| 36 | +│ Services │────────────────┘ |
| 37 | +│ │ |
| 38 | +└───────────────────┘ |
| 39 | + Services handle: |
| 40 | + - Business Logic |
| 41 | + - API Calls |
| 42 | + - Validation |
| 43 | + - State Updates |
| 44 | +
|
| 45 | +``` |
| 46 | + |
| 47 | +### Read Operations (State to Component) |
| 48 | + |
| 49 | +[CS-S02] Components read data directly from the Global State Layer via Store Signals: |
| 50 | + |
| 51 | +1. Global store signals expose reactive state to components |
| 52 | +2. Components subscribe to relevant store signals |
| 53 | +3. Components can derive local computed signals from store signals |
| 54 | +4. UI automatically updates when signal values change |
| 55 | + |
| 56 | +### Write Operations (Component to State) |
| 57 | + |
| 58 | +[CS-S03] Components write data to the Global State through Services: |
| 59 | + |
| 60 | +1. Component dispatches an action by calling a service method |
| 61 | +2. Service performs business logic and validation |
| 62 | +3. Service updates the global state |
| 63 | +4. State changes propagate back to components via signals |
| 64 | + |
| 65 | +## Responsibilities by Layer |
| 66 | + |
| 67 | +### Global State Layer |
| 68 | + |
| 69 | +**Store:** |
| 70 | +- Maintains the single source of truth for application state |
| 71 | +- Holds structured data models |
| 72 | +- Provides methods for state mutations [CS-S03] |
| 73 | + |
| 74 | +**Store Signals:** |
| 75 | +- Exposes reactive state via signals [CS-S02] |
| 76 | +- Provides derived/computed state |
| 77 | +- Enables fine-grained reactivity |
| 78 | + |
| 79 | +### Service Layer |
| 80 | + |
| 81 | +**Services:** |
| 82 | +- Implement most domain business logic [CS-V03] |
| 83 | +- Handle data fetching and API communication [CS-S05] |
| 84 | +- Process and validate data before state updates |
| 85 | +- Orchestrate complex workflows |
| 86 | +- Manage side effects (e.g., logging, analytics) |
| 87 | +- Update global state [CS-S03] |
| 88 | + |
| 89 | +### Component Layer |
| 90 | + |
| 91 | +**Components:** |
| 92 | +- Consume store signals for display |
| 93 | +- Create local computed signals for component-specific derived state |
| 94 | +- Dispatch actions through service methods |
| 95 | +- Maintain minimal local state for UI-only concerns |
| 96 | +- Handle user interactions |
| 97 | +- Focus on presentation logic |
| 98 | + |
| 99 | +## Decision Guidelines |
| 100 | + |
| 101 | +| Concern | Location | Justification | |
| 102 | +|---------|----------|---------------| |
| 103 | +| Application data | Store | Centralized, shared across components | |
| 104 | +| Business logic | Services | Reusable, testable, independent of UI | |
| 105 | +| API communication | Services | Encapsulates external dependencies | |
| 106 | +| Data transformations | Services & Store Signals | Services for write path, Store Signals for read path | |
| 107 | +| Form state | Component local state | Temporary UI state until submission | |
| 108 | +| UI state (expanded/collapsed) | Component local state | UI-specific concerns | |
| 109 | +| Derived data calculations | Store Signals or Component signals | Global derivations in Store Signals, component-specific in local signals | |
| 110 | +| Validations | Services (for business rules), Components (for UI validation) | Business validations in services, immediate feedback in components | |
| 111 | + |
| 112 | +## Best Practices |
| 113 | + |
| 114 | +1. **Minimize component state** - Only use local state for UI-specific concerns |
| 115 | +2. **Keep components pure** - Focus on presentation, delegate logic to services |
| 116 | +3. **Services should be stateless** - They orchestrate but don't store state [CS-V04] |
| 117 | +4. **Global state should be normalized** - Avoid duplication and nested state |
| 118 | +5. **Use computed signals** - Derive values rather than storing calculated results [CS-S02] |
| 119 | +6. **Lazy-load state modules** - Only load state relevant to the current route |
| 120 | +7. **Dispatch one action per user intent** - Services should orchestrate complex workflows |
| 121 | + |
| 122 | +## Anti-patterns to Avoid |
| 123 | + |
| 124 | +1. ❌ Components mutating store directly (bypass services) [violates CS-S03] |
| 125 | +2. ❌ Components containing business logic |
| 126 | +3. ❌ Services with their own state |
| 127 | +4. ❌ Duplicating store data in component state |
| 128 | +5. ❌ Deep nesting in global state |
| 129 | +6. ❌ Storing derived data that could be computed |
| 130 | + |
| 131 | +## Example Flow |
| 132 | + |
| 133 | +```typescript |
| 134 | +// Component reading from store |
| 135 | +@Component({...}) |
| 136 | +export class ProductListComponent { |
| 137 | + // Read directly from store signals |
| 138 | + products = inject(ProductStore).products; |
| 139 | + |
| 140 | + // Local computed signal |
| 141 | + filteredProducts = computed(() => |
| 142 | + this.products().filter(p => p.inStock) |
| 143 | + ); |
| 144 | + |
| 145 | + // Write through service |
| 146 | + constructor(private productService: ProductService) {} |
| 147 | + |
| 148 | + addToCart(productId: string): void { |
| 149 | + this.productService.addProductToCart(productId); |
| 150 | + } |
| 151 | +} |
| 152 | +``` |
| 153 | + |
| 154 | +By following this architecture and data flow pattern, we create a scalable, maintainable application with clear separation of concerns and predictable state management. |
0 commit comments