# 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<string, { from: any; to: any }>;
  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)
