Files
motovaultpro/docs/ARCHITECTURE-OVERVIEW.md
Eric Gullickson d4156cf521 Stuff
2025-11-04 18:38:06 -06:00

515 lines
18 KiB
Markdown

# MotoVaultPro Architecture Overview
## Architecture Summary
MotoVaultPro is a single-tenant vehicle management application built with a **6-container Docker-first architecture**. All development and deployment occurs in production-configured containers with no local installation dependencies.
### Core Containers
1. **Traefik** - Reverse proxy and service discovery
2. **Frontend** - React SPA with Vite (Node.js 20 + nginx)
3. **Backend** - Node.js API with Fastify (Node.js 20)
4. **PostgreSQL** - Primary database (PostgreSQL 15)
5. **Redis** - Caching layer (Redis 7)
6. **Platform** - Vehicle data service (Python FastAPI)
### Key Architectural Principles
- **Production-Only**: All services use production builds and configuration
- **Docker-First**: Zero local installations, all work happens in containers
- **Single-Tenant**: Application serves a single user/tenant
- **User-Scoped Data**: All application data isolated by `user_id`
- **Feature Capsule Organization**: Self-contained feature modules in `backend/src/features/`
## Container Interaction Diagram
```
Internet/Users
|
v
+----------------+------------------+
| Traefik |
| (Reverse Proxy & TLS) |
| Ports: 80, 443, 8080 |
+----------------+------------------+
|
+---------------------+---------------------+
| |
v v
+------------------+ +--------------------+
| Frontend | | Backend |
| React + Vite | | Node.js + Fastify |
| Port: 3000 | | Port: 3001 |
+------------------+ +--------------------+
(frontend network) (backend network)
|
|
+---------------------------------+
| |
v v
+---------------+ +-------------+
| PostgreSQL | | Redis |
| Port: 5432 | | Port: 6379 |
+---------------+ +-------------+
(database network - internal)
```
## Network Topology
### Frontend Network
- **Purpose**: Public traffic routing
- **Type**: Bridge (non-internal)
- **Connected Services**: Traefik, Frontend
- **Access**: External (for Traefik public endpoints)
### Backend Network
- **Purpose**: API service communication
- **Type**: Bridge (non-internal)
- **Connected Services**: Traefik, Backend, Platform
- **Access**: External (requires Auth0 JWT validation)
### Database Network
- **Purpose**: Data layer isolation
- **Type**: Bridge (internal)
- **Connected Services**: Backend, Platform, PostgreSQL, Redis
- **Access**: Internal only, no external exposure
## Request Flow
### User Request Flow
```
1. User → HTTPS Request
2. Traefik → TLS Termination + Route Selection
- Domain: motovaultpro.com or www.motovaultpro.com
- Path: / → Frontend (priority 10)
- Path: /api → Backend (priority 20)
- Path: /platform → Platform (priority 25)
3. Frontend/Backend → Process Request
4. Response → Traefik → User
```
### Authentication Flow
```
1. User → Frontend → Auth0 (Login)
2. Auth0 → JWT Token → Frontend
3. Frontend → Backend (with Authorization: Bearer <JWT>)
4. Backend → Validate JWT via Auth0 JWKS
5. Backend → Extract user_id from JWT (request.user.sub)
6. Backend → Execute user-scoped queries
7. Backend → Response → Frontend
```
### Backend Platform Flow
```
1. Backend Feature → Calls platform domain services (TypeScript in-process)
2. Platform module → Query PostgreSQL (vehicles schema)
3. Platform module → Check/Update Redis cache
4. Platform response → Returned to caller (vehicles, frontend proxies, etc.)
```
### Data Access Flow
```
1. Backend/Platform → PostgreSQL Query
- Database: motovaultpro
- Connection: Internal via database network
2. Backend/Platform → Redis Cache Check
- Connection: Internal via database network
3. Response → Backend → Frontend
```
## Service Details
### Traefik (Reverse Proxy)
- **Image**: traefik:v3.0
- **Purpose**: Service discovery, TLS termination, load balancing
- **Ports**:
- 80 (HTTP)
- 443 (HTTPS)
- 8080 (Dashboard)
- **Networks**: frontend, backend
- **Health Check**: `traefik healthcheck` (30s interval)
- **Configuration**:
- `/etc/traefik/traefik.yml` - Main config
- `/etc/traefik/middleware.yml` - Middleware rules
- Dynamic routing via Docker labels
### Frontend (React SPA)
- **Technology**: React 18 + Vite + TypeScript
- **Build**: Multi-stage Dockerfile (node:20-alpine → nginx:alpine)
- **Port**: 3000 (internal)
- **Networks**: frontend
- **Dependencies**: Backend (API calls)
- **Health Check**: `curl http://localhost:3000` (30s interval)
- **Environment Variables**:
- `VITE_AUTH0_DOMAIN` - Auth0 tenant
- `VITE_AUTH0_CLIENT_ID` - Auth0 application ID
- `VITE_AUTH0_AUDIENCE` - API identifier
- `VITE_API_BASE_URL` - Backend API path (/api)
- **Routing**: Traefik routes non-/api paths to frontend
### Backend (Node.js API)
- **Technology**: Node.js 20 + Fastify + TypeScript
- **Build**: Production build in node:20-alpine
- **Port**: 3001 (internal)
- **Networks**: backend, database
- **Dependencies**: PostgreSQL, Redis, Platform
- **Health Check**: `http://localhost:3001/health` (30s interval)
- **Configuration**:
- `/app/config/production.yml` - Main config
- `/app/config/shared.yml` - Shared config
- `/run/secrets/*` - Secret files (K8s pattern)
- **Secrets**:
- `postgres-password` - Database password
- `platform-vehicles-api-key` - Platform service auth
- `auth0-client-secret` - Auth0 M2M secret
- `google-maps-api-key` - Maps API key
- **Storage**: `/app/data/documents` - Document uploads
### PostgreSQL (Primary Database)
- **Image**: postgres:15-alpine
- **Database**: motovaultpro
- **Port**: 5432 (exposed for development)
- **Networks**: database (internal)
- **User**: postgres
- **Password**: File-based secret (`/run/secrets/postgres-password`)
- **Health Check**: `pg_isready -U postgres` (10s interval)
- **Storage**: Named volume `mvp_postgres_data`
- **Schemas**:
- `public` - Application data (user-scoped)
- `vehicles` - Platform vehicle data (shared)
### Redis (Cache Layer)
- **Image**: redis:7-alpine
- **Port**: 6379 (exposed for development)
- **Networks**: database (internal)
- **Persistence**: AOF enabled (`--appendonly yes`)
- **Health Check**: `redis-cli ping` (10s interval)
- **Storage**: Named volume `mvp_redis_data`
- **Usage**:
- Vehicle data caching (year-based hierarchy)
- Session storage (future)
- Rate limiting (future)
### Platform Module (Vehicle Data)
- **Technology**: TypeScript feature capsule inside `backend/src/features/platform/`
- **Runtime**: Shares the `mvp-backend` Fastify container
- **Dependencies**: PostgreSQL, Redis (accessed via backend connection pool)
- **Deployment**: Bundled with backend build; no separate container or port
- **Health**: Covered by backend `/health` endpoint and feature-specific logs
- **Configuration**:
- `backend/src/features/platform/domain/*.ts` - Business logic
- `backend/src/features/platform/data/*.ts` - Database + vPIC integration
- **Secrets**:
- Reuses backend secrets (PostgreSQL, Auth0, etc.)
- **Purpose**:
- Vehicle make/model/trim/engine data
- VIN decoding (planned)
- Standardized vehicle information
## Platform Module Integration
### Current Architecture
Platform capabilities now run **in-process** within the backend as a feature capsule. This delivers:
- **Shared Language & Tooling**: TypeScript across the stack
- **Centralized Caching**: Reuses backend Redis helpers for year-based lookups
- **Simplified Operations**: No extra container to build, scale, or monitor
### Shared Infrastructure
- **Database**: Uses the backend connection pool against `mvp-postgres`
- **Cache**: Shares the backend Redis client (`mvp-redis`)
- **Runtime**: Packaged with the `mvp-backend` container and Fastify plugins
- **Secrets**: Relies on the same secret files as the backend (PostgreSQL, Auth0, etc.)
### Communication Pattern
```typescript
// Vehicles feature pulling platform data via domain services
const platformService = new PlatformVehicleDataService({
db: postgresPool,
cache: redisClient
});
const makes = await platformService.getMakes({ year: 2024 });
```
### Ongoing Work
- Continue migrating remaining FastAPI utilities into TypeScript where needed
- Expand `/api/platform/*` endpoints as new lookup types are added
- Monitor backend logs for `platform` namespace entries to verify health
## Feature Capsule Architecture
### Organization Pattern
Features are **self-contained modules** within the backend service at `backend/src/features/[name]/`:
```
backend/src/features/
├── vehicles/ # Vehicle management
├── fuel-logs/ # Fuel tracking
├── maintenance/ # Service records
├── stations/ # Gas station locations
├── documents/ # Document storage
└── platform/ # Vehicle data + VIN decoding
```
### Feature Structure
Each feature follows a standardized structure:
```
feature-name/
├── README.md # Feature documentation
├── api/ # Route handlers
├── domain/ # Business logic
├── data/ # Data access layer
├── migrations/ # Database migrations
├── tests/ # Unit and integration tests
├── events/ # Event handlers (optional)
└── external/ # External service integrations (optional)
```
### Current Features
#### Vehicles
- **Purpose**: Vehicle inventory management
- **Tables**: `vehicles` (user-scoped)
- **Integration**: Platform service for make/model/trim data
- **Endpoints**: CRUD + dropdown data
#### Fuel Logs
- **Purpose**: Fuel purchase and efficiency tracking
- **Tables**: `fuel_logs` (user-scoped)
- **Integration**: Stations feature for location data
- **Endpoints**: CRUD + analytics
#### Maintenance
- **Purpose**: Service and maintenance record tracking
- **Tables**: `maintenance_records` (user-scoped)
- **Integration**: Vehicles feature for vehicle data
- **Endpoints**: CRUD + reminders
#### Stations
- **Purpose**: Gas station location and pricing
- **Tables**: `stations` (user-scoped)
- **Integration**: Google Maps API
- **Endpoints**: Search + favorites
#### Documents
- **Purpose**: Document storage and retrieval
- **Tables**: `documents` (user-scoped)
- **Storage**: Filesystem (`/app/data/documents/`)
- **Endpoints**: Upload + download + delete
## Data Flow
### Authentication via Auth0 JWT
```
1. Frontend → Auth0 Login
2. Auth0 → JWT Token (contains user_id in 'sub' claim)
3. Frontend → Backend (Authorization: Bearer <JWT>)
4. Backend → Validate JWT:
- Verify signature via Auth0 JWKS endpoint
- Check issuer: https://{AUTH0_DOMAIN}/
- Check audience: {AUTH0_AUDIENCE}
5. Backend → Extract user_id from token.sub
6. Backend → Execute user-scoped queries
```
### User ID Extraction
```typescript
// From auth.plugin.ts
await request.jwtVerify(); // Validates and populates request.user
const userId = request.user.sub; // Auth0 user ID (e.g., "auth0|123456")
```
### User-Scoped Data Access
All application data is isolated by `user_id`:
```sql
-- Example: Get user's vehicles
SELECT * FROM vehicles WHERE user_id = $1;
-- Example: Create fuel log (user_id inserted)
INSERT INTO fuel_logs (user_id, vehicle_id, gallons, cost, ...)
VALUES ($1, $2, $3, $4, ...);
-- Example: Soft delete (preserves audit trail)
UPDATE vehicles
SET deleted_at = NOW()
WHERE id = $1 AND user_id = $2;
```
### Data Isolation Strategy
- **Foreign Keys**: All user data tables have `user_id` foreign key
- **Query Scoping**: All queries filtered by authenticated user's ID
- **Soft Deletes**: `deleted_at` timestamp for audit trail
- **No Cascade Deletes**: Prevents accidental data loss
- **Index Strategy**: Composite indexes on (`user_id`, primary key)
### Cross-Feature Data Flow
```
1. User creates vehicle (Vehicles feature)
2. User logs fuel purchase (Fuel Logs feature)
- References vehicle_id
- References station_id (Stations feature)
3. User adds maintenance record (Maintenance feature)
- References vehicle_id
- Can attach documents (Documents feature)
```
## Configuration Management
### Kubernetes-Style Patterns
The application uses Kubernetes-inspired configuration patterns:
**ConfigMaps** (YAML files):
- `/app/config/production.yml` - Service-specific config
- `/app/config/shared.yml` - Cross-service config
**Secrets** (File-based):
- `/run/secrets/postgres-password` - Database credentials
- `/run/secrets/auth0-client-secret` - OAuth credentials
- `/run/secrets/google-maps-api-key` - External API keys
### Environment Variables
Used for service references and runtime configuration:
```yaml
NODE_ENV: production
CONFIG_PATH: /app/config/production.yml
SECRETS_DIR: /run/secrets
DATABASE_HOST: mvp-postgres
REDIS_HOST: mvp-redis
```
## Development Workflow
### Container Commands (via Makefile)
```bash
make start # Start all 5 containers
make stop # Stop all containers
make restart # Restart all containers
make rebuild # Rebuild and restart containers
make logs # View all container logs
make logs-backend # View backend logs only
make clean # Remove containers and volumes
```
### Health Monitoring
```bash
# Check container health
docker ps
# View specific service logs
docker logs mvp-backend -f
docker logs mvp-postgres -f
# Test health endpoints (via Traefik)
curl https://motovaultpro.com/api/health # Backend (includes platform module)
# Or from within backend container
docker compose exec mvp-backend curl http://localhost:3001/health
```
### Database Access
```bash
# PostgreSQL shell
make db-shell-app
# Execute SQL
docker exec -it mvp-postgres psql -U postgres -d motovaultpro
# View Redis data
docker exec -it mvp-redis redis-cli
```
## Security Architecture
### Authentication & Authorization
- **Provider**: Auth0 (OAuth 2.0 / OpenID Connect)
- **Token Type**: JWT (JSON Web Token)
- **Validation**: JWKS-based signature verification
- **Token Cache**: 1 hour TTL for Auth0 public keys
- **Issuer Validation**: Prevents token spoofing
- **Audience Validation**: API-specific tokens only
### Protected Resources
All API endpoints require valid JWT except:
- `/health` - Health check (priority routing)
- `/api/health` - API health check (bypass auth)
### Data Security
- **VIN Handling**: Check digit validation, no VIN in logs
- **User Isolation**: Queries filtered by authenticated `user_id`
- **Soft Deletes**: Audit trail preservation
- **No Cascading Deletes**: Manual data cleanup only
- **Encrypted Connections**: PostgreSQL SSL/TLS
### Infrastructure Security
- **Non-root Containers**: All services run as non-root users
- **Network Isolation**: Internal database network
- **Secret Management**: File-based secrets (K8s pattern)
- **No Hardcoded Credentials**: Environment and file injection only
## Deployment Strategy
### Production Environment
- **Container Orchestration**: Docker Compose (current) → Kubernetes (future)
- **Service Discovery**: Traefik with Docker provider
- **TLS**: Automatic certificate management via Traefik
- **Scaling**: Single instance per service (MVP phase)
- **Monitoring**: Container health checks + log aggregation
### Zero-Downtime Deployment
```bash
# Build new images
make rebuild
# Traefik handles traffic routing during restart
# Health checks ensure services are ready before traffic
```
## Observability
### Logging Strategy
- **Format**: Structured JSON logging
- **Levels**: ERROR, WARN, INFO, DEBUG
- **Context**: Request ID, User ID (truncated), Service name
- **Aggregation**: Docker logs → Future: ELK/Loki stack
### Health Checks
Every service exposes health endpoints:
- **Backend**: `GET /health` - Database + Redis connectivity
- **Platform**: `GET /health` - Database + Redis connectivity
- **Frontend**: Nginx status check
- **PostgreSQL**: `pg_isready`
- **Redis**: `redis-cli ping`
### Metrics (Future)
- Request rate and latency
- Database query performance
- Cache hit rates
- Error rates by endpoint
## Performance Considerations
### Caching Strategy
- **Vehicle Data**: Year-based hierarchical caching in Redis
- **JWT Keys**: 1-hour cache for Auth0 public keys
- **Database Queries**: Indexed by (`user_id`, primary key)
### Database Optimization
- **Connection Pooling**: Fastify PostgreSQL plugin
- **Prepared Statements**: SQL injection prevention + performance
- **Indexes**: Composite indexes on frequently queried columns
- **Query Scoping**: All queries filtered by `user_id` for data locality
### Horizontal Scaling (Future)
- **Stateless Services**: Backend and Platform can scale horizontally
- **Shared State**: PostgreSQL and Redis as centralized state
- **Load Balancing**: Traefik distributes traffic across instances
## Related Documentation
- Feature Documentation: `backend/src/features/{feature}/README.md`
- Platform Architecture: `docs/PLATFORM-SERVICES.md`
- Security Details: `docs/SECURITY.md`
- Database Schema: `docs/DATABASE-SCHEMA.md`
- Testing Guide: `docs/TESTING.md`
- Vehicles API: `docs/VEHICLES-API.md`
- Development Commands: `Makefile`