# Cross-Cutting Concerns Aspects that span all phases and must be maintained consistently throughout development. --- ## API Versioning - All endpoints prefixed with `/api/v1/` - Version is part of the URL, not headers - When breaking changes are needed, introduce `/api/v2/` alongside v1 - Deprecation: v1 endpoints log warnings 3 months before removal --- ## Pagination All list endpoints use **cursor-based pagination**: ```typescript // Request GET /api/v1/products?cursor=abc123&limit=20 // Response { "data": [...], "pagination": { "cursor": "def456", // Pass as next cursor, null = no more pages "hasMore": true, "total": 150 // Total count (optional, can be expensive) } } ``` - Default `limit`: 20, max: 100 - Cursor is an opaque string (encoded `_id` or composite sort key) - Prefer cursor over offset/skip for MongoDB performance --- ## Audit Trail Every domain document includes: ```typescript { createdAt: Date; // Set on creation, never modified updatedAt: Date; // Updated on every modification createdBy: string; // userId who created } ``` For sensitive operations (deletes, status transitions, admin actions), maintain an `AuditLog` collection: ```typescript interface AuditLog { id: string; householdId: string; userId: string; action: string; // 'product.delete', 'pantry.transition', etc. entityType: string; // 'Product', 'PantryItem', etc. entityId: string; changes?: Record; timestamp: Date; } ``` Implemented as a NestJS interceptor that logs after successful mutations. --- ## Error Handling Consistent error response format across all endpoints: ```typescript interface ApiError { statusCode: number; error: string; // HTTP status text message: string; // Human-readable message details?: any; // Validation errors, etc. timestamp: string; path: string; } ``` Global exception filter in NestJS catches: - `ValidationException` → 400 - `UnauthorizedException` → 401 - `ForbiddenException` → 403 - `NotFoundException` → 404 - `ConflictException` → 409 (e.g., duplicate barcode) - `TooManyRequestsException` → 429 (LLM rate limit) - Unhandled errors → 500 (log stack trace, return generic message) --- ## Real-Time (WebSocket) NestJS `@WebSocketGateway` with Socket.IO: - **Authentication**: validate JWT on connection - **Rooms**: one room per `householdId` — all household members receive household events - **Namespaces**: optional per-feature namespaces (`/pantry`, `/shopping`) Events introduced per phase: | Phase | Events | | ----- | ------------------------------------------------------------------------------------------------ | | 3 | `pantry:item-added`, `pantry:item-updated`, `pantry:freshness-alert` | | 5 | `shopping:item-checked`, `shopping:item-added`, `shopping:item-removed`, `shopping:list-updated` | | 4 | `meal-plan:updated` | Frontend pattern: - Connect on app mount, join household room - Use React context/Zustand store to distribute events to components - Optimistic UI updates with server reconciliation --- ## Testing Strategy ### Unit Tests (per module, per phase) - **Services**: business logic, calculations (nutrition calculator, freshness calculator, suggestion scoring) - **Guards/Interceptors**: auth, household scoping - **Mocking**: MongoDB operations mocked for service tests - **Framework**: Jest ### Integration Tests (per module) - **In-memory MongoDB** (`mongodb-memory-server`) or test containers - Test full request → service → database → response cycle - **Framework**: Supertest + Jest ### E2E Tests (per phase milestone) - Full Docker Compose stack - Automated script that exercises the happy path: 1. Register/login user 2. Create household 3. Add products 4. Create recipe 5. Stock pantry 6. Generate meal plan 7. Create shopping list 8. Check off items → add to pantry - **Framework**: Supertest or Playwright (for web UI) ### Frontend Tests - **Component tests**: React Testing Library - **Hook tests**: `@testing-library/react-hooks` - **E2E**: Playwright for critical flows (login, add product, create recipe) ### Test Coverage Targets | Type | Target | | ----------- | -------------------- | | Unit | 80%+ | | Integration | Key flows covered | | E2E | Happy path per phase | --- ## Mobile Readiness Design decisions to facilitate React Native development later: 1. **All business logic in API**: the web frontend is a thin UI layer. Mobile will consume the same API. 2. **Shared types package**: `packages/shared` is platform-agnostic TypeScript. Mobile imports it directly. 3. **No SSR dependencies in shared code**: avoid Next.js-specific imports in `packages/shared`. 4. **API client layer**: `packages/web/src/services/api.ts` wraps fetch/axios with auth. Mobile will have its own but same pattern. 5. **WebSocket events**: same events work on mobile (Socket.IO has React Native support). 6. **Auth**: Keycloak has React Native OIDC libraries (`react-native-app-auth`). 7. **Image handling**: API accepts standard multipart uploads — works from any client. 8. **Push notifications**: Phase 3 starts with in-app notifications. Mobile phase adds Firebase Cloud Messaging (FCM) as a notification channel. When the mobile phase begins: - Add `packages/mobile` (React Native via Expo or bare workflow) - Share from `packages/shared` - Build mobile-optimized UI for key flows: pantry check, shopping list, quick add --- ## Security - **Authentication**: All API routes require valid Keycloak JWT (except health check) - **Authorization**: Household-scoped — users can only access data for their households - **Input validation**: Zod schemas validate all inputs; NestJS validation pipe rejects invalid requests - **Rate limiting**: per-IP and per-household (configurable) - **CORS**: restricted to known origins - **Helmet**: HTTP security headers via `@nestjs/helmet` - **Secrets**: environment variables, never committed; `.env.example` documents required vars - **Image uploads**: validate file type and size; store in local volume or S3-compatible storage - **MongoDB**: authenticated access, least-privilege user for the app --- ## Performance - **MongoDB indexes**: reviewed and optimized per phase (documented in each phase doc) - **Query profiling**: enable MongoDB slow query log in dev; review before phase sign-off - **Caching**: consider Redis for: - Product search results (short TTL) - Freshness rule lookups (rarely change) - LLM response caching (identical inputs) - **Denormalization**: nutrition on recipes, product names on pantry items — reduces lookups - **Pagination**: cursor-based, no `skip()` for large collections - **Compression**: gzip responses via NestJS middleware --- ## Observability (Future) Not in initial phases, but plan for: - **Structured logging**: Pino or Winston with JSON format - **Health checks**: `/api/v1/health` returns status of MongoDB, Keycloak connectivity - **Metrics**: Prometheus-compatible endpoint (NestJS has plugins) - **Tracing**: OpenTelemetry for request tracing across services - **Error tracking**: Sentry integration (optional, self-hosted instance possible)