Docs Cleanup

This commit is contained in:
Eric Gullickson
2025-11-02 10:34:43 -06:00
parent a0748ced5b
commit 3693ce5761
60 changed files with 885 additions and 6815 deletions

View File

@@ -60,7 +60,8 @@
"Bash(tree:*)", "Bash(tree:*)",
"Bash(npm run lint)", "Bash(npm run lint)",
"Bash(cat:*)", "Bash(cat:*)",
"Bash(./scripts/export-database.sh --help)" "Bash(./scripts/export-database.sh --help)",
"Bash(xargs:*)"
], ],
"deny": [] "deny": []
} }

View File

@@ -7,14 +7,12 @@ VITE_AUTH0_DOMAIN=motovaultpro.us.auth0.com
VITE_AUTH0_CLIENT_ID=yspR8zdnSxmV8wFIghHynQ08iXAPoQJ3 VITE_AUTH0_CLIENT_ID=yspR8zdnSxmV8wFIghHynQ08iXAPoQJ3
VITE_AUTH0_AUDIENCE=https://api.motovaultpro.com VITE_AUTH0_AUDIENCE=https://api.motovaultpro.com
VITE_API_BASE_URL=/api VITE_API_BASE_URL=/api
VITE_TENANT_ID=admin
# Docker Compose Development Configuration # Docker Compose Development Configuration
# These variables are used by docker-compose for container build args only # These variables are used by docker-compose for container build args only
AUTH0_DOMAIN=motovaultpro.us.auth0.com AUTH0_DOMAIN=motovaultpro.us.auth0.com
AUTH0_CLIENT_ID=yspR8zdnSxmV8wFIghHynQ08iXAPoQJ3 AUTH0_CLIENT_ID=yspR8zdnSxmV8wFIghHynQ08iXAPoQJ3
AUTH0_AUDIENCE=https://api.motovaultpro.com AUTH0_AUDIENCE=https://api.motovaultpro.com
TENANT_ID=admin
# NOTE: Backend services no longer use this file # NOTE: Backend services no longer use this file
# Backend configuration comes from: # Backend configuration comes from:

View File

@@ -1 +0,0 @@
CLAUDE.md

View File

@@ -16,7 +16,7 @@
- Core Backend Modules: `backend/src/core/` (see `backend/src/core/README.md`). - Core Backend Modules: `backend/src/core/` (see `backend/src/core/README.md`).
- Frontend Overview: `frontend/README.md`. - Frontend Overview: `frontend/README.md`.
- URLs and Hosts: - URLs and Hosts:
- Frontend: `https://admin.motovaultpro.com` - Frontend: `https://motovaultpro.com`
- Backend health: `http://localhost:3001/health` - Backend health: `http://localhost:3001/health`
- Add to `/etc/hosts`: `127.0.0.1 motovaultpro.com admin.motovaultpro.com` - Add to `/etc/hosts`: `127.0.0.1 motovaultpro.com`

View File

@@ -25,5 +25,5 @@ make test # backend + frontend tests
- Backend core: `backend/src/core/README.md` - Backend core: `backend/src/core/README.md`
## URLs and Hosts ## URLs and Hosts
- Frontend: `https://admin.motovaultpro.com` - Frontend: `https://motovaultpro.com`
- Backend health: `http://localhost:3001/health` - Backend health: `http://localhost:3001/health`

View File

@@ -53,7 +53,7 @@ make test
- `config-loader.ts` - Environment variable loading and validation - `config-loader.ts` - Environment variable loading and validation
- `database.ts` - PostgreSQL connection pool - `database.ts` - PostgreSQL connection pool
- `redis.ts` - Redis client and cache service - `redis.ts` - Redis client and cache service
- `tenant.ts` - Tenant configuration utilities - `user-context.ts` - User context extraction utilities
### Security (Fastify Plugins) ### Security (Fastify Plugins)
- `src/core/plugins/auth.plugin.ts` - Auth0 JWT via JWKS (@fastify/jwt + get-jwks) - `src/core/plugins/auth.plugin.ts` - Auth0 JWT via JWKS (@fastify/jwt + get-jwks)
@@ -64,7 +64,7 @@ make test
- `logger.ts` - Structured logging with Winston - `logger.ts` - Structured logging with Winston
### Middleware ### Middleware
- `src/core/middleware/tenant.ts` - Tenant extraction and validation - `src/core/middleware/user-context.ts` - User ID extraction from JWT
### Storage ### Storage
- `src/core/storage/` - Storage abstractions - `src/core/storage/` - Storage abstractions

View File

@@ -4,7 +4,7 @@
- `config-loader.ts` — Load and validate environment variables - `config-loader.ts` — Load and validate environment variables
- `database.ts` — PostgreSQL connection pool - `database.ts` — PostgreSQL connection pool
- `redis.ts` — Redis client and cache helpers - `redis.ts` — Redis client and cache helpers
- `tenant.ts` — Tenant configuration utilities - `user-context.ts` — User context utilities
## Plugins (`src/core/plugins/`) ## Plugins (`src/core/plugins/`)
- `auth.plugin.ts` — Auth0 JWT via JWKS (@fastify/jwt, get-jwks) - `auth.plugin.ts` — Auth0 JWT via JWKS (@fastify/jwt, get-jwks)
@@ -15,7 +15,7 @@
- `logger.ts` — Structured logging (Winston) - `logger.ts` — Structured logging (Winston)
## Middleware ## Middleware
- `middleware/tenant.ts`Tenant extraction/validation - `middleware/user-context.ts`User ID extraction from JWT
## Storage (`src/core/storage/`) ## Storage (`src/core/storage/`)
- `storage.service.ts` — Storage abstraction - `storage.service.ts` — Storage abstraction

View File

@@ -21,7 +21,7 @@ Secure vehicle document management with S3-compatible storage. Metadata and file
- **tests/** - All feature tests - **tests/** - All feature tests
## Dependencies ## Dependencies
- Internal: core/auth, core/middleware/tenant, core/storage - Internal: core/auth, core/middleware/user-context, core/storage
- Database: documents table - Database: documents table
## Quick Commands ## Quick Commands

View File

@@ -1,7 +1,6 @@
# MotoVaultPro application ConfigMap template # MotoVaultPro application ConfigMap template
server: server:
port: 3001 port: 3001
tenant_id: admin
database: database:
host: admin-postgres host: admin-postgres

View File

@@ -1,39 +0,0 @@
===========================================
MotoVaultPro Database Import Instructions
===========================================
Export Details:
- Export Date: Sun Nov 2 09:36:30 CST 2025
- Format: sql
- Compressed: true
- File: /Users/egullickson/Documents/Technology/coding/motovaultpro/database-exports/schema_20251102.sql.gz
Import Instructions:
--------------------
1. Copy the export file to your target server:
scp /Users/egullickson/Documents/Technology/coding/motovaultpro/database-exports/schema_20251102.sql.gz user@server:/path/to/import/
2. Import the database (compressed SQL):
# Using Docker:
gunzip -c /path/to/import/schema_20251102.sql.gz | docker exec -i mvp-postgres psql -U postgres -d motovaultpro
# Direct PostgreSQL:
gunzip -c /path/to/import/schema_20251102.sql.gz | psql -U postgres -d motovaultpro
Notes:
------
- The -c flag drops existing database objects before recreating them
- Ensure the target database exists before importing
- For production imports, always test on a staging environment first
- Consider creating a backup of the target database before importing
Create target database:
-----------------------
docker exec -i mvp-postgres psql -U postgres -c "CREATE DATABASE motovaultpro;"
Or if database exists and you want to start fresh:
--------------------------------------------------
docker exec -i mvp-postgres psql -U postgres -c "DROP DATABASE IF EXISTS motovaultpro;"
docker exec -i mvp-postgres psql -U postgres -c "CREATE DATABASE motovaultpro;"

View File

@@ -1,11 +0,0 @@
{
"export_timestamp": "2025-11-02T15:36:30Z",
"database_name": "motovaultpro",
"export_format": "sql",
"compressed": true,
"schema_included": true,
"data_included": false,
"postgresql_version": "PostgreSQL 15.14 on aarch64-unknown-linux-musl, compiled by gcc (Alpine 14.2.0) 14.2.0, 64-bit",
"file_path": "/Users/egullickson/Documents/Technology/coding/motovaultpro/database-exports/schema_20251102.sql.gz",
"file_size": "8.0K"
}

View File

@@ -48,7 +48,6 @@ services:
container_name: mvp-frontend container_name: mvp-frontend
restart: unless-stopped restart: unless-stopped
environment: environment:
VITE_TENANT_ID: ${TENANT_ID:-admin}
VITE_API_BASE_URL: /api VITE_API_BASE_URL: /api
VITE_AUTH0_DOMAIN: ${VITE_AUTH0_DOMAIN:-motovaultpro.us.auth0.com} VITE_AUTH0_DOMAIN: ${VITE_AUTH0_DOMAIN:-motovaultpro.us.auth0.com}
VITE_AUTH0_CLIENT_ID: ${VITE_AUTH0_CLIENT_ID:-yspR8zdnSxmV8wFIghHynQ08iXAPoQJ3} VITE_AUTH0_CLIENT_ID: ${VITE_AUTH0_CLIENT_ID:-yspR8zdnSxmV8wFIghHynQ08iXAPoQJ3}

View File

@@ -1,493 +0,0 @@
services:
# Traefik - Service Discovery and Load Balancing (replaces nginx-proxy)
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
command:
- --configFile=/etc/traefik/traefik.yml
ports:
- "80:80"
- "443:443"
- "8080:8080" # Dashboard
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./config/traefik/traefik.yml:/etc/traefik/traefik.yml:ro
- ./config/traefik/middleware.yml:/etc/traefik/middleware.yml:ro
- ./certs:/certs:ro
- traefik_data:/data
networks:
- frontend
- backend
healthcheck:
test: ["CMD", "traefik", "healthcheck"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik-dashboard.rule=Host(`traefik.motovaultpro.local`)"
- "traefik.http.routers.traefik-dashboard.tls=true"
- "traefik.http.services.traefik-dashboard.loadbalancer.server.port=8080"
- "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$2y$$10$$foobar"
# Platform Services - Landing Page
mvp-platform-landing:
build:
context: ./mvp-platform-services/landing
dockerfile: Dockerfile
args:
VITE_AUTH0_DOMAIN: ${AUTH0_DOMAIN:-motovaultpro.us.auth0.com}
VITE_AUTH0_CLIENT_ID: ${AUTH0_CLIENT_ID:-yspR8zdnSxmV8wFIghHynQ08iXAPoQJ3}
VITE_TENANTS_API_URL: http://mvp-platform-tenants:8000
container_name: mvp-platform-landing
restart: unless-stopped
environment:
VITE_AUTH0_DOMAIN: ${AUTH0_DOMAIN:-motovaultpro.us.auth0.com}
VITE_AUTH0_CLIENT_ID: ${AUTH0_CLIENT_ID:-yspR8zdnSxmV8wFIghHynQ08iXAPoQJ3}
VITE_TENANTS_API_URL: http://mvp-platform-tenants:8000
networks:
- frontend
depends_on:
- mvp-platform-tenants
- traefik
healthcheck:
test: ["CMD-SHELL", "curl -s http://localhost:3000 || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
labels:
- "traefik.enable=true"
- "traefik.http.routers.landing.rule=Host(`motovaultpro.com`)"
- "traefik.http.routers.landing.tls=true"
# - "traefik.http.routers.landing.middlewares=frontend-chain@file"
- "traefik.http.routers.landing.priority=10"
- "traefik.http.services.landing.loadbalancer.server.port=3000"
- "traefik.http.services.landing.loadbalancer.healthcheck.path=/"
- "traefik.http.services.landing.loadbalancer.healthcheck.interval=30s"
- "traefik.http.services.landing.loadbalancer.passhostheader=true"
# Platform Services - Tenants API
mvp-platform-tenants:
build:
context: ./mvp-platform-services/tenants
dockerfile: docker/Dockerfile.api
container_name: mvp-platform-tenants
restart: unless-stopped
environment:
# Core configuration (K8s pattern)
NODE_ENV: production
CONFIG_PATH: /app/config/production.yml
SECRETS_DIR: /run/secrets
SERVICE_NAME: mvp-platform-tenants
# Database connection (temporary fix until k8s config loader implemented)
DATABASE_URL: postgresql://platform_user:platform123@platform-postgres:5432/platform
volumes:
# Configuration files (K8s ConfigMap equivalent)
- ./config/platform/production.yml:/app/config/production.yml:ro
- ./config/shared/production.yml:/app/config/shared.yml:ro
# Secrets (K8s Secrets equivalent)
- ./secrets/platform/platform-db-password.txt:/run/secrets/postgres-password:ro
- ./secrets/platform/tenants-api-key.txt:/run/secrets/api-key:ro
- ./secrets/platform/allowed-service-tokens.txt:/run/secrets/allowed-service-tokens:ro
networks:
- backend
- platform
depends_on:
- platform-postgres
- platform-redis
healthcheck:
test:
- CMD-SHELL
- "python -c \"import urllib.request,sys;\ntry:\n with urllib.request.urlopen('http://localhost:8000/health', timeout=3) as r:\n sys.exit(0 if r.getcode()==200 else 1)\nexcept Exception:\n sys.exit(1)\n\""
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
labels:
- "traefik.enable=true"
- "traefik.docker.network=motovaultpro_backend"
- "traefik.http.routers.tenants-api.rule=Host(`admin.motovaultpro.com`) && PathPrefix(`/api/platform/tenants`)"
- "traefik.http.routers.tenants-api.tls=true"
# - "traefik.http.routers.tenants-api.middlewares=platform-chain@file"
- "traefik.http.routers.tenants-api.priority=25"
- "traefik.http.services.tenants-api.loadbalancer.server.port=8000"
- "traefik.http.services.tenants-api.loadbalancer.healthcheck.path=/health"
- "traefik.http.services.tenants-api.loadbalancer.healthcheck.interval=30s"
- "traefik.http.services.tenants-api.loadbalancer.passhostheader=true"
# Platform Services - Vehicles API
mvp-platform-vehicles-api:
build:
context: ./mvp-platform-services/vehicles
dockerfile: docker/Dockerfile.api
container_name: mvp-platform-vehicles-api
restart: unless-stopped
environment:
# Core configuration loaded from files
NODE_ENV: production
CONFIG_PATH: /app/config/production.yml
SECRETS_DIR: /run/secrets
SERVICE_NAME: mvp-platform-vehicles-api
volumes:
# Configuration files (K8s ConfigMap equivalent)
- ./config/platform/production.yml:/app/config/production.yml:ro
- ./config/shared/production.yml:/app/config/shared.yml:ro
# Secrets (K8s Secrets equivalent)
- ./secrets/platform/vehicles-db-password.txt:/run/secrets/postgres-password:ro
- ./secrets/platform/vehicles-api-key.txt:/run/secrets/api-key:ro
- ./secrets/platform/allowed-service-tokens.txt:/run/secrets/allowed-service-tokens:ro
networks:
- backend
- platform
depends_on:
- mvp-platform-vehicles-db
- mvp-platform-vehicles-redis
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
labels:
- "traefik.enable=true"
- "traefik.docker.network=motovaultpro_backend"
- "traefik.http.routers.vehicles-api.rule=Host(`admin.motovaultpro.com`) && PathPrefix(`/api/platform/vehicles`)"
# Removed temporary direct routes - admin-backend now handles API gateway
- "traefik.http.routers.vehicles-api.tls=true"
# - "traefik.http.routers.vehicles-api.middlewares=platform-chain@file"
- "traefik.http.routers.vehicles-api.priority=25"
- "traefik.http.services.vehicles-api.loadbalancer.server.port=8000"
- "traefik.http.services.vehicles-api.loadbalancer.healthcheck.path=/health"
- "traefik.http.services.vehicles-api.loadbalancer.healthcheck.interval=30s"
- "traefik.http.services.vehicles-api.loadbalancer.passhostheader=true"
# Application Services - Backend API
admin-backend:
build:
context: ./backend
dockerfile: Dockerfile
cache_from:
- node:20-alpine
container_name: admin-backend
restart: unless-stopped
environment:
# Core configuration (K8s pattern)
NODE_ENV: production
CONFIG_PATH: /app/config/production.yml
SECRETS_DIR: /run/secrets
volumes:
# Configuration files (K8s ConfigMap equivalent)
- ./config/app/production.yml:/app/config/production.yml:ro
- ./config/shared/production.yml:/app/config/shared.yml:ro
# Secrets (K8s Secrets equivalent)
- ./secrets/app/postgres-password.txt:/run/secrets/postgres-password:ro
- ./secrets/app/minio-access-key.txt:/run/secrets/minio-access-key:ro
- ./secrets/app/minio-secret-key.txt:/run/secrets/minio-secret-key:ro
- ./secrets/app/platform-vehicles-api-key.txt:/run/secrets/platform-vehicles-api-key:ro
- ./secrets/app/auth0-client-secret.txt:/run/secrets/auth0-client-secret:ro
- ./secrets/app/google-maps-api-key.txt:/run/secrets/google-maps-api-key:ro
networks:
- backend
- database
- platform
- egress # External connectivity for Auth0 JWT validation
depends_on:
- admin-postgres
- admin-redis
- admin-minio
- mvp-platform-vehicles-api
- mvp-platform-tenants
healthcheck:
test:
- CMD-SHELL
- node -e "require('http').get('http://localhost:3001/health', r => process.exit(r.statusCode===200?0:1)).on('error', () => process.exit(1))"
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
labels:
- "traefik.enable=true"
- "traefik.docker.network=motovaultpro_backend"
# Main API router for admin tenant (correct multi-tenant architecture)
- "traefik.http.routers.admin-api.rule=Host(`admin.motovaultpro.com`) && PathPrefix(`/api`)"
- "traefik.http.routers.admin-api.tls=true"
# - "traefik.http.routers.admin-api.middlewares=api-chain@file"
- "traefik.http.routers.admin-api.priority=20"
# Health check router for admin tenant (bypass auth)
- "traefik.http.routers.admin-health.rule=Host(`admin.motovaultpro.com`) && Path(`/api/health`)"
- "traefik.http.routers.admin-health.tls=true"
# - "traefik.http.routers.admin-health.middlewares=health-check-chain@file"
- "traefik.http.routers.admin-health.priority=30"
# Service configuration
- "traefik.http.services.admin-api.loadbalancer.server.port=3001"
- "traefik.http.services.admin-api.loadbalancer.healthcheck.path=/health"
- "traefik.http.services.admin-api.loadbalancer.healthcheck.interval=30s"
- "traefik.http.services.admin-api.loadbalancer.healthcheck.timeout=10s"
# Circuit breaker and retries
- "traefik.http.services.admin-api.loadbalancer.passhostheader=true"
# Application Services - Frontend SPA
admin-frontend:
build:
context: ./frontend
dockerfile: Dockerfile
cache_from:
- node:20-alpine
- nginx:alpine
args:
VITE_AUTH0_DOMAIN: ${VITE_AUTH0_DOMAIN:-motovaultpro.us.auth0.com}
VITE_AUTH0_CLIENT_ID: ${VITE_AUTH0_CLIENT_ID:-yspR8zdnSxmV8wFIghHynQ08iXAPoQJ3}
VITE_AUTH0_AUDIENCE: ${VITE_AUTH0_AUDIENCE:-https://api.motovaultpro.com}
VITE_API_BASE_URL: ${VITE_API_BASE_URL:-/api}
container_name: admin-frontend
restart: unless-stopped
environment:
VITE_TENANT_ID: ${TENANT_ID:-admin}
VITE_API_BASE_URL: /api
VITE_AUTH0_DOMAIN: ${VITE_AUTH0_DOMAIN:-motovaultpro.us.auth0.com}
VITE_AUTH0_CLIENT_ID: ${VITE_AUTH0_CLIENT_ID:-yspR8zdnSxmV8wFIghHynQ08iXAPoQJ3}
VITE_AUTH0_AUDIENCE: ${VITE_AUTH0_AUDIENCE:-https://api.motovaultpro.com}
networks:
- frontend
depends_on:
- admin-backend
healthcheck:
test: ["CMD-SHELL", "curl -s http://localhost:3000 || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
labels:
- "traefik.enable=true"
- "traefik.http.routers.admin-app.rule=Host(`admin.motovaultpro.com`) && !PathPrefix(`/api`)"
- "traefik.http.routers.admin-app.tls=true"
# - "traefik.http.routers.admin-app.middlewares=frontend-chain@file"
- "traefik.http.routers.admin-app.priority=10"
- "traefik.http.services.admin-app.loadbalancer.server.port=3000"
- "traefik.http.services.admin-app.loadbalancer.healthcheck.path=/"
- "traefik.http.services.admin-app.loadbalancer.healthcheck.interval=30s"
- "traefik.http.services.admin-app.loadbalancer.passhostheader=true"
# Database Services - Application PostgreSQL
admin-postgres:
image: postgres:15-alpine
container_name: admin-postgres
restart: unless-stopped
environment:
POSTGRES_DB: motovaultpro
POSTGRES_USER: postgres
POSTGRES_PASSWORD_FILE: /run/secrets/postgres-password
POSTGRES_INITDB_ARGS: --encoding=UTF8
volumes:
- admin_postgres_data:/var/lib/postgresql/data
# Secrets (K8s Secrets equivalent)
- ./secrets/app/postgres-password.txt:/run/secrets/postgres-password:ro
networks:
- database
ports:
- "5432:5432" # Development access only
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
# Database Services - Application Redis
admin-redis:
image: redis:7-alpine
container_name: admin-redis
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- admin_redis_data:/data
networks:
- database
ports:
- "6379:6379" # Development access only
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
# Database Services - Object Storage
admin-minio:
image: minio/minio:latest
container_name: admin-minio
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER_FILE: /run/secrets/minio-access-key
MINIO_ROOT_PASSWORD_FILE: /run/secrets/minio-secret-key
volumes:
- admin_minio_data:/data
# Secrets (K8s Secrets equivalent)
- ./secrets/app/minio-access-key.txt:/run/secrets/minio-access-key:ro
- ./secrets/app/minio-secret-key.txt:/run/secrets/minio-secret-key:ro
networks:
- database
ports:
- "9000:9000" # Development access only
- "9001:9001" # Console access
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
# Platform Infrastructure - PostgreSQL
platform-postgres:
image: postgres:15-alpine
container_name: platform-postgres
restart: unless-stopped
environment:
POSTGRES_DB: platform
POSTGRES_USER: platform_user
POSTGRES_PASSWORD_FILE: /run/secrets/postgres-password
POSTGRES_INITDB_ARGS: --encoding=UTF8
volumes:
- platform_postgres_data:/var/lib/postgresql/data
- ./mvp-platform-services/tenants/sql/schema:/docker-entrypoint-initdb.d
# Secrets (K8s Secrets equivalent)
- ./secrets/platform/platform-db-password.txt:/run/secrets/postgres-password:ro
networks:
- platform
ports:
- "5434:5432" # Development access only
healthcheck:
test: ["CMD-SHELL", "pg_isready -U platform_user -d platform"]
interval: 10s
timeout: 5s
retries: 5
# Platform Infrastructure - Redis
platform-redis:
image: redis:7-alpine
container_name: platform-redis
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- platform_redis_data:/data
networks:
- platform
ports:
- "6381:6379" # Development access only
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
# Platform Services - Vehicles Database
mvp-platform-vehicles-db:
image: postgres:15-alpine
container_name: mvp-platform-vehicles-db
restart: unless-stopped
command: 'postgres
-c shared_buffers=4GB
-c work_mem=256MB
-c maintenance_work_mem=1GB
-c effective_cache_size=12GB
-c max_connections=100
-c checkpoint_completion_target=0.9
-c wal_buffers=256MB
-c max_wal_size=8GB
-c min_wal_size=2GB
-c synchronous_commit=off
-c full_page_writes=off
-c fsync=off
-c random_page_cost=1.1
-c seq_page_cost=1
-c max_worker_processes=8
-c max_parallel_workers=8
-c max_parallel_workers_per_gather=4
-c max_parallel_maintenance_workers=4'
environment:
POSTGRES_DB: vehicles
POSTGRES_USER: mvp_platform_user
POSTGRES_PASSWORD_FILE: /run/secrets/postgres-password
POSTGRES_INITDB_ARGS: --encoding=UTF8
volumes:
- platform_vehicles_data:/var/lib/postgresql/data
- ./mvp-platform-services/vehicles/sql/schema:/docker-entrypoint-initdb.d
# Secrets (K8s Secrets equivalent)
- ./secrets/platform/vehicles-db-password.txt:/run/secrets/postgres-password:ro
networks:
- platform
ports:
- "5433:5432" # Development access only
healthcheck:
test: ["CMD-SHELL", "pg_isready -U mvp_platform_user -d vehicles"]
interval: 10s
timeout: 5s
retries: 5
# Platform Services - Vehicles Redis
mvp-platform-vehicles-redis:
image: redis:7-alpine
container_name: mvp-platform-vehicles-redis
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- platform_vehicles_redis_data:/data
networks:
- platform
ports:
- "6380:6379" # Development access only
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
# Network Definition - 4-Tier Isolation
networks:
frontend:
driver: bridge
internal: false # Only for Traefik public access
labels:
- "com.motovaultpro.network=frontend"
- "com.motovaultpro.purpose=public-traffic-only"
backend:
driver: bridge
internal: true # Complete isolation from host
labels:
- "com.motovaultpro.network=backend"
- "com.motovaultpro.purpose=api-services"
database:
driver: bridge
internal: true # Application data isolation
labels:
- "com.motovaultpro.network=database"
- "com.motovaultpro.purpose=app-data-layer"
platform:
driver: bridge
internal: true # Platform microservices isolation
labels:
- "com.motovaultpro.network=platform"
- "com.motovaultpro.purpose=platform-services"
egress:
driver: bridge
internal: false # External connectivity for Auth0, APIs
labels:
- "com.motovaultpro.network=egress"
- "com.motovaultpro.purpose=external-api-access"
# Volume Definitions
volumes:
traefik_data: null
platform_postgres_data: null
platform_redis_data: null
admin_postgres_data: null
admin_redis_data: null
admin_minio_data: null
platform_vehicles_data: null
platform_vehicles_redis_data: null

View File

@@ -0,0 +1,524 @@
# 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
+-------------------+
| Platform |
| Python + FastAPI |
| Port: 8000 |
+-------------------+
|
+---------------------------------+
| |
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 to Platform Flow
```
1. Backend Feature → HTTP Request → Platform Service
- URL: http://mvp-platform:8000
- Headers: Authorization: Bearer <API_KEY>
2. Platform → Query PostgreSQL (vehicles schema)
3. Platform → Check/Update Redis Cache
4. Platform → Response → Backend
```
### 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 (Vehicle Data Service)
- **Technology**: Python 3.11 + FastAPI
- **Build**: Custom Dockerfile from `mvp-platform-services/vehicles/`
- **Port**: 8000 (internal)
- **Networks**: backend, database
- **Dependencies**: PostgreSQL, Redis
- **Health Check**: `wget http://localhost:8000/health` (30s interval)
- **Configuration**:
- `/app/config/production.yml` - Service config
- `/app/config/shared.yml` - Shared config
- **Secrets**:
- `postgres-password` - Shared database access
- **Purpose**:
- Vehicle make/model/trim/engine data
- VIN decoding (planned)
- Standardized vehicle information
## Platform Service Integration
### Current Architecture
The Platform service is a **separate Python container** that provides vehicle data capabilities to the backend. This separation exists for:
- **Technology Independence**: Python ecosystem for data processing
- **Specialized Caching**: Year-based hierarchical caching strategy
- **Resource Isolation**: Independent scaling and monitoring
### Shared Infrastructure
- **Database**: Both Backend and Platform use `mvp-postgres`
- **Cache**: Both services share `mvp-redis`
- **Network**: Connected via `backend` and `database` networks
- **Secrets**: Share database credentials
### Communication Pattern
```javascript
// Backend calls Platform via internal HTTP
const response = await fetch('http://mvp-platform:8000/api/v1/vehicles/makes?year=2024', {
headers: {
'Authorization': `Bearer ${platformApiKey}`
}
});
```
### Future Evolution
**Planned**: Absorb Platform service into Backend as a feature capsule
- Timeline: Post-MVP phase
- Approach: Rewrite Python service in Node.js
- Location: `backend/src/features/vehicle-platform/`
- Benefits: Simplified deployment, shared codebase, reduced containers
## 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
```
### 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/platform-vehicles-api-key` - Service auth
- `/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
PLATFORM_VEHICLES_API_URL: http://mvp-platform:8000
```
## Development Workflow
### Container Commands (via Makefile)
```bash
make start # Start all 6 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-platform -f
docker logs mvp-postgres -f
# Test health endpoints
curl http://localhost:3001/health # Backend
curl http://localhost:8000/health # Platform
```
### 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`

View File

@@ -91,8 +91,7 @@ Agent: Quality Enforcer Agent
6. Delete old code when replacing (no commented code) 6. Delete old code when replacing (no commented code)
7. Use meaningful variable names (`userID` not `id`) 7. Use meaningful variable names (`userID` not `id`)
8. ALL quality gates must pass (all green policy) 8. ALL quality gates must pass (all green policy)
9. Platform services are independent microservices 9. Feature capsules are self-contained modules
10. Feature capsules are self-contained modules
## Making Changes ## Making Changes
@@ -114,7 +113,6 @@ Agent: Quality Enforcer Agent
**Agent**: Platform Service Agent **Agent**: Platform Service Agent
- Service: `mvp-platform-services/{service}/` - Service: `mvp-platform-services/{service}/`
- API: `mvp-platform-services/{service}/api/` - API: `mvp-platform-services/{service}/api/`
- ETL: `mvp-platform-services/{service}/etl/`
- After changes: `make rebuild` then check service health - After changes: `make rebuild` then check service health
### Database Changes ### Database Changes
@@ -214,7 +212,6 @@ Each service is independent:
mvp-platform-services/{service}/ mvp-platform-services/{service}/
├── api/ # FastAPI application ├── api/ # FastAPI application
├── database/ # SQLAlchemy models + migrations ├── database/ # SQLAlchemy models + migrations
├── etl/ # Data pipelines
└── tests/ # Service tests └── tests/ # Service tests
``` ```
@@ -223,7 +220,6 @@ mvp-platform-services/{service}/
- **Auth**: Frontend uses Auth0, backend validates JWTs - **Auth**: Frontend uses Auth0, backend validates JWTs
- **Database**: PostgreSQL with user-isolated data (user_id scoping) - **Database**: PostgreSQL with user-isolated data (user_id scoping)
- **Platform APIs**: Authenticated via API keys (service-to-service) - **Platform APIs**: Authenticated via API keys (service-to-service)
- **File uploads**: MinIO S3-compatible storage
- **Caching**: Redis with feature-specific TTL strategies - **Caching**: Redis with feature-specific TTL strategies
- **Testing**: Jest (backend/frontend), pytest (platform services) - **Testing**: Jest (backend/frontend), pytest (platform services)
- **Docker-First**: All development in containers (production-only) - **Docker-First**: All development in containers (production-only)
@@ -269,312 +265,3 @@ mvp-platform-services/{service}/
- Context Loading: `.ai/context.json` - Context Loading: `.ai/context.json`
- Development Guidelines: `CLAUDE.md` - Development Guidelines: `CLAUDE.md`
- Feature Documentation: `backend/src/features/{feature}/README.md` - Feature Documentation: `backend/src/features/{feature}/README.md`
### REDESIGN PROMPT
---
You are the orchestration AI for the MotoVaultPro architecture simplification project. Your role is to coordinate
multiple specialized AI agents working in parallel to transform the application from a 14-container microservices
architecture to a streamlined 6-container stack.
## Your Mission
Execute the complete simplification plan documented in `docs/redesign/`. This involves:
- Removing multi-tenant architecture
- Replacing MinIO with filesystem storage
- Consolidating databases (3 PostgreSQL → 1)
- Consolidating caches (3 Redis → 1)
- Renaming all services to mvp-* convention
- Simplifying from 14 containers to 6
## Getting Started
1. **Read the master plan:**
- Start with `docs/redesign/README.md` for overview
- Review `docs/redesign/AGENT-MANIFEST.md` for agent assignments
- Study `docs/redesign/DEPENDENCY-GRAPH.md` for execution order
2. **Understand the agents:**
You will spawn 8 specialized agents across 5 waves:
- **Wave 1:** config-agent, docs-agent (parallel, no dependencies)
- **Wave 2:** infra-agent, backend-agent, storage-agent (parallel, after Wave 1)
- **Wave 3:** Continue Wave 2 agents + platform-agent
- **Wave 4:** frontend-agent (sequential, waits for backend-agent)
- **Wave 5:** test-agent (validates everything, runs last)
3. **Execute the plan:**
- Spawn agents using the Task tool with appropriate subagent_type
- Each agent has detailed instructions in `docs/redesign/PHASE-*.md` files
- Agents should update `docs/redesign/EXECUTION-STATE.json` as they work
- Monitor progress and coordinate between waves
## Critical Requirements
- **Follow the documentation exactly** - All procedures are documented in phase files
- **Respect dependencies** - Check DEPENDENCY-GRAPH.md before starting each wave
- **Validate each phase** - Use validation criteria in each PHASE-*.md file
- **Track state** - Update EXECUTION-STATE.json throughout execution
- **Be ready to rollback** - Use ROLLBACK-STRATEGY.md if phases fail
## Execution Strategy
Spawn agents in waves, NOT all at once:
**Wave 1 (Start immediately):**
Spawn config-agent to execute Phase 4 (Config Cleanup)
Spawn docs-agent to execute Phase 9 (Documentation Updates)
**Wave 2 (After config-agent completes):**
Spawn infra-agent to execute Phase 1 (Docker Compose)
Spawn backend-agent to execute Phase 2 (Remove Tenant)
Spawn storage-agent to execute Phase 3 (Filesystem Storage)
**Wave 3 (After Wave 2 phases complete):**
infra-agent continues with Phase 5 (Networks) and Phase 7 (Database)
backend-agent continues with Phase 6 (Backend Updates)
Spawn platform-agent to execute Phase 8 (Platform Service)
**Wave 4 (After backend-agent Phase 6 completes):**
Spawn frontend-agent to execute Phase 10 (Frontend Updates)
**Wave 5 (After ALL phases 1-10 complete):**
Spawn test-agent to execute Phase 11 (Testing and Validation)
## Success Criteria
The project is complete when:
- All 11 phases show "completed" status in EXECUTION-STATE.json
- test-agent reports all validations passing
- Exactly 6 containers running (mvp-traefik, mvp-frontend, mvp-backend, mvp-postgres, mvp-redis, mvp-platform)
- `make test` passes with no failures
- All features functional (auth, vehicles, documents, fuel-logs, maintenance, stations)
## Important Files
- `docs/redesign/README.md` - Master coordination guide
- `docs/redesign/AGENT-MANIFEST.md` - Agent assignments and timeline
- `docs/redesign/DEPENDENCY-GRAPH.md` - Execution dependencies
- `docs/redesign/FILE-MANIFEST.md` - All file changes (72 operations)
- `docs/redesign/VALIDATION-CHECKLIST.md` - Success criteria
- `docs/redesign/ROLLBACK-STRATEGY.md` - Recovery procedures
- `docs/redesign/PHASE-01.md` through `PHASE-11.md` - Detailed execution steps
## Your First Action
Read `docs/redesign/README.md` and `docs/redesign/AGENT-MANIFEST.md` to understand the full plan, then begin spawning
Wave 1 agents (config-agent and docs-agent).
Remember: You are the orchestrator. Your job is to spawn agents, monitor their progress, coordinate between waves, and
ensure the simplification completes successfully. Each agent has complete instructions in their phase documentation
files.
Begin execution now.
## REDESIGN CONTINUE PROMPT
---
You are resuming the MotoVaultPro architecture simplification project after an interruption. Your role is to assess the
current state, validate completed work, and continue execution from the correct point.
## Critical First Steps
1. **Assess Current State:**
Read `docs/redesign/EXECUTION-STATE.json` to determine:
- Which phases are completed
- Which phase was in progress when interrupted
- Which agents were running
- Any reported errors or failures
2. **Verify Completed Work:**
For each phase marked "completed" in EXECUTION-STATE.json, run the validation checks from the corresponding
`PHASE-*.md` file to confirm it actually completed successfully.
3. **Check System Health:**
```bash
# How many containers are running?
docker compose ps
# What's the current git status?
git status
# Are there any error logs?
docker compose logs --tail=50
Decision Tree
If EXECUTION-STATE.json exists and has data:
Scenario A: A phase shows "in_progress"
- The agent was interrupted mid-phase
- Check validation criteria for that phase
- If validation passes: Mark as completed, continue to next phase
- If validation fails: Decide whether to retry or rollback (see ROLLBACK-STRATEGY.md)
Scenario B: All "in_progress" phases show "completed"
- Determine which wave was active
- Identify the next wave to execute
- Spawn appropriate agents for next wave
Scenario C: A phase shows "failed"
- Review the error in EXECUTION-STATE.json
- Check docs/redesign/ROLLBACK-STRATEGY.md for that phase
- Decide: Fix and retry OR rollback that phase
- Do NOT proceed to dependent phases until fixed
Scenario D: Phases completed but validation failed
- Review docs/redesign/VALIDATION-CHECKLIST.md
- Identify what validation failed
- Fix the issue
- Re-run validation
- Continue when validated
If EXECUTION-STATE.json is empty/missing or all phases show "pending":
Start from the beginning:
- Initialize EXECUTION-STATE.json
- Begin with Wave 1 (config-agent, docs-agent)
- Follow normal execution flow
Resume Checklist
Before continuing, verify:
- Read EXECUTION-STATE.json
- Validated all "completed" phases
- Checked container health: docker compose ps
- Reviewed recent logs: docker compose logs --tail=100
- Identified which wave you're in
- Determined which agents need to spawn next
- No blocking errors or conflicts
Common Resume Scenarios
Scenario: "Wave 1 complete, Wave 2 interrupted"
EXECUTION-STATE.json shows:
- Phase 4 (config-agent): completed ✓
- Phase 9 (docs-agent): completed ✓
- Phase 1 (infra-agent): in_progress
- Phase 2 (backend-agent): pending
- Phase 3 (storage-agent): pending
Action:
1. Validate Phase 1 completion
2. If Phase 1 done: Mark complete, spawn agents for Phases 2, 3
3. If Phase 1 partial: Complete remaining steps from PHASE-01.md
4. Continue Wave 2 execution
Scenario: "All phases complete, testing interrupted"
EXECUTION-STATE.json shows:
- Phases 1-10: completed ✓
- Phase 11 (test-agent): in_progress
Action:
1. Run validation from PHASE-11.md
2. Check: docker compose ps (should show 6 containers)
3. Run: make test
4. If tests pass: Mark Phase 11 complete, project done!
5. If tests fail: Debug failures, fix, retry
Scenario: "Phase failed, need to rollback"
EXECUTION-STATE.json shows:
- Phase 8 (platform-agent): failed
- Error: "Cannot connect to mvp-postgres"
Action:
1. Review ROLLBACK-STRATEGY.md Phase 8 section
2. Execute rollback procedure
3. Fix root cause (check Phase 1, Phase 7 completion)
4. Retry Phase 8
5. Continue when successful
Resuming by Wave
If resuming in Wave 1:
- Check if config-agent (Phase 4) completed
- Check if docs-agent (Phase 9) completed
- If both done: Proceed to Wave 2
- If partial: Complete remaining work
If resuming in Wave 2:
- Validate Wave 1 completed (Phases 4, 9)
- Check status of Phases 1, 2, 3
- Spawn agents for incomplete phases
- Wait for all Wave 2 to complete before Wave 3
If resuming in Wave 3:
- Validate Waves 1 and 2 completed
- Check status of Phases 5, 6, 7, 8
- Continue or spawn agents as needed
- Ensure Phase 1 complete before starting Phase 8
If resuming in Wave 4:
- Validate Phase 6 (backend-agent) completed
- Check status of Phase 10 (frontend-agent)
- If incomplete: Spawn frontend-agent
- If complete: Proceed to Wave 5
If resuming in Wave 5:
- Validate ALL Phases 1-10 completed
- Run Phase 11 testing and validation
- This is the final phase
Key Commands for State Assessment
# Check EXECUTION-STATE.json
cat docs/redesign/EXECUTION-STATE.json | jq '.phases'
# Check container count (should end at 6)
docker compose ps --services | wc -l
# Check for completed phases
cat docs/redesign/EXECUTION-STATE.json | jq '.phases[] | select(.status == "completed") | .name'
# Check for failed/in_progress phases
cat docs/redesign/EXECUTION-STATE.json | jq '.phases[] | select(.status != "completed" and .status != "pending") |
{name, status, errors}'
# Quick validation
docker compose config # Should validate
make test # Should pass when complete
Your First Actions
1. Read and analyze: cat docs/redesign/EXECUTION-STATE.json
2. Check system state: docker compose ps
3. Determine position: Which wave are you in?
4. Validate completed work: Run validation for "completed" phases
5. Identify next steps: Which agents need to spawn?
6. Resume execution: Continue from the correct point
Important Notes
- Never skip validation - Always validate completed phases before continuing
- Never redo completed work - If a phase validates successfully, don't repeat it
- Update state religiously - Keep EXECUTION-STATE.json current
- Watch for cascading failures - A failed early phase blocks later phases
- Be ready to rollback - Sometimes rolling back and retrying is faster than debugging
Safety Protocol
If you're uncertain about the state:
1. Review VALIDATION-CHECKLIST.md for each "completed" phase
2. Run validation commands to verify actual state
3. Compare expected vs. actual (6 containers, 3 networks, etc.)
4. When in doubt: Validate, don't assume
Resume Now
Analyze the current state using the steps above, then continue execution from the appropriate point. Report your
findings and next actions before proceeding.
---

View File

@@ -1,6 +1,6 @@
# MotoVaultPro Documentation # MotoVaultPro Documentation
Project documentation hub for the hybrid platform (platform microservices) and modular monolith application. Project documentation hub for the 6-container single-tenant architecture with integrated platform service.
## Navigation ## Navigation
@@ -20,6 +20,6 @@ Project documentation hub for the hybrid platform (platform microservices) and m
## Notes ## Notes
- Canonical URLs: Frontend `https://admin.motovaultpro.com`, Backend health `http://localhost:3001/health`. - Canonical URLs: Frontend `https://motovaultpro.com`, Backend health `http://localhost:3001/health`.
- Hosts entry required: `127.0.0.1 motovaultpro.com admin.motovaultpro.com`. - Hosts entry required: `127.0.0.1 motovaultpro.com`.
- Feature test coverage: Basic test structure exists for vehicles and documents features; other features have placeholder tests. - Feature test coverage: Basic test structure exists for vehicles and documents features; other features have placeholder tests.

View File

@@ -19,7 +19,7 @@
### VIN Handling ### VIN Handling
- VIN validation using industry-standard check digit algorithm - VIN validation using industry-standard check digit algorithm
- VIN decoding via MVP Platform Vehicles Service (local FastAPI + Postgres) with caching - VIN decoding via integrated MVP Platform service (FastAPI) with shared database and caching
- No VIN storage in logs (mask as needed in logging) - No VIN storage in logs (mask as needed in logging)
### Database Security ### Database Security

View File

@@ -0,0 +1,334 @@
# MotoVaultPro Multi-Tenant Architecture Remnants Analysis
**Date:** November 2, 2025
**Status:** Very Thorough Exploration
**Finding:** Multi-tenant refactor complete in application code, but orphaned platform services and configuration remnants exist
---
## Executive Summary
The migration from 14-container multi-tenant architecture to 6-container single-tenant architecture is **CLEAN at the application level** but has **ORPHANED SERVICES AND CONFIGURATION** that should be addressed:
### Key Findings:
1.**Application code:** CLEAN - No tenant_id references in backend/src or frontend/src
2.**Core middleware:** DELETED - tenant.ts and tenant.ts middleware files removed
3.**Database schema:** CLEAN - No tenant_id columns in application tables
4. ⚠️ **Configuration:** PARTIAL - Legacy references in config and environment variables
5. ⚠️ **Platform services:** ORPHANED - mvp-platform-services/tenants and landing still present and deployed
6. ⚠️ **Documentation:** STALE - References to removed components still exist
---
## Detailed Findings by Category
### 1. CODE REFERENCES TO TENANT (PRIORITY: LOW - Cosmetic)
#### Backend Application Code
**Status:** ✅ CLEAN
- ✅ 0 occurrences of `tenant_id` in `/backend/src/**/*.ts`
- ✅ 0 occurrences of `tenantId` in `/backend/src/**/*.ts`
- ✅ 0 occurrences of `tenant` middleware imports in application code
-`auth.plugin.ts` (line 1-93) - JWT plugin only extracts `sub` and `roles`, no tenant_id
-`app.ts` (line 1-136) - No tenant middleware registration, no tenant routes
- ✅ Core README.md - References deleted tenant.ts (should be removed from docs)
**Findings:**
- File: `/Users/egullickson/Documents/Technology/coding/motovaultpro/backend/src/core/README.md`
- Line 7: "- `tenant.ts` — Tenant configuration utilities"
- Line 18: "- `middleware/tenant.ts` — Tenant extraction/validation"
- **Assessment:** Documentation references non-existent files (misleading, not a code issue)
---
### 2. ENVIRONMENT VARIABLES (PRIORITY: MEDIUM - Confusing)
#### Active Environment Variables with "TENANT"
**File:** `/Users/egullickson/Documents/Technology/coding/motovaultpro/.env.development`
- Line 10: `VITE_TENANT_ID=admin`
- Line 17: `TENANT_ID=admin`
- **Issue:** These variables are defined but NOT USED in the application
- Frontend build doesn't reference VITE_TENANT_ID (verified: 0 occurrences in frontend/src)
- Backend doesn't read TENANT_ID (verified: no usage in backend code)
- Docker-compose only references these in frontend build args (line 51)
- **Assessment:** Cargo-cult configuration - leftover from multi-tenant era
**File:** `/Users/egullickson/Documents/Technology/coding/motovaultpro/docker-compose.yml`
- Line 51: `VITE_TENANT_ID: ${TENANT_ID:-admin}` - Frontend build arg that's never used
- **Assessment:** Dead configuration, no impact but confusing
**File:** `/Users/egullickson/Documents/Technology/coding/motovaultpro/config/app/production.yml.example`
- Line 4: `tenant_id: admin` - Configuration schema still includes this
- **Assessment:** Example file only - not loaded at runtime but misleading for ops
---
### 3. DATABASE SCHEMA (PRIORITY: NONE - Clean)
**Status:** ✅ VERIFIED CLEAN
- Checked application PostgreSQL schema via migrations in `/backend/src/features/**/*migrations/*.sql`
- ✅ No `tenant_id` columns in any application tables
- ✅ All user data properly scoped to `user_id`
- ✅ Sample tables verified:
- `vehicles` - uses `user_id`, not `tenant_id`
- `fuel_logs` - uses `user_id`, not `tenant_id`
- `documents` - uses `user_id`, not `tenant_id`
- `maintenance_records` - uses `user_id`, not `tenant_id`
---
### 4. API ENDPOINTS (PRIORITY: NONE - Clean)
**Status:** ✅ VERIFIED CLEAN
- ✅ No `/tenant/` or `/tenants/` endpoints in application code
- ✅ No tenant-management routes registered
- ✅ All API routes are feature-based: `/api/vehicles`, `/api/documents`, `/api/fuel-logs`, etc.
- ✅ User scoping is implicit via JWT `sub` claim in `request.user.sub`
---
### 5. CONFIGURATION FILES (PRIORITY: MEDIUM - Clean up needed)
#### Production Config
**File:** `/Users/egullickson/Documents/Technology/coding/motovaultpro/config/app/production.yml.example`
```yaml
server:
port: 3001
tenant_id: admin # <-- UNUSED, should remove
```
- **Line 4:** `tenant_id: admin`
- **Issue:** Configuration key exists but is never read
- **Impact:** Example only, but misleading for operators
- **Recommendation:** Remove this line
#### Platform Config
**File:** `/Users/egullickson/Documents/Technology/coding/motovaultpro/config/platform/production.yml`
- No tenant references found in platform configuration
- ✅ Platform (vehicles API) is clean
---
### 6. MIDDLEWARE FOR TENANT ISOLATION (PRIORITY: NONE - Deleted)
**Status:** ✅ DELETED
-`/backend/src/core/middleware/tenant.ts` - DOES NOT EXIST
-`/backend/src/core/config/tenant.ts` - DOES NOT EXIST
-`/backend/src/features/tenant-management/` - DOES NOT EXIST
- ✅ No tenant middleware imports in app.ts
- ✅ No tenant middleware registration in app.ts
---
### 7. MULTI-TENANT PLATFORM SERVICES (PRIORITY: HIGH - Orphaned)
#### CRITICAL: Orphaned Platform Services Still Running in Production
**Status:** ⚠️ ORPHANED - These services are built, deployed, and running but NOT USED
##### mvp-platform-services/tenants
**Location:** `/Users/egullickson/Documents/Technology/coding/motovaultpro/mvp-platform-services/tenants/`
- **Purpose:** Multi-tenant management, signup approvals (NOT NEEDED - single-tenant now)
- **Status:** Still present and potentially running
- **Files:**
- `api/main.py` (100+ lines) - FastAPI application for tenant management
- `sql/schema/001_tenants_schema.sql` - Tenant database schema (separate from app)
- `AUTH0-CONFIG.md` - Multi-tenant Auth0 configuration
**Code References:**
- File: `api/main.py` - Complete multi-tenant service with:
- Models: `TenantCreate`, `TenantResponse`, `SignupRequest`, `SignupResponse`
- Endpoints: `GET /api/v1/tenants/{tenant_id}`, `PUT /api/v1/tenants/{tenant_id}`, `POST /api/v1/tenants/{tenant_id}/signups`
- Database: `CREATE TABLE tenants`, `CREATE TABLE tenant_signups`
- Auth0 integration: Extracts `tenant_id` from Auth0 JWT claims
**Assessment:**
- **Problem:** This entire service is multi-tenant focused and NOT NEEDED in single-tenant architecture
- **Impact:** Resource waste (container, database schema, memory), confusion for future maintainers
- **Priority:** HIGH - Should be deleted
##### mvp-platform-services/landing
**Location:** `/Users/egullickson/Documents/Technology/coding/motovaultpro/mvp-platform-services/landing/`
- **Purpose:** Multi-tenant landing/signup page for different tenants
- **Status:** Still present and potentially running
- **Files:**
- `src/App.tsx` - Routes to `/signup/:tenantId`
- `src/components/TenantSignup.tsx` - Tenant signup flow (references VITE_TENANTS_API_URL)
- `Dockerfile` - Builds landing page service
**Code References:**
- File: `src/App.tsx`
- Line 12: `<Route path="/signup/:tenantId" element={<TenantSignup />} />`
- **Purpose:** Route for tenant-specific signup (NOT NEEDED)
- File: `src/components/TenantSignup.tsx`
- Line 23: `${import.meta.env.VITE_TENANTS_API_URL}/api/v1/tenants/${tenantId}`
- **Purpose:** Calls orphaned tenants service API
**Assessment:**
- **Problem:** This landing page is for multi-tenant signup flow (register new tenant)
- **Impact:** Resource waste, confusion about signup flow (single-tenant should have simpler flow)
- **Priority:** HIGH - Should be deleted or consolidated into main landing
---
### 8. ORPHANED ENVIRONMENT VARIABLE REFERENCES (PRIORITY: HIGH)
#### VITE_TENANTS_API_URL
**Locations:**
1. `/Users/egullickson/Documents/Technology/coding/motovaultpro/mvp-platform-services/landing/src/vite-env.d.ts`
- Line: `readonly VITE_TENANTS_API_URL: string`
- **Issue:** Defined but landing page is not used
2. `/Users/egullickson/Documents/Technology/coding/motovaultpro/mvp-platform-services/landing/Dockerfile`
- `ARG VITE_TENANTS_API_URL`
- `ENV VITE_TENANTS_API_URL=${VITE_TENANTS_API_URL}`
- **Issue:** Build arg that's not used
3. `/Users/egullickson/Documents/Technology/coding/motovaultpro/docker-compose.yml`
- Referenced in platform service environment setup (no longer deployed)
- **Issue:** Docker-compose removed platform-tenants service but vars might still be elsewhere
#### VITE_TENANT_ID
**Locations:**
1. `/Users/egullickson/Documents/Technology/coding/motovaultpro/.env.development`
- Line 10: `VITE_TENANT_ID=admin`
- **Issue:** Never used in frontend code
2. `/Users/egullickson/Documents/Technology/coding/motovaultpro/docker-compose.yml`
- Line 51: `VITE_TENANT_ID: ${TENANT_ID:-admin}`
- **Issue:** Dead build arg
---
### 9. DOCUMENTATION WITH STALE REFERENCES (PRIORITY: LOW - Maintenance)
**Files with tenant references:**
1. **File:** `/Users/egullickson/Documents/Technology/coding/motovaultpro/backend/src/core/README.md`
- Lines 7, 18: References deleted tenant.ts files
- **Assessment:** Misleading documentation
- **Fix:** Remove lines 7 and 18
2. **File:** `/Users/egullickson/Documents/Technology/coding/motovaultpro/backend/src/features/documents/README.md`
- Line 24: References `core/middleware/tenant`
- **Assessment:** Outdated dependency documentation
- **Fix:** Remove tenant middleware reference
3. **File:** `/Users/egullickson/Documents/Technology/coding/motovaultpro/docs/redesign/` (multiple files)
- These are DESIGN DOCUMENTS describing the refactoring process
- **Assessment:** Historical documents, not application code
- **Fix:** Archive or document clearly as historical
---
## Summary Table
| Category | Finding | Status | Priority | Impact |
|----------|---------|--------|----------|--------|
| Backend Code | No tenant_id references | CLEAN | NONE | N/A |
| Frontend Code | No tenant_id references | CLEAN | NONE | N/A |
| Database Schema | No tenant_id columns | CLEAN | NONE | N/A |
| API Endpoints | No /tenant/ routes | CLEAN | NONE | N/A |
| Middleware | Deleted tenant middleware | DELETED | NONE | N/A |
| Environment Vars | VITE_TENANT_ID, TENANT_ID unused | ORPHANED | MEDIUM | Confusing |
| Config Files | production.yml.example has unused tenant_id | ORPHANED | MEDIUM | Confusing |
| Platform Tenants Service | Multi-tenant service still in repo and deployable | ORPHANED | HIGH | Resource waste |
| Platform Landing Service | Multi-tenant landing page still in repo | ORPHANED | HIGH | Resource waste |
| Core README.md | References deleted files | STALE | LOW | Confusing |
| Features README.md | References deleted middleware | STALE | LOW | Confusing |
---
## Recommendations by Priority
### PRIORITY 1 (HIGH) - Delete Orphaned Services
These should be removed from the codebase entirely:
1. **Delete `/mvp-platform-services/tenants/` directory**
- Multi-tenant signup service not needed
- Delete entire directory:
```bash
rm -rf mvp-platform-services/tenants/
```
2. **Delete or refactor `/mvp-platform-services/landing/` directory**
- Multi-tenant landing page not needed
- Consider: If single-tenant landing is needed, refactor completely
- If not needed: `rm -rf mvp-platform-services/landing/`
3. **Simplify `/mvp-platform-services/` structure**
- After deletions, only `vehicles/` should remain
- Consider if `/mvp-platform-services/` directory structure makes sense anymore
### PRIORITY 2 (MEDIUM) - Clean up Configuration
1. **Update `/config/app/production.yml.example`**
- Line 4: Remove `tenant_id: admin`
2. **Update `/.env.development`**
- Line 10: Remove `VITE_TENANT_ID=admin`
- Line 17: Remove `TENANT_ID=admin`
3. **Update `/docker-compose.yml`**
- Line 51: Remove `VITE_TENANT_ID` environment variable
- Verify no orphaned platform service references
### PRIORITY 3 (LOW) - Fix Documentation
1. **Update `/backend/src/core/README.md`**
- Remove line 7: `- `tenant.ts` — Tenant configuration utilities`
- Remove line 18: `- `middleware/tenant.ts` — Tenant extraction/validation`
2. **Update `/backend/src/features/documents/README.md`**
- Line 24: Remove `core/middleware/tenant` dependency
3. **Archive redesign documentation**
- Move `/docs/redesign/` to `/docs/archive/redesign/` if not actively maintained
---
## Files to Preserve (Not Affected)
These files are CLEAN and should be preserved:
- ✅ `/backend/src/**` - All feature code (vehicles, documents, fuel-logs, etc.)
- ✅ `/frontend/src/**` - All UI code
- ✅ `/mvp-platform-services/vehicles/**` - Vehicles platform service (still needed)
- ✅ `/docker-compose.yml` - Core structure is correct
- ✅ `/config/app/` - Mostly correct after line 4 removal
---
## Verification Commands
To verify this analysis is accurate, run these commands:
```bash
# Verify no tenant_id in application code
grep -r "tenant_id" backend/src/features/ --include="*.ts" --include="*.sql" | wc -l
# Expected: 0
# Verify no tenantId in frontend
grep -r "tenantId" frontend/src/ --include="*.ts" --include="*.tsx" | wc -l
# Expected: 0
# Verify tenant middleware deleted
ls -la backend/src/core/middleware/tenant.ts 2>&1
# Expected: "No such file or directory"
# Verify tenant config deleted
ls -la backend/src/core/config/tenant.ts 2>&1
# Expected: "No such file or directory"
# Check for orphaned services
ls -la mvp-platform-services/
# Current: landing tenants vehicles
# Should be: vehicles (after cleanup)
```
---
## Conclusion
**The multi-tenant refactor is architecturally successful** at the application level (0 tenant_id references in active code). However, **orphaned platform services and stale configuration create technical debt and confusion**.
**Recommended action:** Execute Priority 1 (delete orphaned services) and Priority 2 (clean configuration) to fully complete the refactor and prevent future confusion.

View File

@@ -3,7 +3,7 @@
This document explains the endtoend Vehicles API architecture after the platform service rebuild, how the MotoVaultPro app consumes it, how migrations/seeding work, and how to operate the stack in productiononly development. This document explains the endtoend Vehicles API architecture after the platform service rebuild, how the MotoVaultPro app consumes it, how migrations/seeding work, and how to operate the stack in productiononly development.
## Overview ## Overview
- Architecture: MotoVaultPro Application Service (Fastify + TS) consumes the MVP Platform Vehicles Service (FastAPI + Postgres + Redis). - Architecture: MotoVaultPro Application Service (Fastify + TS) consumes the MVP Platform service (FastAPI) with shared Postgres and Redis.
- Goal: Predictable year→make→model→trim→engine cascades, productiononly workflow, AIfriendly code layout and docs. - Goal: Predictable year→make→model→trim→engine cascades, productiononly workflow, AIfriendly code layout and docs.
## Platform Vehicles Service ## Platform Vehicles Service
@@ -52,8 +52,8 @@ Seed files under `mvp-platform-services/vehicles/sql/schema/`:
- 2017 Chevrolet Corvette Z06 Convertible → Engine LT4 (6.2L V8 SC) - 2017 Chevrolet Corvette Z06 Convertible → Engine LT4 (6.2L V8 SC)
Reapply seeds on an existing volume: Reapply seeds on an existing volume:
- `docker compose exec -T mvp-platform-vehicles-db psql -U mvp_platform_user -d vehicles -f /docker-entrypoint-initdb.d/005_seed_specific_vehicles.sql` - `docker compose exec -T mvp-postgres psql -U mvp_user -d mvp_db -f /docker-entrypoint-initdb.d/005_seed_specific_vehicles.sql`
- Clear platform cache: `docker compose exec -T mvp-platform-vehicles-redis sh -lc "redis-cli FLUSHALL"` - Clear platform cache: `docker compose exec -T mvp-redis sh -lc "redis-cli FLUSHALL"`
## MotoVaultPro Backend (Application Service) ## MotoVaultPro Backend (Application Service)
@@ -135,21 +135,22 @@ VIN/License rule
### Rebuild a single service ### Rebuild a single service
- Frontend: `docker compose up -d --build frontend` - Frontend: `docker compose up -d --build frontend`
- Backend: `docker compose up -d --build backend` - Backend: `docker compose up -d --build backend`
- Platform API: `docker compose up -d --build mvp-platform-vehicles-api` - Platform API: `docker compose up -d --build mvp-platform`
### Logs & Health ### Logs & Health
- Backend: `/health` shows status/feature list - Backend: `/health` shows status/feature list
- Platform: `/health` shows database/cache status - Platform: `/health` shows database/cache status
- Logs: - Logs:
- `make logs-backend`, `make logs-frontend` - `make logs-backend`, `make logs-frontend`
- `docker compose logs -f mvp-platform-vehicles-api` - `docker compose logs -f mvp-platform`
### Common Reset Sequences ### Common Reset Sequences
- Platform seed reapply (nondestructive): apply `005_seed_specific_vehicles.sql` and flush Redis cache. - Platform seed reapply (nondestructive): apply `005_seed_specific_vehicles.sql` and flush Redis cache.
- Platform reset (destructive only to platform DB/cache): - Platform reset (WARNING - DESTRUCTIVE to shared resources):
- `docker compose rm -sf mvp-platform-vehicles-db mvp-platform-vehicles-redis` - `docker compose rm -sf mvp-postgres mvp-redis`
- `docker volume rm motovaultpro_platform_vehicles_data motovaultpro_platform_vehicles_redis_data` - `docker volume rm motovaultpro_postgres_data motovaultpro_redis_data`
- `docker compose up -d mvp-platform-vehicles-db mvp-platform-vehicles-redis mvp-platform-vehicles-api` - `docker compose up -d mvp-postgres mvp-redis mvp-platform`
- Note: This will destroy ALL application data, not just platform data, as database and cache are shared
## Security Summary ## Security Summary
- Platform: `Authorization: Bearer ${API_KEY}` required on all `/api/v1/vehicles/*` endpoints. - Platform: `Authorization: Bearer ${API_KEY}` required on all `/api/v1/vehicles/*` endpoints.
@@ -164,7 +165,7 @@ VIN/License rule
- Check backend `/api/vehicles` 500s (migrations not run or DB unavailable). - Check backend `/api/vehicles` 500s (migrations not run or DB unavailable).
- Run `make migrate` or ensure backend container automigrate is succeeding; check `docker compose logs backend`. - Run `make migrate` or ensure backend container automigrate is succeeding; check `docker compose logs backend`.
- Dropdowns not updating after seed: - Dropdowns not updating after seed:
- Run specific seed SQL (see above) and `redis-cli FLUSHALL` on platform Redis. - Run specific seed SQL (see above) and `redis-cli FLUSHALL` on shared Redis (mvp-redis).
- Backend flapping on start after rebuild: - Backend flapping on start after rebuild:
- Ensure Postgres is up; the runner now waits/retries, but confirm logs. - Ensure Postgres is up; the runner now waits/retries, but confirm logs.

View File

@@ -1,412 +0,0 @@
# Agent Manifest - Parallel Execution Coordination
## Agent Roster
### Agent 1: infra-agent (Infrastructure Agent)
**Assigned Phases:** 1, 5, 7
**Focus:** Docker, networks, databases
**Estimated Duration:** 45-60 minutes
**Complexity:** High
**Responsibilities:**
- Phase 1: Rename containers and update docker-compose.yml
- Phase 5: Simplify network architecture (5 → 3 networks)
- Phase 7: Update database configurations
**Files Modified:**
- docker-compose.yml
- Network definitions
- Volume configurations
- Database connection strings
**Can Run in Parallel With:**
- config-agent
- docs-agent
- backend-agent (different files)
- storage-agent (different files)
**Must Wait For:**
- config-agent (Phase 4) before starting Phase 1
---
### Agent 2: backend-agent (Backend Agent)
**Assigned Phases:** 2, 6
**Focus:** Backend code removal and updates
**Estimated Duration:** 40-50 minutes
**Complexity:** Medium-High
**Responsibilities:**
- Phase 2: Remove multi-tenant architecture code
- Phase 6: Update service references and API clients
**Files Modified:**
- backend/src/core/middleware/tenant.ts (DELETE)
- backend/src/core/config/tenant.ts (DELETE)
- backend/src/features/tenant-management/ (DELETE entire directory)
- backend/src/app.ts (MODIFY)
- backend/src/features/vehicles/ (MODIFY)
- backend/src/core/plugins/auth.plugin.ts (MODIFY)
**Can Run in Parallel With:**
- infra-agent (different files)
- storage-agent (different files)
- platform-agent (different services)
- docs-agent
**Must Wait For:**
- config-agent (Phase 4)
---
### Agent 3: storage-agent (Storage Agent)
**Assigned Phases:** 3
**Focus:** MinIO to filesystem migration
**Estimated Duration:** 30-40 minutes
**Complexity:** Medium
**Responsibilities:**
- Phase 3: Replace MinIO with filesystem storage
**Files Modified:**
- backend/src/core/storage/adapters/filesystem.adapter.ts (CREATE)
- backend/src/core/storage/storage.service.ts (MODIFY)
- backend/src/features/documents/documents.controller.ts (MODIFY)
- backend/src/features/documents/documents.service.ts (MODIFY)
**Can Run in Parallel With:**
- backend-agent (different files)
- infra-agent (different scope)
- platform-agent
- docs-agent
**Must Wait For:**
- None (can start immediately)
---
### Agent 4: platform-agent (Platform Service Agent)
**Assigned Phases:** 8
**Focus:** mvp-platform service simplification
**Estimated Duration:** 35-45 minutes
**Complexity:** Medium-High
**Responsibilities:**
- Phase 8: Simplify mvp-platform service
**Files Modified:**
- mvp-platform-services/vehicles/ (all files)
- Remove ETL and MSSQL dependencies
- Update to use mvp-postgres and mvp-redis
**Can Run in Parallel With:**
- backend-agent (different codebase)
- storage-agent (different scope)
- docs-agent
**Must Wait For:**
- infra-agent Phase 1 (needs new container names)
---
### Agent 5: config-agent (Configuration Agent)
**Assigned Phases:** 4
**Focus:** Configuration and secrets cleanup
**Estimated Duration:** 20-30 minutes
**Complexity:** Low-Medium
**Responsibilities:**
- Phase 4: Clean up configuration files and secrets
**Files Modified:**
- config/app/production.yml (MODIFY)
- .env (MODIFY)
- secrets/app/ (DELETE MinIO and platform files)
- secrets/platform/ (DELETE entire directory)
**Can Run in Parallel With:**
- docs-agent
- Initial startup of all other agents
**Must Wait For:**
- None (FIRST WAVE - starts immediately)
**Blocks:**
- backend-agent (needs config cleanup first)
- infra-agent (needs config cleanup first)
---
### Agent 6: frontend-agent (Frontend Agent)
**Assigned Phases:** 10
**Focus:** Frontend updates
**Estimated Duration:** 25-35 minutes
**Complexity:** Low-Medium
**Responsibilities:**
- Phase 10: Remove tenant UI and update API clients
**Files Modified:**
- frontend/src/ (various files)
- Remove tenant-related components
- Update Auth0 integration
- Update API clients
**Can Run in Parallel With:**
- docs-agent
**Must Wait For:**
- backend-agent (needs backend changes complete)
---
### Agent 7: docs-agent (Documentation Agent)
**Assigned Phases:** 9
**Focus:** Documentation and Makefile updates
**Estimated Duration:** 30-40 minutes
**Complexity:** Low
**Responsibilities:**
- Phase 9: Update all documentation files
**Files Modified:**
- README.md
- CLAUDE.md
- AI-INDEX.md
- .ai/context.json
- docs/PLATFORM-SERVICES.md
- docs/TESTING.md
- Makefile
- All feature README files
**Can Run in Parallel With:**
- ALL agents (no conflicts)
**Must Wait For:**
- None (FIRST WAVE - starts immediately)
---
### Agent 8: test-agent (Testing Agent)
**Assigned Phases:** 11
**Focus:** Testing and validation
**Estimated Duration:** 20-30 minutes
**Complexity:** Low
**Responsibilities:**
- Phase 11: Run all tests and validation
**Files Modified:**
- Test files (update references)
- Validation of all changes
**Can Run in Parallel With:**
- None (runs last)
**Must Wait For:**
- ALL other agents (LAST WAVE)
---
## Execution Dependency Graph
```
Wave 1 (Parallel - Start Immediately):
┌─────────────────┐ ┌─────────────────┐
│ config-agent │ │ docs-agent │
│ Phase 4 │ │ Phase 9 │
└────────┬────────┘ └─────────────────┘
│ Blocks backend-agent and infra-agent
Wave 2 (Parallel - After config-agent):
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ infra-agent │ │ backend-agent │ │ storage-agent │
│ Phase 1 │ │ Phase 2 │ │ Phase 3 │
└────────┬────────┘ └────────┬────────┘ └─────────────────┘
│ │
│ │
▼ ▼
Wave 3 (Parallel - Continue and Add):
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ infra-agent │ │ backend-agent │ │ platform-agent │
│ Phase 5, 7 │ │ Phase 6 │ │ Phase 8 │
└─────────────────┘ └────────┬────────┘ └─────────────────┘
│ Blocks frontend-agent
Wave 4 (Sequential - After backend-agent):
┌─────────────────┐
│ frontend-agent │
│ Phase 10 │
└────────┬────────┘
│ All agents must complete
Wave 5 (Sequential - After All):
┌─────────────────┐
│ test-agent │
│ Phase 11 │
└─────────────────┘
```
## Detailed Execution Timeline
### Wave 1: Start (T+0)
```
T+0:00 → config-agent starts Phase 4
T+0:00 → docs-agent starts Phase 9
T+0:20 → config-agent completes Phase 4 ✓
T+0:30 → docs-agent completes Phase 9 ✓
```
### Wave 2: Main Execution (T+20-30)
```
T+0:20 → infra-agent starts Phase 1
T+0:20 → backend-agent starts Phase 2
T+0:20 → storage-agent starts Phase 3
T+0:45 → infra-agent completes Phase 1 ✓
T+0:50 → storage-agent completes Phase 3 ✓
T+0:55 → backend-agent completes Phase 2 ✓
```
### Wave 3: Continued + Platform (T+45-95)
```
T+0:45 → platform-agent starts Phase 8 (waits for infra Phase 1)
T+0:50 → infra-agent starts Phase 5
T+0:55 → backend-agent starts Phase 6
T+1:05 → infra-agent completes Phase 5 ✓
T+1:10 → infra-agent starts Phase 7
T+1:20 → backend-agent completes Phase 6 ✓
T+1:25 → platform-agent completes Phase 8 ✓
T+1:30 → infra-agent completes Phase 7 ✓
```
### Wave 4: Frontend (T+80-115)
```
T+1:20 → frontend-agent starts Phase 10 (waits for backend Phase 6)
T+1:50 → frontend-agent completes Phase 10 ✓
```
### Wave 5: Testing (T+110-140)
```
T+1:50 → test-agent starts Phase 11 (waits for all)
T+2:15 → test-agent completes Phase 11 ✓
```
**Total Parallel Execution Time:** ~2 hours 15 minutes
**vs. Sequential Execution:** ~6-8 hours
**Time Savings:** ~65-70%
## File Conflict Matrix
### Files Touched by Multiple Agents
| File | Agents | Coordination |
|------|--------|--------------|
| docker-compose.yml | infra-agent (Phase 1) | Sequential only - no conflict |
| backend/src/app.ts | backend-agent (Phase 2, 6) | Same agent - sequential |
| config/app/production.yml | config-agent (Phase 4) | Single agent - no conflict |
| Makefile | docs-agent (Phase 9) | Single agent - no conflict |
| .env | config-agent (Phase 4) | Single agent - no conflict |
**No file conflicts detected** - All agents work on different files or sequential phases.
## Communication Protocol
### State Updates
Agents must update `EXECUTION-STATE.json` when:
1. **Phase Start:** Set status to "in_progress", record timestamp
2. **Phase Complete:** Set status to "completed", record timestamp
3. **Phase Failed:** Set status to "failed", record error
### Coordination Points
**Critical Handoffs:**
1. config-agent Phase 4 → infra-agent Phase 1
2. config-agent Phase 4 → backend-agent Phase 2
3. infra-agent Phase 1 → platform-agent Phase 8
4. backend-agent Phase 6 → frontend-agent Phase 10
5. All agents → test-agent Phase 11
### Conflict Resolution
If unexpected conflict occurs:
1. First agent creates `docs/redesign/locks/{filename}.lock`
2. Second agent waits for lock release
3. First agent deletes lock after completion
4. Second agent proceeds
## Success Criteria Per Agent
### infra-agent
- [ ] All 6 containers renamed correctly
- [ ] docker-compose.yml validates (`docker compose config`)
- [ ] Networks reduced to 3
- [ ] Volumes configured correctly
- [ ] Containers start successfully
### backend-agent
- [ ] All tenant code removed
- [ ] No import errors
- [ ] API endpoints still functional
- [ ] Tests pass for modified features
### storage-agent
- [ ] Filesystem adapter created
- [ ] Document upload/download works
- [ ] No MinIO references remain
- [ ] File permissions correct
### platform-agent
- [ ] mvp-platform service simplified
- [ ] Connects to mvp-postgres and mvp-redis
- [ ] API endpoints functional
- [ ] No MSSQL/ETL dependencies
### config-agent
- [ ] All platform configs removed
- [ ] MinIO configs removed
- [ ] Secrets cleaned up
- [ ] .env simplified
### frontend-agent
- [ ] Tenant UI removed
- [ ] Auth0 integration updated
- [ ] API clients work
- [ ] No console errors
### docs-agent
- [ ] All documentation updated
- [ ] Makefile commands updated
- [ ] README reflects new architecture
- [ ] Feature docs updated
### test-agent
- [ ] `make rebuild` succeeds
- [ ] All 6 containers healthy
- [ ] `make test` passes
- [ ] No regressions
## Emergency Procedures
### Agent Failure
If an agent fails:
1. Check EXECUTION-STATE.json for error details
2. Review agent's phase documentation
3. Option A: Retry agent with fix
4. Option B: Manual intervention
5. Option C: Rollback using ROLLBACK-STRATEGY.md
### Deadlock Detection
If agents are waiting indefinitely:
1. Check for circular dependencies (shouldn't exist)
2. Check for orphaned lock files
3. Review EXECUTION-STATE.json
4. Manually release locks if needed
### Coordination Failure
If agents lose sync:
1. Pause all agents
2. Review EXECUTION-STATE.json
3. Identify completed vs. pending phases
4. Resume from last known good state

View File

@@ -1,316 +0,0 @@
# Dependency Graph - Phase Execution Order
## Visual Phase Dependencies
```
START
├─────────────────────────────────────────────┐
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ PHASE 4: Config │ │ PHASE 9: Docs │
│ Agent: config-agent │ │ Agent: docs-agent │
│ Duration: 20-30 min │ │ Duration: 30-40 min │
└────────────┬────────────┘ └─────────────────────────┘
│ (Parallel - no deps)
│ Blocks: infra-agent, backend-agent
├────────────────────┬─────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ PHASE 1: Docker │ │ PHASE 2: Remove │ │ PHASE 3: Storage │
│ Agent: infra-agent │ │ Tenant │ │ Agent:storage-agent │
│ Duration: 25-30min │ │ Agent:backend-agent │ │ Duration: 30-40min │
└──────────┬──────────┘ └──────────┬──────────┘ └─────────────────────┘
│ │ (Parallel)
│ │
│ Blocks platform-agent │
│ │
├───────────┐ ├───────────┐
│ │ │ │
▼ ▼ ▼ ▼
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ PHASE 5: │ │ PHASE 8: │ │ PHASE 6: │
│ Network │ │ Platform │ │ Backend │
│ Agent: infra │ │ Agent: platform │ │ Agent: backend │
│ Duration:15min │ │ Duration:35-45m │ │ Duration:20min │
└────────┬────────┘ └──────────────────┘ └────────┬────────┘
│ │
│ │ Blocks frontend-agent
▼ │
┌─────────────────┐ │
│ PHASE 7: │ │
│ Database │ │
│ Agent: infra │ │
│ Duration:15min │ │
└─────────────────┘ │
┌─────────────────────┐
│ PHASE 10: Frontend │
│ Agent: frontend │
│ Duration: 25-35min │
└──────────┬──────────┘
All phases must complete before testing
┌─────────────────────┐
│ PHASE 11: Testing │
│ Agent: test-agent │
│ Duration: 20-30min │
└─────────────────────┘
END
```
## Phase Dependency Matrix
| Phase | Agent | Depends On | Blocks | Can Run Parallel With |
|-------|-------|------------|--------|----------------------|
| 4 | config-agent | None | 1, 2 | 9 |
| 9 | docs-agent | None | None | 4, 1, 2, 3, 5, 6, 7, 8, 10 |
| 1 | infra-agent | 4 | 5, 7, 8 | 2, 3, 9 |
| 2 | backend-agent | 4 | 6, 10 | 1, 3, 9 |
| 3 | storage-agent | None | None | 1, 2, 4, 9, 5, 6, 7, 8 |
| 5 | infra-agent | 1 | 7 | 2, 3, 6, 8, 9 |
| 6 | backend-agent | 2 | 10 | 1, 3, 5, 7, 8, 9 |
| 7 | infra-agent | 5 | None | 2, 3, 6, 8, 9 |
| 8 | platform-agent | 1 | None | 2, 3, 5, 6, 7, 9 |
| 10 | frontend-agent | 6 | 11 | 9 (tail end) |
| 11 | test-agent | ALL | None | None |
## Critical Path Analysis
### Longest Path (Sequential)
```
Phase 4 (30m) → Phase 2 (20m) → Phase 6 (20m) → Phase 10 (30m) → Phase 11 (25m)
Total: 125 minutes (2 hours 5 minutes)
```
### Parallel Optimization
With 8 agents working in parallel:
```
Wave 1: Max(Phase 4: 30m, Phase 9: 40m) = 40 minutes
Wave 2: Max(Phase 1: 30m, Phase 2: 20m, Phase 3: 40m) = 40 minutes
Wave 3: Max(Phase 5: 15m, Phase 6: 20m, Phase 7: 15m, Phase 8: 45m) = 45 minutes
Wave 4: Phase 10: 30 minutes
Wave 5: Phase 11: 25 minutes
Total: 180 minutes (3 hours)
```
**Note:** Critical path runs through: Phase 9 → Phase 3 → Phase 8 → Phase 10 → Phase 11
## Agent Execution Waves
### Wave 1: Foundation (Parallel)
**Start Time:** T+0
**Duration:** 40 minutes
| Agent | Phase | Duration | Start | End |
|-------|-------|----------|-------|-----|
| config-agent | 4 | 30 min | T+0 | T+30 |
| docs-agent | 9 | 40 min | T+0 | T+40 |
**Completion Signal:** Both agents update EXECUTION-STATE.json status to "completed"
---
### Wave 2: Core Infrastructure (Parallel)
**Start Time:** T+30 (after config-agent completes)
**Duration:** 40 minutes
| Agent | Phase | Duration | Start | End |
|-------|-------|----------|-------|-----|
| infra-agent | 1 | 30 min | T+30 | T+60 |
| backend-agent | 2 | 20 min | T+30 | T+50 |
| storage-agent | 3 | 40 min | T+30 | T+70 |
**Waits For:** config-agent completion
**Completion Signal:** All three agents complete their first phases
---
### Wave 3: Continued Work (Parallel)
**Start Time:** Varies by agent
**Duration:** 45 minutes
| Agent | Phase | Duration | Start | End | Waits For |
|-------|-------|----------|-------|-----|-----------|
| infra-agent | 5 | 15 min | T+60 | T+75 | Phase 1 |
| backend-agent | 6 | 20 min | T+50 | T+70 | Phase 2 |
| platform-agent | 8 | 45 min | T+60 | T+105 | Phase 1 |
**Then:**
| Agent | Phase | Duration | Start | End | Waits For |
|-------|-------|----------|-------|-----|-----------|
| infra-agent | 7 | 15 min | T+75 | T+90 | Phase 5 |
**Completion Signal:** All agents finish their assigned phases
---
### Wave 4: Frontend (Sequential)
**Start Time:** T+70 (after backend-agent Phase 6)
**Duration:** 30 minutes
| Agent | Phase | Duration | Start | End | Waits For |
|-------|-------|----------|-------|-----|-----------|
| frontend-agent | 10 | 30 min | T+70 | T+100 | Phase 6 |
**Waits For:** backend-agent Phase 6 completion
**Completion Signal:** frontend-agent updates status
---
### Wave 5: Validation (Sequential)
**Start Time:** T+105 (after all agents complete)
**Duration:** 25 minutes
| Agent | Phase | Duration | Start | End | Waits For |
|-------|-------|----------|-------|-----|-----------|
| test-agent | 11 | 25 min | T+105 | T+130 | ALL phases |
**Waits For:** platform-agent Phase 8 (last to complete)
**Completion Signal:** All tests pass, project simplified
---
## Resource Conflict Analysis
### File-Level Conflicts
**None Detected** - All agents work on different files or in sequence.
### Potential Race Conditions
**Docker Compose Access:**
- Only infra-agent modifies docker-compose.yml
- Sequential phases (1, 5, 7) prevent conflicts
- **Risk:** Low
**Config File Access:**
- Only config-agent modifies config/app/production.yml
- Single phase (4) prevents conflicts
- **Risk:** None
**Backend Code Access:**
- backend-agent works on different files in Phase 2 vs. Phase 6
- storage-agent works on different files (storage/ vs. backend)
- **Risk:** None
### Lock File Strategy
If conflicts arise (they shouldn't):
```bash
# Agent 1 creates lock
touch docs/redesign/locks/docker-compose.yml.lock
# Agent 2 checks for lock
if [ -f docs/redesign/locks/docker-compose.yml.lock ]; then
wait_for_lock_release
fi
# Agent 1 releases lock
rm docs/redesign/locks/docker-compose.yml.lock
```
## Synchronization Points
### Critical Handoffs
1. **config-agent → infra-agent, backend-agent**
- **What:** Configuration cleanup complete
- **Why:** Backend and infra need clean config to work
- **Check:** EXECUTION-STATE.json phase 4 status = "completed"
2. **infra-agent Phase 1 → platform-agent Phase 8**
- **What:** Docker compose updated with new names
- **Why:** Platform service needs new container names
- **Check:** EXECUTION-STATE.json phase 1 status = "completed"
3. **backend-agent Phase 6 → frontend-agent Phase 10**
- **What:** Backend API updates complete
- **Why:** Frontend needs updated API contracts
- **Check:** EXECUTION-STATE.json phase 6 status = "completed"
4. **All Agents → test-agent Phase 11**
- **What:** All code changes complete
- **Why:** Testing validates entire simplification
- **Check:** EXECUTION-STATE.json phases 1-10 all "completed"
## Bottleneck Analysis
### Potential Bottlenecks
1. **platform-agent Phase 8 (45 minutes)**
- Longest single phase
- Blocks final testing
- **Mitigation:** Start as early as possible (after Phase 1)
2. **config-agent Phase 4 (30 minutes)**
- Blocks Wave 2 start
- **Mitigation:** First wave priority, simple changes
3. **storage-agent Phase 3 (40 minutes)**
- Not on critical path but moderately long
- **Mitigation:** Can run fully parallel
### Optimization Opportunities
1. **Start docs-agent immediately** - No dependencies, can run entire duration
2. **Prioritize config-agent** - Unblocks Wave 2 quickly
3. **Start storage-agent early** - Long duration, no dependencies
4. **Stagger infra-agent phases** - Phases 1, 5, 7 run sequentially within agent
## Decision Points
### Proceed to Next Wave
**Wave 1 → Wave 2:**
```
IF EXECUTION-STATE.json phase 4 status == "completed"
THEN spawn Wave 2 agents
ELSE wait
```
**Wave 2 → Wave 3:**
```
IF EXECUTION-STATE.json phase 1 status == "completed"
THEN spawn platform-agent
CONTINUE infra-agent to Phase 5
CONTINUE backend-agent to Phase 6
```
**Wave 3 → Wave 4:**
```
IF EXECUTION-STATE.json phase 6 status == "completed"
THEN spawn frontend-agent
```
**Wave 4 → Wave 5:**
```
IF all phases 1-10 status == "completed"
THEN spawn test-agent
ELSE identify failures and halt
```
## Rollback Decision Tree
```
IF test-agent Phase 11 fails
├─ IF frontend-agent Phase 10 suspected
│ └─ Rollback Phase 10 only
├─ IF backend-agent Phase 2 or 6 suspected
│ └─ Rollback Phases 2 and 6
├─ IF infrastructure suspected
│ └─ Rollback Phases 1, 5, 7
└─ IF all else
└─ Full rollback to original state
```
See ROLLBACK-STRATEGY.md for detailed procedures.

View File

@@ -1,242 +0,0 @@
{
"simplification_version": "1.0.0",
"started_at": "2025-11-01T20:18:39Z",
"completed_at": "2025-11-02T02:13:45Z",
"status": "completed",
"current_wave": 5,
"phases": {
"1": {
"name": "Docker Compose Simplification",
"agent": "infra-agent",
"status": "completed",
"started_at": "2025-11-01T20:45:00Z",
"completed_at": "2025-11-01T20:50:00Z",
"duration_minutes": 5,
"validation_passed": false,
"errors": [
"Container validation blocked: Requires Phases 2 (Multi-Tenant Removal) and 3 (Storage Migration) to complete before containers can build and start. docker-compose.yml changes are complete and valid."
]
},
"2": {
"name": "Remove Multi-Tenant Architecture",
"agent": "backend-agent",
"status": "completed",
"started_at": "2025-11-01T20:40:00Z",
"completed_at": "2025-11-01T21:00:00Z",
"duration_minutes": 20,
"validation_passed": true,
"errors": []
},
"3": {
"name": "Filesystem Storage Migration",
"agent": "storage-agent",
"status": "completed",
"started_at": "2025-11-01T20:46:00Z",
"completed_at": "2025-11-01T20:56:00Z",
"duration_minutes": 10,
"validation_passed": true,
"errors": []
},
"4": {
"name": "Configuration Cleanup",
"agent": "config-agent",
"status": "completed",
"started_at": "2025-11-01T20:25:00Z",
"completed_at": "2025-11-01T20:30:00Z",
"duration_minutes": 5,
"validation_passed": true,
"errors": []
},
"5": {
"name": "Network Simplification",
"agent": "infra-agent",
"status": "completed",
"started_at": "2025-11-02T02:10:44Z",
"completed_at": "2025-11-02T02:11:26Z",
"duration_minutes": 1,
"validation_passed": true,
"errors": []
},
"6": {
"name": "Backend Service Updates",
"agent": "backend-agent",
"status": "completed",
"started_at": "2025-11-02T02:06:58Z",
"completed_at": "2025-11-02T02:07:57Z",
"duration_minutes": 1,
"validation_passed": true,
"errors": []
},
"7": {
"name": "Database Updates",
"agent": "infra-agent",
"status": "completed",
"started_at": "2025-11-02T02:11:58Z",
"completed_at": "2025-11-02T02:12:10Z",
"duration_minutes": 1,
"validation_passed": true,
"errors": ["Runtime database validation deferred to Phase 11 (containers not running)"]
},
"8": {
"name": "Platform Service Simplification",
"agent": "platform-agent",
"status": "completed",
"started_at": "2025-11-02T02:08:15Z",
"completed_at": "2025-11-02T02:10:18Z",
"duration_minutes": 2,
"validation_passed": true,
"errors": []
},
"9": {
"name": "Documentation Updates",
"agent": "docs-agent",
"status": "completed",
"started_at": "2025-11-01T20:20:00Z",
"completed_at": "2025-11-01T20:35:00Z",
"duration_minutes": 15,
"validation_passed": true,
"errors": []
},
"10": {
"name": "Frontend Updates",
"agent": "frontend-agent",
"status": "completed",
"started_at": "2025-11-02T02:12:30Z",
"completed_at": "2025-11-02T02:12:45Z",
"duration_minutes": 1,
"validation_passed": true,
"errors": ["Frontend build validation deferred to Phase 11 (Docker build required)"]
},
"11": {
"name": "Testing and Validation",
"agent": "test-agent",
"status": "completed",
"started_at": "2025-11-02T02:13:10Z",
"completed_at": "2025-11-02T02:13:45Z",
"duration_minutes": 1,
"validation_passed": true,
"errors": ["Runtime container validation requires 'make rebuild' and 'make test' to complete"]
}
},
"agents": {
"config-agent": {
"status": "completed",
"assigned_phases": [4],
"current_phase": null,
"completed_phases": [4],
"total_duration_minutes": 5
},
"docs-agent": {
"status": "completed",
"assigned_phases": [9],
"current_phase": null,
"completed_phases": [9],
"total_duration_minutes": 15
},
"infra-agent": {
"status": "completed",
"assigned_phases": [1, 5, 7],
"current_phase": null,
"completed_phases": [1, 5, 7],
"total_duration_minutes": 7
},
"backend-agent": {
"status": "completed",
"assigned_phases": [2, 6],
"current_phase": null,
"completed_phases": [2, 6],
"total_duration_minutes": 21
},
"storage-agent": {
"status": "completed",
"assigned_phases": [3],
"current_phase": null,
"completed_phases": [3],
"total_duration_minutes": 10
},
"platform-agent": {
"status": "completed",
"assigned_phases": [8],
"current_phase": null,
"completed_phases": [8],
"total_duration_minutes": 2
},
"frontend-agent": {
"status": "completed",
"assigned_phases": [10],
"current_phase": null,
"completed_phases": [10],
"total_duration_minutes": 1
},
"test-agent": {
"status": "completed",
"assigned_phases": [11],
"current_phase": null,
"completed_phases": [11],
"total_duration_minutes": 1
}
},
"waves": {
"1": {
"name": "Foundation",
"agents": ["config-agent", "docs-agent"],
"status": "completed",
"started_at": "2025-11-01T20:18:39Z",
"completed_at": "2025-11-01T20:25:14Z"
},
"2": {
"name": "Core Infrastructure",
"agents": ["infra-agent", "backend-agent", "storage-agent"],
"status": "completed",
"started_at": "2025-11-01T20:25:14Z",
"completed_at": "2025-11-01T20:33:05Z",
"waits_for_wave": 1
},
"3": {
"name": "Continued Work",
"agents": ["infra-agent", "backend-agent", "platform-agent"],
"status": "in_progress",
"started_at": "2025-11-01T20:33:05Z",
"completed_at": null,
"waits_for_wave": 2
},
"4": {
"name": "Frontend",
"agents": ["frontend-agent"],
"status": "pending",
"started_at": null,
"completed_at": null,
"waits_for_wave": 3
},
"5": {
"name": "Validation",
"agents": ["test-agent"],
"status": "completed",
"started_at": "2025-11-02T02:13:10Z",
"completed_at": "2025-11-02T02:13:45Z",
"waits_for_wave": 4
}
},
"conflicts": [],
"validations": {
"docker_compose_valid": true,
"backend_builds": true,
"frontend_builds": true,
"tests_pass": null,
"containers_healthy": true,
"no_tenant_references": true,
"no_minio_references": true,
"no_old_container_names": true,
"service_count": 6,
"network_count": 3
},
"rollbacks": [],
"notes": [
"All 6 containers running and healthy",
"Fixed TypeScript build errors in filesystem adapter",
"Fixed config schema validation (removed tenant fields)",
"Fixed platform database password (using shared postgres password)",
"Fixed frontend nginx permissions",
"Architecture successfully simplified: 14 → 6 containers (57% reduction)"
]
}

View File

@@ -1,478 +0,0 @@
# File Manifest - Complete File Change Inventory
## Summary
| Action | Count | Agent |
|--------|-------|-------|
| DELETE | 23 files + 1 directory | config-agent, backend-agent |
| MODIFY | 45 files | All agents |
| CREATE | 4 files | storage-agent |
| **TOTAL** | **72 file operations** | **8 agents** |
## Files to DELETE (23 files + 1 directory)
### Backend Files (Agent: backend-agent, Phase 2)
```
backend/src/core/middleware/tenant.ts
backend/src/core/config/tenant.ts
backend/src/features/tenant-management/ (entire directory)
├── index.ts
├── tenant.controller.ts
├── tenant.service.ts
├── tenant.routes.ts
├── tenant.types.ts
└── tests/
├── tenant.test.ts
└── fixtures/
```
### Configuration & Secrets (Agent: config-agent, Phase 4)
```
secrets/app/minio-access-key.txt
secrets/app/minio-secret-key.txt
secrets/app/platform-vehicles-api-key.txt
secrets/platform/ (entire directory)
├── postgres-password.txt
├── redis-password.txt
└── api-keys/
```
### Docker Services (Agent: infra-agent, Phase 1)
**Note:** These are removed from docker-compose.yml, not file deletions
```
Services removed:
- admin-minio
- mvp-platform-landing
- mvp-platform-tenants
- platform-postgres
- platform-redis
- mvp-platform-vehicles-db
- mvp-platform-vehicles-redis
- mvp-platform-vehicles-etl
```
---
## Files to CREATE (4 files)
### Storage Adapter (Agent: storage-agent, Phase 3)
```
backend/src/core/storage/adapters/filesystem.adapter.ts (NEW)
data/documents/.gitkeep (NEW - directory marker)
```
### Volume Mount
```
./data/documents/ (directory created by Docker)
```
---
## Files to MODIFY (45 files)
### Phase 1: Docker Compose (Agent: infra-agent)
#### docker-compose.yml
**Lines:** Entire file restructure
**Changes:**
- Rename all services: admin-* → mvp-*, mvp-platform-vehicles-api → mvp-platform
- Remove 8 service definitions
- Add volume mount: `./data/documents:/app/data/documents`
- Update network assignments (5 → 3 networks)
- Update service discovery labels
---
### Phase 2: Remove Tenant (Agent: backend-agent)
#### backend/src/app.ts
**Lines:** ~30-45, ~120-130
**Changes:**
- Remove tenant middleware import
- Remove tenant middleware registration
- Remove tenant-management feature registration
#### backend/src/core/plugins/auth.plugin.ts
**Lines:** ~55-75
**Changes:**
- Remove `https://motovaultpro.com/tenant_id` claim extraction
- Simplify JWT payload to only extract `sub` and `roles`
#### backend/src/features/vehicles/domain/vehicles.service.ts
**Lines:** Various
**Changes:**
- Remove tenant context from function signatures (if any)
- Ensure only user_id is used for data isolation
#### backend/src/features/vehicles/domain/platform-integration.service.ts
**Lines:** ~20-30, ~100-120
**Changes:**
- Remove tenant context
- Update platform client URL to use mvp-platform
#### backend/src/features/fuel-logs/*.ts
**Changes:**
- Remove tenant references (verify user_id only)
#### backend/src/features/maintenance/*.ts
**Changes:**
- Remove tenant references (verify user_id only)
#### backend/src/features/stations/*.ts
**Changes:**
- Remove tenant references (verify user_id only)
#### backend/src/features/documents/*.ts
**Changes:**
- Remove tenant references (verify user_id only)
---
### Phase 3: Filesystem Storage (Agent: storage-agent)
#### backend/src/core/storage/storage.service.ts
**Lines:** ~10-25
**Changes:**
- Update factory function to return FilesystemAdapter
- Remove MinIO configuration check
#### backend/src/features/documents/documents.controller.ts
**Lines:** ~176-269 (upload), ~271-319 (download), ~129-174 (delete)
**Changes:**
- No changes needed (uses StorageService interface)
- Verify file paths work with filesystem adapter
#### backend/src/features/documents/documents.service.ts
**Lines:** ~40-80
**Changes:**
- Update storage_key format for filesystem paths
- Add filesystem-specific error handling
---
### Phase 4: Config Cleanup (Agent: config-agent)
#### config/app/production.yml
**Lines:** Remove entire sections
**Changes:**
- Remove `platform_vehicles_api_url` (add internal: `http://mvp-platform:8000`)
- Remove `platform_vehicles_api_key`
- Remove `platform_tenants_api_url`
- Remove MinIO configuration section
- Remove tenant-specific database URLs
#### .env
**Lines:** Remove variables
**Changes:**
- Remove `PLATFORM_VEHICLES_API_KEY`
- Remove `MINIO_ENDPOINT`, `MINIO_ACCESS_KEY`, `MINIO_SECRET_KEY`
- Update `PLATFORM_VEHICLES_API_URL=http://mvp-platform:8000`
- Update `DATABASE_URL` to use mvp-postgres
- Update `REDIS_URL` to use mvp-redis
#### .env.development (if exists)
**Changes:** Same as .env
---
### Phase 5: Network Simplification (Agent: infra-agent)
#### docker-compose.yml
**Lines:** Networks section
**Changes:**
- Remove `platform` network
- Remove `egress` network
- Keep `frontend`, `backend`, `database`
- Update service network assignments
---
### Phase 6: Backend Updates (Agent: backend-agent)
#### backend/src/core/config/config-loader.ts
**Lines:** ~50-80
**Changes:**
- Update database URL to use mvp-postgres
- Update Redis URL to use mvp-redis
- Remove tenant-specific config loading
#### backend/src/features/vehicles/external/platform-vehicles/platform-vehicles.client.ts
**Lines:** ~15-25
**Changes:**
- Update base URL to http://mvp-platform:8000
- Remove API key authentication (same network)
#### backend/src/index.ts
**Changes:**
- Verify service startup with new config
---
### Phase 7: Database Updates (Agent: infra-agent)
#### backend/src/_system/migrations/
**Changes:**
- Review migrations for tenant references (should be none)
- Verify user_id isolation only
#### docker-compose.yml
**Lines:** mvp-postgres service
**Changes:**
- Verify connection string
- Add volumes_platform schema initialization (if needed)
---
### Phase 8: Platform Service (Agent: platform-agent)
#### mvp-platform-services/vehicles/
**Entire service restructure:**
**mvp-platform-services/vehicles/Dockerfile**
- Remove MSSQL dependencies
- Simplify to single-container deployment
**mvp-platform-services/vehicles/main.py**
- Update database connection to use mvp-postgres
- Update cache connection to use mvp-redis
- Remove ETL imports and endpoints
**mvp-platform-services/vehicles/config.py**
- Update DATABASE_URL
- Update REDIS_URL
**mvp-platform-services/vehicles/requirements.txt**
- Remove MSSQL drivers (pymssql, pyodbc)
- Keep PostgreSQL (psycopg2)
---
### Phase 9: Documentation (Agent: docs-agent)
#### README.md
**Lines:** ~1-30
**Changes:**
- Update architecture description (14 → 6 containers)
- Update service names (admin-* → mvp-*)
- Update quick start instructions
#### CLAUDE.md
**Lines:** Various
**Changes:**
- Remove multi-tenant architecture guidance
- Remove platform service development instructions
- Update container names in examples
#### AI-INDEX.md
**Lines:** ~3-24
**Changes:**
- Update architecture description
- Remove platform services section
- Update URLs and container names
#### .ai/context.json
**Lines:** Entire file
**Changes:**
- Update architecture metadata (hybrid → simplified)
- Update service list (14 → 6)
- Remove tenant-management feature
- Update platform service description
#### docs/PLATFORM-SERVICES.md
**Lines:** Entire file restructure
**Changes:**
- Document single mvp-platform service
- Remove tenant service documentation
- Remove landing service documentation
- Update architecture diagrams
#### docs/TESTING.md
**Lines:** ~24-60
**Changes:**
- Update container names (admin-* → mvp-*)
- Remove platform service test setup
- Update integration test patterns
#### docs/DATABASE-SCHEMA.md
**Changes:**
- Verify no tenant references
- Document vehicles_platform schema (if added)
#### Makefile
**Lines:** All commands
**Changes:**
```diff
- docker compose exec admin-backend
+ docker compose exec mvp-backend
- docker compose exec admin-frontend
+ docker compose exec mvp-frontend
- docker compose exec admin-postgres
+ docker compose exec mvp-postgres
```
#### backend/src/features/*/README.md (5 files)
**Changes:**
- Update container names in examples
- Remove tenant context from feature descriptions
- Update testing instructions
---
### Phase 10: Frontend Updates (Agent: frontend-agent)
#### frontend/src/App.tsx
**Changes:**
- Remove tenant selection UI (if exists)
- Remove tenant context provider (if exists)
#### frontend/src/core/auth/
**Changes:**
- Update Auth0 integration
- Remove tenant_id claim extraction
- Verify user authentication still works
#### frontend/src/core/api/
**Changes:**
- Remove tenant management API client (if exists)
- Update API base URLs (if hardcoded)
#### frontend/src/features/*/
**Changes:**
- Remove any tenant-related components
- Verify API calls work with new backend
---
### Phase 11: Testing (Agent: test-agent)
#### backend/src/features/*/tests/
**Changes:**
- Update container name references in test helpers
- Remove tenant context from test fixtures
- Update integration tests
#### frontend/src/features/*/tests/
**Changes:**
- Update component tests
- Remove tenant-related test cases
---
## File Conflict Resolution
### Potential Conflicts
| File | Agents | Resolution |
|------|--------|------------|
| docker-compose.yml | infra-agent (Phases 1, 5) | Sequential phases - no conflict |
| backend/src/app.ts | backend-agent (Phases 2, 6) | Sequential phases - no conflict |
| config/app/production.yml | config-agent (Phase 4) | Single agent - no conflict |
| Makefile | docs-agent (Phase 9) | Single agent - no conflict |
**No actual conflicts** - All multi-phase modifications are by same agent in sequence.
### Lock File Locations
If conflicts arise (they shouldn't), lock files would be created in:
```
docs/redesign/locks/
├── docker-compose.yml.lock
├── app.ts.lock
├── production.yml.lock
└── Makefile.lock
```
## File Change Statistics
### By Agent
| Agent | DELETE | MODIFY | CREATE | Total |
|-------|--------|--------|--------|-------|
| config-agent | 6 files | 3 files | 0 | 9 |
| backend-agent | 7 files + 1 dir | 12 files | 0 | 19 |
| storage-agent | 0 | 3 files | 2 files | 5 |
| infra-agent | 0 (service removal) | 8 files | 0 | 8 |
| platform-agent | 0 | 6 files | 0 | 6 |
| docs-agent | 0 | 10 files | 0 | 10 |
| frontend-agent | 0 | 8 files | 0 | 8 |
| test-agent | 0 | 7 files | 0 | 7 |
| **TOTAL** | **13 + 1 dir** | **57** | **2** | **72** |
### By File Type
| Type | DELETE | MODIFY | CREATE |
|------|--------|--------|--------|
| .ts/.tsx | 7 | 35 | 2 |
| .yml/.yaml | 0 | 2 | 0 |
| .md | 0 | 10 | 0 |
| .json | 0 | 1 | 0 |
| .txt (secrets) | 6 | 0 | 0 |
| .py | 0 | 6 | 0 |
| Makefile | 0 | 1 | 0 |
| .env | 0 | 2 | 0 |
## Version Control Strategy
### Branch Strategy
```bash
# Main branch
git checkout main
# Create feature branch
git checkout -b simplify-architecture
# Each agent works on sub-branch
git checkout -b simplify/phase-1
git checkout -b simplify/phase-2
...
# Merge phases sequentially
# Or merge all at once after validation
```
### Commit Strategy
**Option A: Per-Phase Commits**
```
git commit -m "Phase 1: Rename containers and update docker-compose"
git commit -m "Phase 2: Remove multi-tenant architecture"
...
```
**Option B: Per-Agent Commits**
```
git commit -m "config-agent: Clean up configuration and secrets"
git commit -m "backend-agent: Remove tenant code and update services"
...
```
**Recommended:** Per-Phase commits for better rollback granularity.
## Backup Strategy
Before starting:
```bash
# Create backup branch
git checkout -b backup-before-simplification
# Tag current state
git tag -a pre-simplification -m "State before architecture simplification"
# Export docker volumes
docker run --rm -v mvp_postgres_data:/data -v $(pwd):/backup \
alpine tar czf /backup/postgres-backup.tar.gz /data
```
## File Verification Checklist
After all changes:
- [ ] No references to `admin-backend` (should be `mvp-backend`)
- [ ] No references to `admin-frontend` (should be `mvp-frontend`)
- [ ] No references to `admin-postgres` (should be `mvp-postgres`)
- [ ] No references to `tenant_id` in application code
- [ ] No references to MinIO in backend code
- [ ] No platform service API keys in config
- [ ] All tests updated for new container names
- [ ] All documentation reflects 6-container architecture

View File

@@ -1,402 +0,0 @@
# Phase 1: Docker Compose Simplification
## Agent Assignment
**Primary Agent:** infra-agent
**Collaborators:** None
**Estimated Duration:** 25-30 minutes
## Prerequisites
- **Phases that must complete first:** Phase 4 (Config Cleanup)
- **Files that must not be locked:** docker-compose.yml
- **System state:** All containers stopped or ready for restart
## Objectives
1. Rename all services from `admin-*` to `mvp-*` naming convention
2. Rename `mvp-platform-vehicles-api` to `mvp-platform`
3. Remove 8 unnecessary platform service containers
4. Add filesystem volume mount for document storage
5. Update all Traefik labels for new service names
6. Ensure 6 containers total in final configuration
## Files to Modify
### docker-compose.yml
**Action:** Major restructure
**Location:** `/docker-compose.yml`
## Step-by-Step Instructions
### Step 1: Stop All Running Containers
```bash
# Stop all services
docker compose down
# Verify all stopped
docker compose ps
# Expected: No containers listed
```
### Step 2: Backup Current docker-compose.yml
```bash
# Create backup
cp docker-compose.yml docker-compose.yml.backup-phase1-$(date +%Y%m%d)
# Verify backup
ls -la docker-compose.yml*
```
### Step 3: Rename Services
**Services to Rename:**
```yaml
# OLD → NEW
traefik → mvp-traefik
admin-frontend → mvp-frontend
admin-backend → mvp-backend
admin-postgres → mvp-postgres
admin-redis → mvp-redis
mvp-platform-vehicles-api → mvp-platform
```
**Find and Replace:**
```bash
# In docker-compose.yml, replace:
sed -i.bak 's/admin-frontend/mvp-frontend/g' docker-compose.yml
sed -i.bak 's/admin-backend/mvp-backend/g' docker-compose.yml
sed -i.bak 's/admin-postgres/mvp-postgres/g' docker-compose.yml
sed -i.bak 's/admin-redis/mvp-redis/g' docker-compose.yml
sed -i.bak 's/mvp-platform-vehicles-api/mvp-platform/g' docker-compose.yml
# Note: traefik already has correct name
```
### Step 4: Remove Platform Services
**Delete these entire service definitions from docker-compose.yml:**
```yaml
admin-minio: # DELETE entire block
mvp-platform-landing: # DELETE entire block
mvp-platform-tenants: # DELETE entire block
platform-postgres: # DELETE entire block
platform-redis: # DELETE entire block
mvp-platform-vehicles-db: # DELETE entire block
mvp-platform-vehicles-redis: # DELETE entire block
mvp-platform-vehicles-etl: # DELETE entire block
```
### Step 5: Add Filesystem Volume Mount
**Add to mvp-backend service:**
```yaml
mvp-backend:
# ... existing config ...
volumes:
- ./config/app/production.yml:/app/config/production.yml:ro
- ./secrets/app/postgres-password.txt:/run/secrets/postgres-password:ro
- ./data/documents:/app/data/documents # ADD THIS LINE
# ... rest of config ...
```
**Create directory on host:**
```bash
mkdir -p ./data/documents
chmod 755 ./data/documents
```
### Step 6: Update Volume Names
**Find and replace volume names:**
```yaml
# OLD volumes:
admin_postgres_data
admin_redis_data
admin_minio_data # DELETE
# NEW volumes:
mvp_postgres_data
mvp_redis_data
```
**At bottom of docker-compose.yml:**
```yaml
volumes:
mvp_postgres_data:
name: mvp_postgres_data
mvp_redis_data:
name: mvp_redis_data
# Remove admin_minio_data
```
### Step 7: Update Traefik Labels
**For mvp-frontend:**
```yaml
mvp-frontend:
labels:
- "traefik.enable=true"
- "traefik.http.routers.mvp-frontend.rule=Host(`admin.motovaultpro.com`)" # Updated
- "traefik.http.routers.mvp-frontend.entrypoints=websecure"
- "traefik.http.routers.mvp-frontend.tls=true"
- "traefik.http.services.mvp-frontend.loadbalancer.server.port=80" # Updated service name
```
**For mvp-backend:**
```yaml
mvp-backend:
labels:
- "traefik.enable=true"
- "traefik.http.routers.mvp-backend.rule=Host(`admin.motovaultpro.com`) && PathPrefix(`/api`)"
- "traefik.http.routers.mvp-backend.entrypoints=websecure"
- "traefik.http.routers.mvp-backend.tls=true"
- "traefik.http.services.mvp-backend.loadbalancer.server.port=3001" # Updated service name
```
**For mvp-platform:**
```yaml
mvp-platform:
labels:
- "traefik.enable=true"
- "traefik.http.routers.mvp-platform.rule=Host(`admin.motovaultpro.com`) && PathPrefix(`/platform`)"
- "traefik.http.routers.mvp-platform.entrypoints=websecure"
- "traefik.http.routers.mvp-platform.tls=true"
- "traefik.http.services.mvp-platform.loadbalancer.server.port=8000" # Updated service name
```
### Step 8: Update Internal Service References
**In mvp-backend environment variables or config:**
```yaml
mvp-backend:
environment:
- DATABASE_HOST=mvp-postgres # Updated from admin-postgres
- REDIS_HOST=mvp-redis # Updated from admin-redis
- PLATFORM_VEHICLES_API_URL=http://mvp-platform:8000 # Updated
```
**In mvp-platform:**
```yaml
mvp-platform:
environment:
- DATABASE_HOST=mvp-postgres # Will use same postgres as backend
- REDIS_HOST=mvp-redis # Will use same redis as backend
```
### Step 9: Validate docker-compose.yml
```bash
# Validate syntax
docker compose config
# Expected: No errors, valid YAML output
# Check service count
docker compose config --services | wc -l
# Expected: 6
```
### Step 10: Update .env if Needed
**Ensure .env references new service names:**
```bash
# .env should have:
DATABASE_URL=postgresql://postgres:password@mvp-postgres:5432/motovaultpro
REDIS_URL=redis://mvp-redis:6379
PLATFORM_VEHICLES_API_URL=http://mvp-platform:8000
```
### Step 11: Start Services
```bash
# Build and start all containers
docker compose up -d --build
# Check status
docker compose ps
# Expected: 6 services running
# Expected services:
# - mvp-traefik
# - mvp-frontend
# - mvp-backend
# - mvp-postgres
# - mvp-redis
# - mvp-platform
```
### Step 12: Verify Traefik Dashboard
```bash
# Access Traefik dashboard
open http://localhost:8080
# Check discovered services
curl -s http://localhost:8080/api/http/services | jq -r '.[].name'
# Expected to see: mvp-frontend, mvp-backend, mvp-platform
# Check routers
curl -s http://localhost:8080/api/http/routers | jq -r '.[].name'
# Expected to see: mvp-frontend, mvp-backend, mvp-platform routers
```
## Validation Criteria
### Container Validation
- [ ] Exactly 6 containers running
- [ ] All containers have "healthy" or "running" status
- [ ] No "admin-*" named containers (except in volumes)
- [ ] mvp-platform exists (not mvp-platform-vehicles-api)
**Validation Command:**
```bash
docker compose ps --format "table {{.Service}}\t{{.Status}}"
```
### Service Validation
- [ ] mvp-traefik accessible at localhost:8080
- [ ] mvp-frontend accessible at https://admin.motovaultpro.com
- [ ] mvp-backend accessible at https://admin.motovaultpro.com/api/health
- [ ] mvp-postgres accepting connections
- [ ] mvp-redis accepting connections
- [ ] mvp-platform accessible (internal)
**Validation Commands:**
```bash
# Test Traefik
curl -s http://localhost:8080/api/version | jq
# Test backend health
curl -s -k https://admin.motovaultpro.com/api/health
# Test postgres
docker compose exec mvp-postgres pg_isready -U postgres
# Test redis
docker compose exec mvp-redis redis-cli ping
# Expected: PONG
# Test platform service (internal)
docker compose exec mvp-backend curl http://mvp-platform:8000/health
```
### Volume Validation
- [ ] mvp_postgres_data volume exists
- [ ] mvp_redis_data volume exists
- [ ] ./data/documents directory exists and is writable
- [ ] No admin_minio_data volume
**Validation Commands:**
```bash
# Check volumes
docker volume ls | grep mvp
# Expected: mvp_postgres_data, mvp_redis_data
# Check filesystem mount
docker compose exec mvp-backend ls -la /app/data/documents
# Expected: Directory exists, writable
# Verify no MinIO volume
docker volume ls | grep minio
# Expected: Empty (no results)
```
### Network Validation (Phase 5 will simplify further)
- [ ] Services can communicate internally
- [ ] Traefik can route to all services
- [ ] No network errors in logs
**Validation Commands:**
```bash
# Test internal communication
docker compose exec mvp-backend ping -c 1 mvp-postgres
docker compose exec mvp-backend ping -c 1 mvp-redis
docker compose exec mvp-backend ping -c 1 mvp-platform
# Check logs for network errors
docker compose logs mvp-backend | grep -i "network\|connection"
# Expected: No critical errors
```
## Rollback Procedure
If validation fails:
```bash
# 1. Stop containers
docker compose down
# 2. Restore backup
cp docker-compose.yml.backup-phase1-YYYYMMDD docker-compose.yml
# 3. Restart with original config
docker compose up -d
# 4. Verify rollback
docker compose ps
# Expected: 14 containers (original state)
```
See ROLLBACK-STRATEGY.md Phase 1 section for detailed procedure.
## Dependencies on Other Phases
### Blocks These Phases:
- Phase 5 (Network Simplification) - needs new service names
- Phase 7 (Database Updates) - needs new container names
- Phase 8 (Platform Service) - needs new mvp-platform name
### Blocked By:
- Phase 4 (Config Cleanup) - needs clean configuration first
## Estimated Duration
**25-30 minutes**
- Backup and preparation: 5 minutes
- Service renaming: 10 minutes
- Validation: 10 minutes
- Troubleshooting buffer: 5 minutes
## Conflict Zones
**None** - This phase exclusively owns docker-compose.yml during execution.
## Success Indicators
1. `docker compose config` validates successfully
2. All 6 containers start and reach healthy status
3. Traefik dashboard shows 3 services
4. Application accessible via browser
5. No errors in container logs
## Update EXECUTION-STATE.json
```json
{
"phases": {
"1": {
"status": "in_progress",
"started_at": "[timestamp]",
"agent": "infra-agent"
}
}
}
```
**On completion:**
```json
{
"phases": {
"1": {
"status": "completed",
"started_at": "[timestamp]",
"completed_at": "[timestamp]",
"duration_minutes": 28,
"validation_passed": true
}
}
}
```
## Next Phase
After successful completion, infra-agent can proceed to Phase 5 (Network Simplification), and platform-agent can start Phase 8 (Platform Service Simplification).

View File

@@ -1,98 +0,0 @@
# Phase 2: Remove Multi-Tenant Architecture
## Agent Assignment
**Primary Agent:** backend-agent
**Duration:** 20 minutes
## Prerequisites
- Phase 4 (Config Cleanup) must be complete
- Backend container accessible
## Objectives
1. Delete all tenant-related code files
2. Remove tenant middleware from application
3. Remove tenant context from features
4. Simplify JWT claims to user-only
## Step-by-Step Instructions
### Step 1: Delete Tenant Files
```bash
# Delete tenant middleware
rm backend/src/core/middleware/tenant.ts
# Delete tenant configuration
rm backend/src/core/config/tenant.ts
# Delete tenant-management feature
rm -rf backend/src/features/tenant-management/
```
### Step 2: Update backend/src/app.ts
Remove tenant imports and registration:
```typescript
// REMOVE these lines:
import { tenantMiddleware } from './core/middleware/tenant';
fastify.register(tenantMiddleware);
fastify.register(tenantManagementRoutes, { prefix: '/api/tenant-management' });
```
### Step 3: Update backend/src/core/plugins/auth.plugin.ts
Simplify JWT payload extraction:
```typescript
// REMOVE tenant claim extraction:
// const tenantId = request.user?.['https://motovaultpro.com/tenant_id'];
// KEEP only:
request.user = {
sub: payload.sub, // user ID
roles: payload['https://motovaultpro.com/roles'] || []
};
```
### Step 4: Verify No Tenant References in Features
```bash
cd backend/src/features
grep -r "tenant_id" .
grep -r "tenantId" .
# Expected: 0 results
```
### Step 5: Rebuild Backend
```bash
cd backend
npm run build
# Expected: No errors
```
### Step 6: Update Tests
```bash
# Remove tenant-management tests
rm -rf backend/src/features/tenant-management/tests/
# Update other test files
grep -r "tenant" backend/src/features/*/tests/
# Fix any remaining references
```
## Validation Criteria
- [ ] backend/src/core/middleware/tenant.ts deleted
- [ ] backend/src/core/config/tenant.ts deleted
- [ ] backend/src/features/tenant-management/ deleted
- [ ] No tenant imports in app.ts
- [ ] JWT only extracts sub and roles
- [ ] Backend builds successfully
- [ ] No tenant_id references in features
**Validation Command:**
```bash
npm run build && grep -r "tenant_id" backend/src/features/ | wc -l
# Expected: 0
```
## Update EXECUTION-STATE.json
```json
{
"phases": {"2": {"status": "completed", "validation_passed": true}}
}
```

View File

@@ -1,118 +0,0 @@
# Phase 3: Filesystem Storage Migration
## Agent Assignment
**Primary Agent:** storage-agent
**Duration:** 30-40 minutes
## Prerequisites
- None (can start immediately)
## Objectives
1. Create filesystem storage adapter
2. Replace MinIO adapter with filesystem
3. Update documents feature to use filesystem
4. Verify document upload/download works
## Step-by-Step Instructions
### Step 1: Create Filesystem Adapter
Create `backend/src/core/storage/adapters/filesystem.adapter.ts`:
```typescript
import { StorageService } from '../storage.service';
import * as fs from 'fs/promises';
import * as path from 'path';
import { createReadStream } from 'fs';
export class FilesystemAdapter implements StorageService {
private basePath: string;
constructor(basePath: string = '/app/data/documents') {
this.basePath = basePath;
}
async putObject(bucket: string, key: string, body: Buffer, contentType?: string): Promise<void> {
const filePath = path.join(this.basePath, key);
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, body);
}
async getObjectStream(bucket: string, key: string): Promise<NodeJS.ReadableStream> {
const filePath = path.join(this.basePath, key);
return createReadStream(filePath);
}
async deleteObject(bucket: string, key: string): Promise<void> {
const filePath = path.join(this.basePath, key);
await fs.unlink(filePath);
}
async headObject(bucket: string, key: string): Promise<any> {
const filePath = path.join(this.basePath, key);
const stats = await fs.stat(filePath);
return { size: stats.size, lastModified: stats.mtime };
}
async getSignedUrl(bucket: string, key: string): Promise<string> {
// Not needed for filesystem, return direct path
return `/api/documents/download/${key}`;
}
}
```
### Step 2: Update Storage Service Factory
Modify `backend/src/core/storage/storage.service.ts`:
```typescript
import { FilesystemAdapter } from './adapters/filesystem.adapter';
export function getStorageService(): StorageService {
// Always use filesystem adapter
return new FilesystemAdapter('/app/data/documents');
}
```
### Step 3: Verify Documents Feature
No changes needed to documents.controller.ts - it uses StorageService interface.
Storage keys will be filesystem paths:
`documents/{userId}/{vehicleId}/{documentId}/{filename}`
### Step 4: Test Document Upload
```bash
# Rebuild backend
cd backend && npm run build
# Restart backend
docker compose restart mvp-backend
# Test upload (requires authentication)
curl -X POST https://admin.motovaultpro.com/api/documents \
-H "Authorization: Bearer $TOKEN" \
-F "file=@test.pdf" \
-F "vehicleId=123"
# Verify file exists
docker compose exec mvp-backend ls -la /app/data/documents/
```
## Validation Criteria
- [ ] FilesystemAdapter created
- [ ] getStorageService returns FilesystemAdapter
- [ ] Document upload works
- [ ] Document download works
- [ ] Files stored in /app/data/documents/
- [ ] No MinIO references in code
**Validation Command:**
```bash
grep -r "minio\|MinIO" backend/src/ | wc -l
# Expected: 0
```
## Update EXECUTION-STATE.json
```json
{
"phases": {"3": {"status": "completed", "validation_passed": true}}
}
```

View File

@@ -1,99 +0,0 @@
# Phase 4: Configuration Cleanup
## Agent Assignment
**Primary Agent:** config-agent
**Duration:** 20-30 minutes
## Prerequisites
- None (FIRST WAVE - starts immediately)
## Objectives
1. Remove MinIO configuration
2. Remove platform tenant service configuration
3. Remove platform API keys
4. Clean up secrets directory
5. Simplify environment variables
## Step-by-Step Instructions
### Step 1: Update config/app/production.yml
Remove these sections:
```yaml
# REMOVE:
minio:
endpoint: admin-minio
port: 9000
bucket: motovaultpro
platform_tenants:
api_url: http://mvp-platform-tenants:8000
api_key: ${PLATFORM_TENANTS_API_KEY}
# UPDATE:
platform_vehicles:
api_url: http://mvp-platform:8000 # No API key needed (same network)
```
### Step 2: Update .env
```bash
# REMOVE these lines:
# PLATFORM_VEHICLES_API_KEY=
# MINIO_ENDPOINT=
# MINIO_ACCESS_KEY=
# MINIO_SECRET_KEY=
# PLATFORM_TENANTS_API_URL=
# UPDATE these:
PLATFORM_VEHICLES_API_URL=http://mvp-platform:8000
DATABASE_URL=postgresql://postgres:password@mvp-postgres:5432/motovaultpro
REDIS_URL=redis://mvp-redis:6379
```
### Step 3: Delete Secret Files
```bash
# Delete MinIO secrets
rm secrets/app/minio-access-key.txt
rm secrets/app/minio-secret-key.txt
# Delete platform API key
rm secrets/app/platform-vehicles-api-key.txt
# Delete platform secrets directory
rm -rf secrets/platform/
```
### Step 4: Verify No Sensitive References
```bash
grep -r "minio" config/
grep -r "platform-vehicles-api-key" config/
grep -r "platform-tenants" config/
# All should return 0 results
```
## Validation Criteria
- [ ] config/app/production.yml has no MinIO section
- [ ] config/app/production.yml has no platform tenant section
- [ ] .env has no MINIO_* variables
- [ ] .env has no PLATFORM_VEHICLES_API_KEY
- [ ] secrets/app/minio-*.txt deleted
- [ ] secrets/platform/ deleted
- [ ] Platform vehicles URL points to mvp-platform
**Validation Command:**
```bash
grep -E "minio|MINIO" config/ .env
# Expected: 0 results
```
## Blocks
This phase MUST complete before:
- Phase 1 (infra-agent needs clean config)
- Phase 2 (backend-agent needs clean config)
## Update EXECUTION-STATE.json
```json
{
"phases": {"4": {"status": "completed", "validation_passed": true}},
"waves": {"1": {"status": "completed"}}
}
```

View File

@@ -1,100 +0,0 @@
# Phase 5: Network Simplification
## Agent Assignment
**Primary Agent:** infra-agent
**Duration:** 15 minutes
## Prerequisites
- Phase 1 (Docker Compose) must be complete
## Objectives
1. Reduce networks from 5 to 3
2. Remove platform and egress networks
3. Update service network assignments
4. Maintain proper isolation
## Step-by-Step Instructions
### Step 1: Update docker-compose.yml Networks Section
**Remove these networks:**
```yaml
# DELETE:
platform:
driver: bridge
egress:
driver: bridge
```
**Keep these networks:**
```yaml
networks:
frontend:
driver: bridge
backend:
driver: bridge
database:
driver: bridge
```
### Step 2: Update Service Network Assignments
```yaml
mvp-traefik:
networks:
- frontend
mvp-frontend:
networks:
- frontend
- backend # Needs to reach backend API
mvp-backend:
networks:
- backend
- database # Needs to reach postgres and redis
mvp-postgres:
networks:
- database
mvp-redis:
networks:
- database
mvp-platform:
networks:
- backend # Reached by mvp-backend
- database # Reaches postgres and redis
```
### Step 3: Restart Services
```bash
docker compose down
docker compose up -d
```
### Step 4: Verify Network Configuration
```bash
# List networks
docker network ls | grep motovaultpro
# Expected: 3 networks (frontend, backend, database)
# Test connectivity
docker compose exec mvp-backend ping -c 1 mvp-postgres
docker compose exec mvp-backend ping -c 1 mvp-platform
# Expected: Successful
```
## Validation Criteria
- [ ] Only 3 networks exist (frontend, backend, database)
- [ ] All services can communicate as needed
- [ ] No platform or egress networks
- [ ] Traefik routing still works
## Update EXECUTION-STATE.json
```json
{
"phases": {"5": {"status": "completed", "validation_passed": true}}
}
```

View File

@@ -1,76 +0,0 @@
# Phase 6: Backend Service Updates
## Agent Assignment
**Primary Agent:** backend-agent
**Duration:** 20 minutes
## Prerequisites
- Phase 2 (Remove Tenant) must be complete
## Objectives
1. Update database connection strings to use mvp-postgres
2. Update Redis connection strings to use mvp-redis
3. Update platform client URL to use mvp-platform
4. Remove API key authentication for platform service
## Step-by-Step Instructions
### Step 1: Update Config Loader
Modify `backend/src/core/config/config-loader.ts`:
```typescript
// Update database URL
const DATABASE_URL = process.env.DATABASE_URL ||
'postgresql://postgres:password@mvp-postgres:5432/motovaultpro';
// Update Redis URL
const REDIS_URL = process.env.REDIS_URL ||
'redis://mvp-redis:6379';
```
### Step 2: Update Platform Client
Modify `backend/src/features/vehicles/external/platform-vehicles/platform-vehicles.client.ts`:
```typescript
// Update base URL
private baseURL = process.env.PLATFORM_VEHICLES_API_URL ||
'http://mvp-platform:8000';
// REMOVE API key authentication (same network, no auth needed)
// DELETE:
// headers: { 'X-API-Key': this.apiKey }
```
### Step 3: Verify No Old Container Names
```bash
grep -r "admin-postgres" backend/src/
grep -r "admin-redis" backend/src/
grep -r "admin-backend" backend/src/
# Expected: 0 results for all
```
### Step 4: Rebuild and Test
```bash
cd backend
npm run build
docker compose restart mvp-backend
# Test platform connectivity
docker compose exec mvp-backend curl http://mvp-platform:8000/health
# Expected: 200 OK
```
## Validation Criteria
- [ ] All database URLs use mvp-postgres
- [ ] All Redis URLs use mvp-redis
- [ ] Platform client uses mvp-platform
- [ ] No API key for platform service
- [ ] Backend builds successfully
- [ ] Backend starts without errors
## Update EXECUTION-STATE.json
```json
{
"phases": {"6": {"status": "completed", "validation_passed": true}}
}
```

View File

@@ -1,64 +0,0 @@
# Phase 7: Database Updates
## Agent Assignment
**Primary Agent:** infra-agent
**Duration:** 15 minutes
## Prerequisites
- Phase 5 (Network Simplification) must be complete
## Objectives
1. Verify database schema has no tenant_id columns
2. Ensure all tables use user_id isolation only
3. Verify migrations don't reference tenants
## Step-by-Step Instructions
### Step 1: Connect to Database
```bash
docker compose exec mvp-postgres psql -U postgres -d motovaultpro
```
### Step 2: Verify No tenant_id Columns
```sql
SELECT table_name, column_name
FROM information_schema.columns
WHERE table_schema = 'public'
AND column_name = 'tenant_id';
```
**Expected:** 0 rows
### Step 3: Verify user_id Columns Exist
```sql
SELECT table_name
FROM information_schema.columns
WHERE table_schema = 'public'
AND column_name = 'user_id';
```
**Expected:** vehicles, fuel_logs, maintenance_logs, documents, etc.
### Step 4: Check Migrations
```bash
grep -r "tenant" backend/src/_system/migrations/
# Expected: 0 results (no tenant references)
```
### Step 5: Verify Platform Schema (if needed)
If mvp-platform uses separate schema:
```sql
CREATE SCHEMA IF NOT EXISTS vehicles_platform;
-- Platform service will initialize its tables
```
## Validation Criteria
- [ ] No tenant_id columns in application database
- [ ] All tables have user_id for isolation
- [ ] Migrations have no tenant references
- [ ] Database accessible from mvp-backend and mvp-platform
## Update EXECUTION-STATE.json
```json
{
"phases": {"7": {"status": "completed", "validation_passed": true}}
}
```

View File

@@ -1,156 +0,0 @@
# Phase 8: Platform Service Simplification
## Agent Assignment
**Primary Agent:** platform-agent
**Duration:** 35-45 minutes
## Prerequisites
- Phase 1 (Docker Compose) must be complete
## Objectives
1. Remove MSSQL database dependency
2. Remove ETL container and pipeline
3. Update to use mvp-postgres and mvp-redis
4. Load VPIC data at startup (not weekly ETL)
5. Simplify to single container
## Step-by-Step Instructions
### Step 1: Update Platform Service Config
Modify `mvp-platform-services/vehicles/config.py`:
```python
# Update database connection
DATABASE_URL = os.getenv(
'DATABASE_URL',
'postgresql://postgres:password@mvp-postgres:5432/motovaultpro'
)
# Update Redis connection
REDIS_URL = os.getenv(
'REDIS_URL',
'redis://mvp-redis:6379'
)
# Use vehicles_platform schema for isolation
SCHEMA = 'vehicles_platform'
```
### Step 2: Update requirements.txt
Remove MSSQL dependencies:
```
# REMOVE:
# pymssql
# pyodbc
# KEEP:
psycopg2-binary
redis
fastapi
uvicorn
```
### Step 3: Remove ETL Code
```bash
cd mvp-platform-services/vehicles/
# Remove ETL scripts
rm -rf etl/
# Remove MSSQL migration scripts
rm -rf migrations/mssql/
```
### Step 4: Create Startup Data Loader
Create `mvp-platform-services/vehicles/startup_loader.py`:
```python
"""Load VPIC data at service startup"""
import asyncio
from database import get_db
from vpic_client import VPICClient
async def load_initial_data():
"""Load vehicle data from VPIC API at startup"""
db = await get_db()
vpic = VPICClient()
# Check if data already loaded
result = await db.fetch_one("SELECT COUNT(*) FROM vehicles_platform.makes")
if result[0] > 0:
print("Data already loaded, skipping...")
return
# Load makes, models, etc. from VPIC
print("Loading initial vehicle data...")
# Implementation here...
```
### Step 5: Update main.py
```python
from startup_loader import load_initial_data
@app.on_event("startup")
async def startup_event():
"""Run on service startup"""
await load_initial_data()
```
### Step 6: Update Dockerfile
```dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# No ETL dependencies needed
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```
### Step 7: Rebuild and Test
```bash
# Rebuild platform service
docker compose build mvp-platform
# Restart
docker compose up -d mvp-platform
# Check logs
docker compose logs mvp-platform
# Test API
curl http://localhost:8000/health
curl http://localhost:8000/vehicles/makes?year=2024
```
## Validation Criteria
- [ ] No MSSQL dependencies in requirements.txt
- [ ] No ETL code remains
- [ ] Uses mvp-postgres for database
- [ ] Uses mvp-redis for cache
- [ ] Service starts successfully
- [ ] API endpoints work
- [ ] VIN decode functional
**Validation Commands:**
```bash
grep -r "mssql\|pymssql\|pyodbc" mvp-platform-services/vehicles/
# Expected: 0 results
docker compose exec mvp-platform python -c "import psycopg2; print('OK')"
# Expected: OK
curl http://localhost:8000/vehicles/makes?year=2024
# Expected: JSON response with makes
```
## Update EXECUTION-STATE.json
```json
{
"phases": {"8": {"status": "completed", "validation_passed": true}}
}
```

View File

@@ -1,155 +0,0 @@
# Phase 9: Documentation Updates
## Agent Assignment
**Primary Agent:** docs-agent
**Duration:** 30-40 minutes
## Prerequisites
- None (FIRST WAVE - can start immediately)
## Objectives
1. Update all documentation for 6-container architecture
2. Remove multi-tenant documentation
3. Update container names throughout
4. Update Makefile commands
5. Update AI context files
## Step-by-Step Instructions
### Step 1: Update README.md
```markdown
# Change from:
Modular monolith application with independent platform microservices.
# To:
Simplified 6-container architecture with integrated platform service.
## Quick Start (containers)
# Update all commands with new names:
make setup # Uses mvp-* containers
make start # Starts 6 services
```
### Step 2: Update CLAUDE.md
Remove multi-tenant sections:
```markdown
# REMOVE sections about:
- Multi-tenant architecture
- Tenant-specific database URLs
- Platform service independence (simplify to integrated service)
# UPDATE:
- Container names (admin-* → mvp-*)
- Architecture description (14 → 6 containers)
```
### Step 3: Update AI-INDEX.md
```markdown
# Update architecture line:
- Architecture: Simplified 6-container stack (was: Hybrid platform)
# Remove:
- Platform service development sections
- Tenant management guidance
```
### Step 4: Update .ai/context.json
```json
{
"architecture": "simplified-6-container",
"critical_requirements": {
"mobile_desktop_development": true,
"docker_first": true,
"multi_tenant": false // CHANGED
},
"services": {
"mvp-traefik": "...",
"mvp-frontend": "...",
"mvp-backend": "...",
"mvp-postgres": "...",
"mvp-redis": "...",
"mvp-platform": "..."
}
}
```
### Step 5: Update Makefile
Replace all container name references:
```makefile
# Find and replace:
sed -i.bak 's/admin-backend/mvp-backend/g' Makefile
sed -i.bak 's/admin-frontend/mvp-frontend/g' Makefile
sed -i.bak 's/admin-postgres/mvp-postgres/g' Makefile
sed -i.bak 's/admin-redis/mvp-redis/g' Makefile
# Update help text:
echo "MotoVaultPro - Simplified 6-Container Architecture"
```
### Step 6: Update docs/PLATFORM-SERVICES.md
```markdown
# Simplify to document only mvp-platform service
# Remove:
- mvp-platform-tenants documentation
- mvp-platform-landing documentation
- ETL pipeline documentation
# Update:
- Service now uses mvp-postgres and mvp-redis
- No separate database instances
```
### Step 7: Update docs/TESTING.md
```markdown
# Update all container names in test commands:
make shell-backend # Now uses mvp-backend
docker compose exec mvp-backend npm test
# Remove:
- Platform service test setup
- Tenant context in integration tests
```
### Step 8: Update Feature READMEs
```bash
# Update each feature README:
for feature in vehicles fuel-logs maintenance stations documents; do
sed -i.bak 's/admin-backend/mvp-backend/g' \
backend/src/features/$feature/README.md
done
```
### Step 9: Verify No Old References
```bash
grep -r "admin-backend\|admin-frontend\|admin-postgres" \
README.md CLAUDE.md docs/ Makefile
# Expected: 0 results
grep -r "14 containers\|fourteen containers" docs/
# Expected: 0 results
```
## Validation Criteria
- [ ] README.md describes 6-container architecture
- [ ] CLAUDE.md has no multi-tenant guidance
- [ ] AI-INDEX.md updated
- [ ] .ai/context.json updated
- [ ] Makefile uses mvp-* names
- [ ] docs/PLATFORM-SERVICES.md simplified
- [ ] docs/TESTING.md updated
- [ ] Feature READMEs updated
- [ ] No old container name references
**Validation Command:**
```bash
grep -r "admin-backend" docs/ README.md CLAUDE.md Makefile | wc -l
# Expected: 0
```
## Update EXECUTION-STATE.json
```json
{
"phases": {"9": {"status": "completed", "validation_passed": true}},
"waves": {"1": {"status": "completed"}}
}
```

View File

@@ -1,119 +0,0 @@
# Phase 10: Frontend Updates
## Agent Assignment
**Primary Agent:** frontend-agent
**Duration:** 25-35 minutes
## Prerequisites
- Phase 6 (Backend Updates) must be complete
## Objectives
1. Remove tenant selection UI (if exists)
2. Update Auth0 integration (no tenant claims)
3. Remove tenant management API client
4. Verify all API calls work with simplified backend
## Step-by-Step Instructions
### Step 1: Search for Tenant References
```bash
cd frontend/src
grep -r "tenant" .
# Review results to identify tenant-related code
```
### Step 2: Remove Tenant UI Components (if they exist)
```bash
# Common locations:
rm -f src/components/TenantSelector.tsx
rm -f src/components/TenantContext.tsx
rm -f src/contexts/TenantContext.tsx
```
### Step 3: Update Auth0 Integration
Modify auth configuration to not extract tenant_id:
```typescript
// In auth setup file:
// REMOVE:
// const tenantId = user?.['https://motovaultpro.com/tenant_id'];
// KEEP only:
const userId = user?.sub;
const roles = user?.['https://motovaultpro.com/roles'] || [];
```
### Step 4: Remove Tenant Management API Client
```bash
# If exists:
rm src/core/api/tenantManagementClient.ts
```
### Step 5: Update App.tsx
```typescript
// Remove tenant provider if exists:
// DELETE:
// <TenantProvider>
// <App />
// </TenantProvider>
```
### Step 6: Verify API Clients
Check that API clients don't send tenant headers:
```typescript
// Ensure API client doesn't include:
// headers: { 'X-Tenant-Id': tenantId }
```
### Step 7: Build Frontend
```bash
cd frontend
npm run build
# Expected: No errors
```
### Step 8: Test in Browser
```bash
docker compose restart mvp-frontend
# Open browser
open https://admin.motovaultpro.com
# Test:
- Login via Auth0
- Create vehicle
- Upload document
- Create fuel log
# All should work without tenant context
```
### Step 9: Check Console for Errors
```
# In browser console:
# Expected: No tenant-related errors
# Expected: No API call failures
```
## Validation Criteria
- [ ] No tenant UI components
- [ ] Auth0 doesn't extract tenant_id
- [ ] No tenant management API client
- [ ] Frontend builds successfully
- [ ] Application loads without errors
- [ ] All features work
- [ ] No console errors
**Validation Commands:**
```bash
npm run build
# Expected: Build successful
grep -r "tenant" frontend/src/ | wc -l
# Expected: 0 or minimal (only in comments)
```
## Update EXECUTION-STATE.json
```json
{
"phases": {"10": {"status": "completed", "validation_passed": true}}
}
```

View File

@@ -1,269 +0,0 @@
# Phase 11: Testing and Validation
## Agent Assignment
**Primary Agent:** test-agent
**Duration:** 20-30 minutes
## Prerequisites
- ALL phases 1-10 must be complete
- All agents must report success
## Objectives
1. Verify all 6 containers are healthy
2. Run full test suite (backend + frontend)
3. Validate all features work end-to-end
4. Confirm no regressions
5. Final architecture validation
## Step-by-Step Instructions
### Step 1: Verify Container Health
```bash
# Check all containers running
docker compose ps
# Expected: 6 services, all "running (healthy)"
# Verify services:
# - mvp-traefik
# - mvp-frontend
# - mvp-backend
# - mvp-postgres
# - mvp-redis
# - mvp-platform
```
### Step 2: Run Backend Tests
```bash
# Enter backend container
docker compose exec mvp-backend npm test
# Expected: All tests pass
# No failures related to tenants, MinIO, or old service names
```
### Step 3: Run Frontend Tests
```bash
# Run frontend tests
make test-frontend
# Expected: All tests pass
```
### Step 4: Test Core Features
**Authentication:**
```bash
# Test Auth0 login
curl -s -k https://admin.motovaultpro.com/api/health
# Expected: 200 OK
```
**Vehicles:**
```bash
# Test vehicle creation
curl -X POST https://admin.motovaultpro.com/api/vehicles \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"vin": "1HGBH41JXMN109186", "nickname": "Test"}'
# Expected: 201 Created
```
**Documents:**
```bash
# Test document upload
curl -X POST https://admin.motovaultpro.com/api/documents \
-H "Authorization: Bearer $TOKEN" \
-F "file=@test.pdf" \
-F "vehicleId=123"
# Expected: 201 Created
# Verify file in filesystem
docker compose exec mvp-backend ls /app/data/documents/
# Expected: Files exist
```
**Platform Service:**
```bash
# Test vehicle makes endpoint
curl http://localhost:8000/vehicles/makes?year=2024
# Expected: JSON array of makes
```
### Step 5: Architecture Validation
**Container Count:**
```bash
docker compose ps --services | wc -l
# Expected: 6
```
**Network Count:**
```bash
docker network ls | grep motovaultpro | wc -l
# Expected: 3 (frontend, backend, database)
```
**Volume Count:**
```bash
docker volume ls | grep mvp | wc -l
# Expected: 2 (mvp_postgres_data, mvp_redis_data)
```
### Step 6: Code Quality Checks
**No Tenant References:**
```bash
grep -r "tenant_id" backend/src/features/ | wc -l
# Expected: 0
```
**No Old Container Names:**
```bash
grep -r "admin-backend\|admin-frontend\|admin-postgres" \
backend/ frontend/ docs/ | wc -l
# Expected: 0
```
**No MinIO References:**
```bash
grep -r "minio\|MinIO" backend/src/ | wc -l
# Expected: 0
```
### Step 7: Performance Check
**Startup Time:**
```bash
time docker compose up -d
# Should be faster than before (fewer containers)
```
**Memory Usage:**
```bash
docker stats --no-stream
# Total memory should be lower than 14-container setup
```
### Step 8: Mobile Testing
```bash
# Test responsive design
# Access https://admin.motovaultpro.com on mobile
# Verify all features work
```
### Step 9: Final Clean Rebuild
```bash
# Ultimate test: clean rebuild
make clean
make setup
# Expected:
# - All 6 containers start
# - Migrations run successfully
# - Application accessible
# - Tests pass
```
## Validation Criteria
### Critical Validations (Must Pass)
- [ ] Exactly 6 containers running
- [ ] All containers healthy
- [ ] Backend tests pass (100%)
- [ ] Frontend tests pass (100%)
- [ ] No tenant_id in application code
- [ ] No old container names in code/docs
- [ ] No MinIO references
- [ ] All features functional
### Integration Validations
- [ ] Auth0 login works
- [ ] Vehicle CRUD works
- [ ] Document upload/download works
- [ ] Fuel logs work
- [ ] Maintenance logs work
- [ ] Stations work
### Architecture Validations
- [ ] 3 networks configured
- [ ] 2 volumes (postgres, redis)
- [ ] Traefik routing works
- [ ] Platform service accessible
## Validation Report
Create validation report:
```bash
cat > docs/redesign/VALIDATION-REPORT-$(date +%Y%m%d).md <<EOF
# Simplification Validation Report
Date: $(date)
## Container Status
$(docker compose ps)
## Test Results
Backend: PASS/FAIL
Frontend: PASS/FAIL
## Architecture Metrics
Containers: 6
Networks: 3
Volumes: 2
## Feature Testing
- Authentication: PASS/FAIL
- Vehicles: PASS/FAIL
- Documents: PASS/FAIL
- Fuel Logs: PASS/FAIL
- Maintenance: PASS/FAIL
- Stations: PASS/FAIL
## Code Quality
Tenant references: 0
Old container names: 0
MinIO references: 0
## Conclusion
Simplification: SUCCESS/FAILURE
Ready for production: YES/NO
EOF
```
## Final Update to EXECUTION-STATE.json
```json
{
"status": "completed",
"completed_at": "[timestamp]",
"phases": {
"11": {
"status": "completed",
"validation_passed": true,
"duration_minutes": 25
}
},
"validations": {
"docker_compose_valid": true,
"backend_builds": true,
"frontend_builds": true,
"tests_pass": true,
"containers_healthy": true,
"no_tenant_references": true,
"no_minio_references": true,
"no_old_container_names": true
}
}
```
## Success Criteria
If all validations pass:
- Architecture successfully simplified
- 14 → 6 containers (57% reduction)
- All features functional
- No regressions
- Ready for production deployment
## If Failures Occur
1. Review VALIDATION-REPORT
2. Identify failing phase
3. Consult ROLLBACK-STRATEGY.md
4. Decide: fix and retry OR rollback

View File

@@ -1,203 +0,0 @@
# MotoVaultPro Simplification - AI Agent Coordination
## Overview
This directory contains comprehensive documentation for executing the MotoVaultPro simplification using multiple AI agents working in parallel. The goal is to transform the current 14-container microservices architecture into a streamlined 6-container stack.
## Architecture Transformation
### Current State (14 containers)
- traefik, admin-frontend, admin-backend, admin-postgres, admin-redis, admin-minio
- mvp-platform-landing, mvp-platform-tenants, mvp-platform-vehicles-api
- platform-postgres, platform-redis, mvp-platform-vehicles-db, mvp-platform-vehicles-redis, mvp-platform-vehicles-etl
### Target State (6 containers)
1. **mvp-traefik** - Reverse proxy and SSL termination
2. **mvp-frontend** - React application
3. **mvp-backend** - Fastify API server
4. **mvp-postgres** - PostgreSQL database
5. **mvp-redis** - Redis cache
6. **mvp-platform** - Simplified vehicles service
## Key Simplifications
1. **Remove Multi-Tenancy** - Application already uses user_id isolation
2. **Replace MinIO** - Use filesystem storage with mounted volume
3. **Consolidate Databases** - 3 PostgreSQL instances → 1 instance
4. **Consolidate Caches** - 3 Redis instances → 1 instance
5. **Simplify Platform Service** - Remove ETL pipeline and MSSQL dependency
6. **Consistent Naming** - All services use mvp-* prefix
## Documentation Structure
### Core Documentation
- **README.md** (this file) - Master coordination document
- **AGENT-MANIFEST.md** - Agent assignments and dependency graph
- **DEPENDENCY-GRAPH.md** - Visual phase dependencies
- **FILE-MANIFEST.md** - Complete file change inventory
- **VALIDATION-CHECKLIST.md** - Success criteria and validation steps
- **ROLLBACK-STRATEGY.md** - Rollback procedures
- **EXECUTION-STATE.json** - Shared state tracking (runtime)
### Phase Documentation (11 files)
- **PHASE-01-DOCKER-COMPOSE.md** - Container renaming and docker-compose.yml
- **PHASE-02-REMOVE-TENANT.md** - Multi-tenant architecture removal
- **PHASE-03-FILESYSTEM-STORAGE.md** - MinIO to filesystem migration
- **PHASE-04-CONFIG-CLEANUP.md** - Configuration and secrets cleanup
- **PHASE-05-NETWORK-SIMPLIFICATION.md** - Network architecture updates
- **PHASE-06-BACKEND-UPDATES.md** - Backend code updates
- **PHASE-07-DATABASE-UPDATES.md** - Database schema updates
- **PHASE-08-PLATFORM-SERVICE.md** - mvp-platform service simplification
- **PHASE-09-DOCUMENTATION.md** - Documentation updates
- **PHASE-10-FRONTEND-UPDATES.md** - Frontend updates
- **PHASE-11-TESTING.md** - Testing and validation
## Agent Execution Strategy
### 8 Specialized Agents
1. **infra-agent** - Phases 1, 5, 7 (Docker, networks, databases)
2. **backend-agent** - Phases 2, 6 (Backend code)
3. **storage-agent** - Phase 3 (MinIO to filesystem)
4. **platform-agent** - Phase 8 (mvp-platform service)
5. **config-agent** - Phase 4 (Configuration cleanup)
6. **frontend-agent** - Phase 10 (Frontend updates)
7. **docs-agent** - Phase 9 (Documentation)
8. **test-agent** - Phase 11 (Testing and validation)
### Execution Waves
**Wave 1 (Parallel - No Dependencies):**
- config-agent (Phase 4)
- docs-agent (Phase 9)
**Wave 2 (Parallel - After Wave 1):**
- infra-agent starts (Phase 1)
- backend-agent starts (Phase 2)
- storage-agent starts (Phase 3)
**Wave 3 (Parallel - After Wave 2):**
- infra-agent continues (Phases 5, 7)
- backend-agent continues (Phase 6)
- platform-agent starts (Phase 8)
**Wave 4 (Sequential):**
- frontend-agent (Phase 10)
**Wave 5 (Sequential - Validates Everything):**
- test-agent (Phase 11)
## Getting Started
### For Orchestration AI
1. **Read Core Documentation:**
- AGENT-MANIFEST.md - Understand agent assignments
- DEPENDENCY-GRAPH.md - Understand execution order
- FILE-MANIFEST.md - Understand file changes
2. **Spawn Agents in Waves:**
```
Wave 1: config-agent, docs-agent
Wave 2: infra-agent, backend-agent, storage-agent (wait for Wave 1)
Wave 3: Continue Wave 2 agents, add platform-agent
Wave 4: frontend-agent (wait for backend-agent)
Wave 5: test-agent (wait for all)
```
3. **Monitor Execution:**
- Track EXECUTION-STATE.json for phase completion
- Watch for conflict notifications
- Validate each wave before starting next
### For Individual Agents
1. **Read Assignment:**
- Check AGENT-MANIFEST.md for your phases
- Review DEPENDENCY-GRAPH.md for prerequisites
2. **Execute Phases:**
- Read PHASE-*.md for detailed instructions
- Follow step-by-step procedures
- Run validation checks
- Update EXECUTION-STATE.json
3. **Coordinate:**
- Check for file locks before modifying
- Report conflicts in AGENT-LOG.md
- Wait for dependent phases to complete
## Success Criteria
### Per-Phase Success
- All validation checks pass
- No file conflicts
- Changes follow coding standards
### Integration Success
- `make rebuild` succeeds
- All 6 containers start healthy
- `make test` passes (all tests green)
- No functionality regressions
### Final Acceptance
- 14 → 6 containers running
- 5 → 3 networks configured
- Multi-tenant code removed
- MinIO replaced with filesystem
- Platform service simplified
- Documentation updated
- All tests passing
## Timeline Estimate
**Sequential Execution:** ~8-12 hours
**Parallel Execution (8 agents):** ~2-3 hours (60-70% time reduction)
## Risk Mitigation
1. **Git Branching:** Each phase works on feature branch
2. **Incremental Validation:** Test after each phase
3. **Rollback Capability:** Each phase documents rollback
4. **Conflict Detection:** File locks prevent concurrent edits
5. **State Tracking:** EXECUTION-STATE.json tracks progress
## Communication Protocols
### State Updates
Agents update EXECUTION-STATE.json when:
- Starting a phase
- Completing a phase
- Encountering conflicts
- Requiring coordination
### Conflict Resolution
If file conflict detected:
1. Agent creates lock file
2. Other agent waits
3. First agent completes work
4. Lock released
5. Second agent proceeds
### Error Handling
If phase fails:
1. Agent reports in EXECUTION-STATE.json
2. Dependent phases are blocked
3. Orchestrator decides: retry or rollback
4. Follow ROLLBACK-STRATEGY.md if needed
## Next Steps
1. **Orchestration AI:** Review AGENT-MANIFEST.md
2. **Spawn Wave 1:** config-agent and docs-agent
3. **Monitor Progress:** Track EXECUTION-STATE.json
4. **Spawn Wave 2:** After Wave 1 completes
5. **Continue Through Waves:** Until test-agent passes
## Questions or Issues
Refer to specific phase documentation for detailed guidance. Each PHASE-*.md file contains:
- Step-by-step instructions
- Validation criteria
- Rollback procedures
- Conflict resolution guidance

View File

@@ -1,545 +0,0 @@
# Rollback Strategy - Recovery Procedures
## Overview
This document provides comprehensive rollback procedures for each phase of the simplification. Each phase can be rolled back independently, and full system rollback is available.
## Pre-Execution Backup
### Before Starting ANY Phase
```bash
# 1. Create backup branch
git checkout -b backup-$(date +%Y%m%d-%H%M%S)
git push origin backup-$(date +%Y%m%d-%H%M%S)
# 2. Tag current state
git tag -a pre-simplification-$(date +%Y%m%d) \
-m "State before architecture simplification"
git push origin --tags
# 3. Export docker volumes
docker run --rm -v admin_postgres_data:/data -v $(pwd):/backup \
alpine tar czf /backup/postgres-backup-$(date +%Y%m%d).tar.gz /data
docker run --rm -v admin_redis_data:/data -v $(pwd):/backup \
alpine tar czf /backup/redis-backup-$(date +%Y%m%d).tar.gz /data
# 4. Export MinIO data (if documents exist)
docker run --rm -v admin_minio_data:/data -v $(pwd):/backup \
alpine tar czf /backup/minio-backup-$(date +%Y%m%d).tar.gz /data
# 5. Document current state
docker compose ps > container-state-$(date +%Y%m%d).txt
docker network ls > network-state-$(date +%Y%m%d).txt
```
---
## Per-Phase Rollback Procedures
### Phase 1: Docker Compose Rollback
**Rollback Trigger:**
- docker-compose.yml validation fails
- Containers fail to start
- Network errors
- Volume mount issues
**Rollback Steps:**
```bash
# 1. Stop current containers
docker compose down
# 2. Restore docker-compose.yml
git checkout HEAD~1 -- docker-compose.yml
# 3. Restart with original config
docker compose up -d
# 4. Verify original state
docker compose ps # Should show 14 containers
```
**Validation:**
- [ ] 14 containers running
- [ ] All containers healthy
- [ ] No errors in logs
**Risk:** Low - file-based rollback, no data loss
---
### Phase 2: Remove Tenant Rollback
**Rollback Trigger:**
- Build errors after tenant code removal
- Application won't start
- Tests failing
- Missing functionality
**Rollback Steps:**
```bash
# 1. Restore deleted files
git checkout HEAD~1 -- backend/src/core/middleware/tenant.ts
git checkout HEAD~1 -- backend/src/core/config/tenant.ts
git checkout HEAD~1 -- backend/src/features/tenant-management/
# 2. Restore modified files
git checkout HEAD~1 -- backend/src/app.ts
git checkout HEAD~1 -- backend/src/core/plugins/auth.plugin.ts
# 3. Rebuild backend
cd backend
npm install
npm run build
# 4. Restart backend container
docker compose restart mvp-backend # or admin-backend if Phase 1 not done
```
**Validation:**
- [ ] Backend builds successfully
- [ ] Backend starts without errors
- [ ] Tests pass
- [ ] Tenant functionality restored
**Risk:** Low-Medium - code rollback, no data impact
---
### Phase 3: Filesystem Storage Rollback
**Rollback Trigger:**
- Document upload/download fails
- File system errors
- Permission issues
- Data access errors
**Rollback Steps:**
```bash
# 1. Stop backend
docker compose stop mvp-backend
# 2. Restore storage adapter
git checkout HEAD~1 -- backend/src/core/storage/
# 3. Restore documents feature
git checkout HEAD~1 -- backend/src/features/documents/
# 4. Re-add MinIO to docker-compose.yml
git checkout HEAD~1 -- docker-compose.yml
# (Only MinIO service, keep other Phase 1 changes if applicable)
# 5. Restore MinIO data if backed up
docker volume create admin_minio_data
docker run --rm -v admin_minio_data:/data -v $(pwd):/backup \
alpine tar xzf /backup/minio-backup-YYYYMMDD.tar.gz -C /
# 6. Rebuild and restart
docker compose up -d admin-minio
docker compose restart mvp-backend
```
**Validation:**
- [ ] MinIO container running
- [ ] Document upload works
- [ ] Document download works
- [ ] Existing documents accessible
**Risk:** Medium - requires MinIO restore, potential data migration
---
### Phase 4: Config Cleanup Rollback
**Rollback Trigger:**
- Service connection failures
- Authentication errors
- Missing configuration
- Environment variable errors
**Rollback Steps:**
```bash
# 1. Restore config files
git checkout HEAD~1 -- config/app/production.yml
git checkout HEAD~1 -- .env
git checkout HEAD~1 -- .env.development
# 2. Restore secrets
git checkout HEAD~1 -- secrets/app/
git checkout HEAD~1 -- secrets/platform/
# 3. Restart affected services
docker compose restart mvp-backend mvp-platform
```
**Validation:**
- [ ] Backend connects to database
- [ ] Backend connects to Redis
- [ ] Platform service accessible
- [ ] Auth0 integration works
**Risk:** Low - configuration rollback, no data loss
---
### Phase 5: Network Simplification Rollback
**Rollback Trigger:**
- Service discovery failures
- Network isolation broken
- Container communication errors
- Traefik routing issues
**Rollback Steps:**
```bash
# 1. Stop all services
docker compose down
# 2. Remove simplified networks
docker network rm motovaultpro_frontend motovaultpro_backend motovaultpro_database
# 3. Restore network configuration
git checkout HEAD~1 -- docker-compose.yml
# (Restore only networks section if possible)
# 4. Recreate networks and restart
docker compose up -d
# 5. Verify routing
curl http://localhost:8080/api/http/routers # Traefik dashboard
```
**Validation:**
- [ ] All 5 networks exist
- [ ] Services can communicate
- [ ] Traefik routes correctly
- [ ] No network errors
**Risk:** Medium - requires container restart, brief downtime
---
### Phase 6: Backend Updates Rollback
**Rollback Trigger:**
- Service reference errors
- API connection failures
- Database connection issues
- Build failures
**Rollback Steps:**
```bash
# 1. Restore backend code
git checkout HEAD~1 -- backend/src/core/config/config-loader.ts
git checkout HEAD~1 -- backend/src/features/vehicles/external/
# 2. Rebuild backend
cd backend
npm run build
# 3. Restart backend
docker compose restart mvp-backend
```
**Validation:**
- [ ] Backend starts successfully
- [ ] Connects to database
- [ ] Platform client works
- [ ] Tests pass
**Risk:** Low - code rollback, no data impact
---
### Phase 7: Database Updates Rollback
**Rollback Trigger:**
- Database connection failures
- Schema errors
- Migration failures
- Data access issues
**Rollback Steps:**
```bash
# 1. Restore database configuration
git checkout HEAD~1 -- backend/src/_system/migrations/
git checkout HEAD~1 -- docker-compose.yml
# (Only database section)
# 2. Restore database volume if corrupted
docker compose down mvp-postgres
docker volume rm mvp_postgres_data
docker volume create admin_postgres_data
docker run --rm -v admin_postgres_data:/data -v $(pwd):/backup \
alpine tar xzf /backup/postgres-backup-YYYYMMDD.tar.gz -C /
# 3. Restart database
docker compose up -d mvp-postgres
# 4. Re-run migrations if needed
docker compose exec mvp-backend node dist/_system/migrations/run-all.js
```
**Validation:**
- [ ] Database accessible
- [ ] All tables exist
- [ ] Data intact
- [ ] Migrations current
**Risk:** High - potential data loss if volume restore needed
---
### Phase 8: Platform Service Rollback
**Rollback Trigger:**
- Platform API failures
- Database connection errors
- Service crashes
- API endpoint errors
**Rollback Steps:**
```bash
# 1. Stop simplified platform service
docker compose down mvp-platform
# 2. Restore platform service files
git checkout HEAD~1 -- mvp-platform-services/vehicles/
# 3. Restore full platform architecture in docker-compose.yml
git checkout HEAD~1 -- docker-compose.yml
# (Only platform services section)
# 4. Restore platform database
docker volume create mvp_platform_vehicles_db_data
docker run --rm -v mvp_platform_vehicles_db_data:/data -v $(pwd):/backup \
alpine tar xzf /backup/platform-db-backup-YYYYMMDD.tar.gz -C /
# 5. Restart all platform services
docker compose up -d mvp-platform-vehicles-api mvp-platform-vehicles-db \
mvp-platform-vehicles-redis mvp-platform-vehicles-etl
```
**Validation:**
- [ ] Platform service accessible
- [ ] API endpoints work
- [ ] VIN decode works
- [ ] Hierarchical data loads
**Risk:** Medium-High - requires multi-container restore
---
### Phase 9: Documentation Rollback
**Rollback Trigger:**
- Incorrect documentation
- Missing instructions
- Broken links
- Confusion among team
**Rollback Steps:**
```bash
# 1. Restore all documentation
git checkout HEAD~1 -- README.md CLAUDE.md AI-INDEX.md
git checkout HEAD~1 -- docs/
git checkout HEAD~1 -- .ai/context.json
git checkout HEAD~1 -- Makefile
git checkout HEAD~1 -- backend/src/features/*/README.md
```
**Validation:**
- [ ] Documentation accurate
- [ ] Examples work
- [ ] Makefile commands work
**Risk:** None - documentation only, no functional impact
---
### Phase 10: Frontend Rollback
**Rollback Trigger:**
- Build errors
- Runtime errors
- UI broken
- API calls failing
**Rollback Steps:**
```bash
# 1. Restore frontend code
git checkout HEAD~1 -- frontend/src/
# 2. Rebuild frontend
cd frontend
npm install
npm run build
# 3. Restart frontend container
docker compose restart mvp-frontend
```
**Validation:**
- [ ] Frontend builds successfully
- [ ] UI loads without errors
- [ ] Auth works
- [ ] API calls work
**Risk:** Low - frontend rollback, no data impact
---
### Phase 11: Testing Rollback
**Note:** Testing phase doesn't modify code, only validates. If tests fail, rollback appropriate phases based on failure analysis.
---
## Full System Rollback
### Complete Rollback to Pre-Simplification State
**When to Use:**
- Multiple phases failing
- Unrecoverable errors
- Production blocker
- Need to abort entire simplification
**Rollback Steps:**
```bash
# 1. Stop all services
docker compose down
# 2. Restore entire codebase
git checkout pre-simplification
# 3. Restore volumes
docker volume rm mvp_postgres_data mvp_redis_data
docker volume create admin_postgres_data admin_redis_data admin_minio_data
docker run --rm -v admin_postgres_data:/data -v $(pwd):/backup \
alpine tar xzf /backup/postgres-backup-YYYYMMDD.tar.gz -C /
docker run --rm -v admin_redis_data:/data -v $(pwd):/backup \
alpine tar xzf /backup/redis-backup-YYYYMMDD.tar.gz -C /
docker run --rm -v admin_minio_data:/data -v $(pwd):/backup \
alpine tar xzf /backup/minio-backup-YYYYMMDD.tar.gz -C /
# 4. Restart all services
docker compose up -d
# 5. Verify original state
docker compose ps # Should show 14 containers
make test
```
**Validation:**
- [ ] All 14 containers running
- [ ] All tests passing
- [ ] Application functional
- [ ] Data intact
**Duration:** 15-30 minutes
**Risk:** Low if backups are good
---
## Partial Rollback Scenarios
### Scenario 1: Keep Infrastructure Changes, Rollback Backend
```bash
# Keep Phase 1 (Docker), rollback Phases 2-11
git checkout pre-simplification -- backend/ frontend/
docker compose restart mvp-backend mvp-frontend
```
### Scenario 2: Keep Config Cleanup, Rollback Code
```bash
# Keep Phase 4, rollback Phases 1-3, 5-11
git checkout pre-simplification -- docker-compose.yml backend/src/ frontend/src/
```
### Scenario 3: Rollback Only Storage
```bash
# Rollback Phase 3 only
git checkout HEAD~1 -- backend/src/core/storage/ backend/src/features/documents/
docker compose up -d admin-minio
```
---
## Rollback Decision Matrix
| Failure Type | Rollback Scope | Risk | Duration |
|--------------|---------------|------|----------|
| Container start fails | Phase 1 | Low | 5 min |
| Build errors | Specific phase | Low | 10 min |
| Test failures | Investigate, partial | Medium | 15-30 min |
| Data corruption | Full + restore | High | 30-60 min |
| Network issues | Phase 5 | Medium | 10 min |
| Platform API down | Phase 8 | Medium | 15 min |
| Critical production bug | Full system | Medium | 30 min |
---
## Post-Rollback Actions
After any rollback:
1. **Document the Issue:**
```bash
# Create incident report
echo "Rollback performed: $(date)" >> docs/redesign/ROLLBACK-LOG.md
echo "Reason: [description]" >> docs/redesign/ROLLBACK-LOG.md
echo "Phases rolled back: [list]" >> docs/redesign/ROLLBACK-LOG.md
```
2. **Analyze Root Cause:**
- Review logs
- Identify failure point
- Document lessons learned
3. **Plan Fix:**
- Address root cause
- Update phase documentation
- Add validation checks
4. **Retry (if appropriate):**
- Apply fix
- Re-execute phase
- Validate thoroughly
---
## Emergency Contacts
If rollback fails or assistance needed:
- Technical Lead: [contact]
- DevOps Lead: [contact]
- Database Admin: [contact]
- Emergency Hotline: [contact]
---
## Rollback Testing
Before starting simplification, test rollback procedures:
```bash
# Dry run rollback
git checkout -b rollback-test
# Make test change
echo "test" > test.txt
git add test.txt
git commit -m "test"
# Rollback test
git checkout HEAD~1 -- test.txt
# Verify rollback works
git checkout main
git branch -D rollback-test
```

View File

@@ -1,446 +0,0 @@
# Validation Checklist - Success Criteria
## Per-Phase Validation
### Phase 1: Docker Compose (infra-agent)
**Container Renaming:**
- [ ] traefik → mvp-traefik
- [ ] admin-frontend → mvp-frontend
- [ ] admin-backend → mvp-backend
- [ ] admin-postgres → mvp-postgres
- [ ] admin-redis → mvp-redis
- [ ] mvp-platform-vehicles-api → mvp-platform
**Service Removal:**
- [ ] admin-minio removed
- [ ] mvp-platform-landing removed
- [ ] mvp-platform-tenants removed
- [ ] platform-postgres removed
- [ ] platform-redis removed
- [ ] mvp-platform-vehicles-db removed
- [ ] mvp-platform-vehicles-redis removed
- [ ] mvp-platform-vehicles-etl removed
**Configuration:**
- [ ] docker-compose.yml validates: `docker compose config`
- [ ] Volume mount added: `./data/documents:/app/data/documents`
- [ ] Network count reduced from 5 to 3
- [ ] All Traefik labels updated with new service names
**Validation Commands:**
```bash
docker compose config # Should validate without errors
docker compose ps # Should show 6 services only
```
---
### Phase 2: Remove Tenant (backend-agent)
**Code Deletion:**
- [ ] backend/src/core/middleware/tenant.ts deleted
- [ ] backend/src/core/config/tenant.ts deleted
- [ ] backend/src/features/tenant-management/ deleted
**Code Modification:**
- [ ] backend/src/app.ts - No tenant middleware import
- [ ] backend/src/app.ts - No tenant middleware registration
- [ ] backend/src/app.ts - No tenant-management routes
- [ ] backend/src/core/plugins/auth.plugin.ts - No tenant_id claim extraction
**No Tenant References:**
```bash
# Should return 0 results in application code
grep -r "tenant_id" backend/src/features/
grep -r "tenantId" backend/src/features/
grep -r "tenant-management" backend/src/
```
**Build Check:**
```bash
cd backend
npm run build # Should compile without errors
```
---
### Phase 3: Filesystem Storage (storage-agent)
**New Files:**
- [ ] backend/src/core/storage/adapters/filesystem.adapter.ts created
- [ ] Implements StorageService interface correctly
- [ ] data/documents/ directory exists
**Modified Files:**
- [ ] backend/src/core/storage/storage.service.ts uses FilesystemAdapter
- [ ] backend/src/features/documents/ updated for filesystem
**No MinIO References:**
```bash
# Should return 0 results
grep -r "minio" backend/src/
grep -r "MinIO" backend/src/
grep -r "s3" backend/src/core/storage/
```
**Functional Test:**
```bash
# Test document upload/download
curl -X POST http://localhost:3001/api/documents/upload \
-H "Authorization: Bearer $TOKEN" \
-F "file=@test.pdf"
# Verify file exists in ./data/documents/{userId}/
```
---
### Phase 4: Config Cleanup (config-agent)
**Config File Updates:**
- [ ] config/app/production.yml - No MinIO section
- [ ] config/app/production.yml - No platform tenant API
- [ ] config/app/production.yml - Platform vehicles URL = http://mvp-platform:8000
**Environment Updates:**
- [ ] .env - No MINIO_* variables
- [ ] .env - No PLATFORM_VEHICLES_API_KEY
- [ ] .env - DATABASE_URL uses mvp-postgres
- [ ] .env - REDIS_URL uses mvp-redis
**Secrets Deletion:**
- [ ] secrets/app/minio-access-key.txt deleted
- [ ] secrets/app/minio-secret-key.txt deleted
- [ ] secrets/app/platform-vehicles-api-key.txt deleted
- [ ] secrets/platform/ directory deleted
**Validation:**
```bash
# No sensitive references should remain
grep -r "minio" config/
grep -r "platform-vehicles-api-key" config/
```
---
### Phase 5: Network Simplification (infra-agent)
**Network Configuration:**
- [ ] Only 3 networks: frontend, backend, database
- [ ] platform network removed
- [ ] egress network removed
**Service Network Assignments:**
- [ ] mvp-traefik: frontend
- [ ] mvp-frontend: frontend, backend
- [ ] mvp-backend: backend, database
- [ ] mvp-postgres: database
- [ ] mvp-redis: database
- [ ] mvp-platform: backend, database
**Validation:**
```bash
docker network ls | grep motovaultpro
# Should show only 3 networks
docker compose config | grep -A5 "networks:"
# Verify correct network assignments
```
---
### Phase 6: Backend Updates (backend-agent)
**Service References:**
- [ ] All database URLs use mvp-postgres
- [ ] All Redis URLs use mvp-redis
- [ ] Platform client URL = http://mvp-platform:8000
**No Old Container Names:**
```bash
grep -r "admin-postgres" backend/src/
grep -r "admin-redis" backend/src/
grep -r "admin-backend" backend/src/
# Should all return 0 results
```
**Build and Start:**
```bash
make rebuild
make logs-backend # No errors
```
---
### Phase 7: Database Updates (infra-agent)
**Connection Strings:**
- [ ] Application uses mvp-postgres
- [ ] Platform service uses mvp-postgres
**Schema Validation:**
```bash
# Connect to database
make db-shell-app
# Verify tables exist
\dt
# Verify no tenant_id columns (only user_id)
SELECT column_name FROM information_schema.columns
WHERE table_schema = 'public' AND column_name = 'tenant_id';
# Should return 0 rows
```
---
### Phase 8: Platform Service (platform-agent)
**Service Simplification:**
- [ ] No MSSQL dependencies
- [ ] No ETL container
- [ ] Uses mvp-postgres and mvp-redis
- [ ] Single container deployment
**API Functionality:**
```bash
# Test platform service endpoints
curl http://localhost:8000/health
curl http://localhost:8000/vehicles/makes?year=2024
```
**No Old Dependencies:**
```bash
grep -r "mssql" mvp-platform-services/vehicles/
grep -r "pyodbc" mvp-platform-services/vehicles/
# Should return 0 results
```
---
### Phase 9: Documentation (docs-agent)
**Documentation Updates:**
- [ ] README.md reflects 6-container architecture
- [ ] CLAUDE.md no multi-tenant guidance
- [ ] AI-INDEX.md updated
- [ ] .ai/context.json updated
- [ ] docs/PLATFORM-SERVICES.md updated
- [ ] docs/TESTING.md updated
- [ ] Makefile uses mvp-* container names
**Consistency Check:**
```bash
# No old container names in docs
grep -r "admin-backend" docs/ README.md CLAUDE.md Makefile
grep -r "admin-frontend" docs/ README.md CLAUDE.md Makefile
# Should return 0 results
```
---
### Phase 10: Frontend Updates (frontend-agent)
**Code Updates:**
- [ ] No tenant selection UI
- [ ] No tenant context provider
- [ ] Auth0 integration updated (no tenant claims)
- [ ] API clients work
**Build Check:**
```bash
cd frontend
npm run build # Should build without errors
```
**No Tenant References:**
```bash
grep -r "tenant" frontend/src/
# Should return minimal/no results
```
---
### Phase 11: Testing (test-agent)
**Container Health:**
- [ ] All 6 containers running
- [ ] All containers healthy status
**Test Suite:**
- [ ] Backend tests pass: `make test`
- [ ] Frontend tests pass
- [ ] Integration tests pass
- [ ] No regressions
**Validation Commands:**
```bash
docker compose ps
# Should show 6 services, all healthy
make test
# All tests should pass
```
---
## Integration Validation
### Cross-Phase Validation
**Architecture Consistency:**
- [ ] 6 containers total (no more, no less)
- [ ] 3 networks configured
- [ ] mvp-* naming consistent everywhere
- [ ] No tenant code remaining
- [ ] No MinIO references
- [ ] No old platform services
**Functional Validation:**
- [ ] Authentication works (Auth0)
- [ ] Vehicle operations work
- [ ] Fuel logs CRUD works
- [ ] Maintenance logs work
- [ ] Stations work
- [ ] Document upload/download works
**Performance Validation:**
- [ ] Application starts in reasonable time
- [ ] API response times acceptable
- [ ] No memory leaks
- [ ] No excessive logging
---
## Final Acceptance Criteria
### Must-Pass Criteria
**Infrastructure:**
```bash
# 1. All containers healthy
docker compose ps
# Expected: 6 services, all "running (healthy)"
# 2. Networks correct
docker network ls | grep motovaultpro | wc -l
# Expected: 3
# 3. Volumes correct
docker volume ls | grep motovaultpro | wc -l
# Expected: 2 (postgres_data, redis_data)
```
**Build and Tests:**
```bash
# 4. Clean rebuild succeeds
make clean && make setup
# Expected: All services start successfully
# 5. All tests pass
make test
# Expected: 0 failures
# 6. Linting passes
cd backend && npm run lint
cd frontend && npm run lint
# Expected: No errors
```
**Code Quality:**
```bash
# 7. No tenant references in application
grep -r "tenant_id" backend/src/features/ | wc -l
# Expected: 0
# 8. No old container names
grep -r "admin-backend" backend/ frontend/ docs/ | wc -l
# Expected: 0
# 9. No MinIO references
grep -r "minio" backend/src/ | wc -l
# Expected: 0
```
**Functionality:**
- [ ] 10. Can log in via Auth0
- [ ] 11. Can create vehicle
- [ ] 12. Can upload document
- [ ] 13. Can create fuel log
- [ ] 14. Can create maintenance log
- [ ] 15. Can search stations
**Mobile Compatibility:**
- [ ] 16. Frontend responsive on mobile
- [ ] 17. All features work on mobile
- [ ] 18. No mobile-specific errors
### Nice-to-Have Criteria
- [ ] Documentation comprehensive
- [ ] Code comments updated
- [ ] Performance improved vs. before
- [ ] Memory usage reduced
- [ ] Startup time faster
---
## Validation Responsibility Matrix
| Validation | Agent | Phase | Critical |
|------------|-------|-------|----------|
| Container rename | infra-agent | 1 | Yes |
| Service removal | infra-agent | 1 | Yes |
| Tenant code deleted | backend-agent | 2 | Yes |
| Filesystem storage | storage-agent | 3 | Yes |
| Config cleanup | config-agent | 4 | Yes |
| Network simplification | infra-agent | 5 | Yes |
| Service references | backend-agent | 6 | Yes |
| Database updates | infra-agent | 7 | Yes |
| Platform simplification | platform-agent | 8 | Yes |
| Documentation | docs-agent | 9 | No |
| Frontend updates | frontend-agent | 10 | Yes |
| Full integration | test-agent | 11 | Yes |
---
## Rollback Triggers
Rollback if:
- [ ] Any critical validation fails
- [ ] Tests have >10% failure rate
- [ ] Containers fail to start
- [ ] Data loss detected
- [ ] Security issues introduced
- [ ] Production blockers identified
See ROLLBACK-STRATEGY.md for procedures.
---
## Sign-Off Checklist
**Project Lead:**
- [ ] All critical validations passed
- [ ] Architecture simplified as intended
- [ ] No functionality regressions
- [ ] Documentation complete
- [ ] Team trained on new architecture
**Technical Lead:**
- [ ] Code quality maintained
- [ ] Tests comprehensive
- [ ] Performance acceptable
- [ ] Security not compromised
**DevOps Lead:**
- [ ] Containers deploy successfully
- [ ] Networks configured correctly
- [ ] Volumes persistent
- [ ] Monitoring operational
**Final Approval:**
- [ ] Ready for production deployment
- [ ] Rollback plan documented
- [ ] Team informed of changes

View File

@@ -1,188 +0,0 @@
# MotoVaultPro Simplification - Validation Report
Date: 2025-11-01
Duration: ~6 hours
## Executive Summary
**STATUS: SUCCESS** - Architecture successfully simplified from 14 containers to 6 containers
## Container Status
All 6 containers are running and healthy:
| Container | Status | Health |
|-----------|--------|--------|
| mvp-traefik | Running | Healthy |
| mvp-frontend | Running | Healthy |
| mvp-backend | Running | Healthy |
| mvp-postgres | Running | Healthy |
| mvp-redis | Running | Healthy |
| mvp-platform | Running | Healthy |
## Architecture Metrics
| Metric | Before | After | Reduction |
|--------|--------|-------|-----------|
| Containers | 14 | 6 | 57% |
| PostgreSQL instances | 3 | 1 | 67% |
| Redis instances | 3 | 1 | 67% |
| Networks (defined) | 5 | 3 | 40% |
| Volumes | 5+ | 2 | 60% |
## Phase Completion
All 11 phases completed successfully:
1. ✅ Docker Compose Simplification (5 min)
2. ✅ Remove Multi-Tenant Architecture (20 min)
3. ✅ Filesystem Storage Migration (10 min)
4. ✅ Configuration Cleanup (5 min)
5. ✅ Network Simplification (1 min)
6. ✅ Backend Service Updates (1 min)
7. ✅ Database Updates (1 min)
8. ✅ Platform Service Simplification (2 min)
9. ✅ Documentation Updates (15 min)
10. ✅ Frontend Updates (1 min)
11. ✅ Testing and Validation (1 min)
## Code Quality Validations
-**No tenant_id references** - 0 occurrences in backend features
-**No old container names** - 0 occurrences (admin-backend, admin-frontend, admin-postgres, admin-redis)
-**No MinIO references** - 0 occurrences in backend source code
-**docker-compose.yml valid** - Successfully parses and validates
-**Service count** - Exactly 6 services defined
-**Network count** - Exactly 3 networks defined (frontend, backend, database)
## Build Validations
-**Backend builds** - TypeScript compilation successful
-**Frontend builds** - Vite build successful
-**Platform builds** - Python/FastAPI build successful
-**All containers start** - No startup errors
-**Health checks pass** - All services report healthy
## Issues Resolved
### Issue 1: TypeScript Build Errors
**Problem:** Unused parameters in FilesystemAdapter caused build failures
**Solution:** Prefixed unused parameters with underscore (_bucket, _options)
**Status:** RESOLVED
### Issue 2: Config Schema Validation
**Problem:** Config schema required removed fields (platform.services.tenants, frontend.tenant_id)
**Solution:** Updated schema to remove tenant-related required fields
**Status:** RESOLVED
### Issue 3: Platform Database Authentication
**Problem:** Platform service using wrong password file (non-existent secrets/platform/vehicles-db-password.txt)
**Solution:** Updated to use shared secrets/app/postgres-password.txt
**Status:** RESOLVED
### Issue 4: Frontend Nginx Permissions
**Problem:** Non-root nginx user couldn't read /etc/nginx/nginx.conf
**Solution:** Added chown for nginx.conf in Dockerfile
**Status:** RESOLVED
## Services Architecture
### Before (14 containers)
- traefik
- admin-frontend, admin-backend, admin-postgres, admin-redis, admin-minio
- mvp-platform-landing, mvp-platform-tenants
- mvp-platform-vehicles-api, mvp-platform-vehicles-db, mvp-platform-vehicles-redis, mvp-platform-vehicles-etl
- platform-postgres, platform-redis
### After (6 containers)
- **mvp-traefik** - Reverse proxy and SSL termination
- **mvp-frontend** - React SPA (nginx)
- **mvp-backend** - Node.js/Fastify API
- **mvp-postgres** - Shared PostgreSQL database
- **mvp-redis** - Shared Redis cache
- **mvp-platform** - Simplified vehicles service (FastAPI)
## Network Architecture
### Before (5 networks)
- frontend, backend, database, platform, egress
### After (3 networks)
- **frontend** - Traefik public access
- **backend** - API services communication
- **database** - Data layer isolation
## Storage Architecture
### Before
- MinIO object storage (separate container)
- 3 separate PostgreSQL databases
- 3 separate Redis caches
### After
- Filesystem storage at `/app/data/documents`
- 1 shared PostgreSQL database (mvp-postgres)
- 1 shared Redis cache (mvp-redis)
## Configuration Changes
- Removed multi-tenant configuration
- Removed MinIO configuration
- Consolidated database connection strings
- Simplified service authentication (no API keys between internal services)
- Updated all service references to mvp-* naming
## Runtime Validation Status
**Container Runtime:** ✅ PASSED - All 6 containers healthy
**Build Tests:** ✅ PASSED - All services build successfully
**Code Tests:** Deferred - Run `make test` for full test suite
**Feature Tests:** Deferred - Manual testing required
## Next Steps
To complete validation:
1. Run full test suite:
```bash
make test
```
2. Test core features:
- Auth0 login
- Vehicle CRUD operations
- Document upload/download
- Fuel logs
- Maintenance logs
- Stations
3. Performance testing:
- Monitor memory usage
- Check startup times
- Test API response times
## Conclusion
**Simplification: SUCCESS**
The MotoVaultPro architecture has been successfully simplified from 14 containers to 6 containers, achieving a 57% reduction in container count. All code-level validations pass, all containers are healthy, and the application is ready for feature testing.
### Benefits Achieved
1. **Reduced Complexity** - 57% fewer containers to manage
2. **Lower Resource Usage** - Shared databases and caches
3. **Simplified Deployment** - Fewer services to coordinate
4. **Easier Maintenance** - Consolidated configuration
5. **Faster Startup** - Fewer container dependencies
6. **Cost Reduction** - Lower infrastructure requirements
### Technical Achievements
- Removed multi-tenant architecture (single-tenant user_id isolation)
- Replaced MinIO with filesystem storage
- Consolidated 3 PostgreSQL → 1
- Consolidated 3 Redis → 1
- Simplified network topology
- Unified mvp-* naming convention
- Removed ETL pipeline complexity
**Ready for Production:** After full test suite passes

View File

@@ -1,36 +0,0 @@
FROM node:18-alpine as builder
WORKDIR /app
# Copy package files and install dependencies
COPY package.json ./
RUN npm install
# Copy source code
COPY . .
# Build arguments for environment variables
ARG VITE_AUTH0_DOMAIN
ARG VITE_AUTH0_CLIENT_ID
ARG VITE_TENANTS_API_URL
# Set environment variables for build
ENV VITE_AUTH0_DOMAIN=${VITE_AUTH0_DOMAIN}
ENV VITE_AUTH0_CLIENT_ID=${VITE_AUTH0_CLIENT_ID}
ENV VITE_TENANTS_API_URL=${VITE_TENANTS_API_URL}
# Build the application
RUN npm run build
# Production stage
FROM nginx:alpine
# Copy built app to nginx
COPY --from=builder /app/dist /usr/share/nginx/html
# Copy nginx configuration
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 3000
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -1,13 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MotoVaultPro - Vehicle Management Platform</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View File

@@ -1,27 +0,0 @@
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Single HTTP server for internal proxying (edge TLS handled by nginx-proxy)
server {
listen 3000;
server_name localhost motovaultpro.com;
root /usr/share/nginx/html;
index index.html;
# Handle React Router (SPA)
location / {
try_files $uri $uri/ /index.html;
}
# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
}
}

View File

@@ -1,26 +0,0 @@
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 3000;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Handle React Router (SPA)
location / {
try_files $uri $uri/ /index.html;
}
# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
}
}

View File

@@ -1,24 +0,0 @@
{
"name": "mvp-platform-landing",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.8.0",
"@auth0/auth0-react": "^2.2.3",
"axios": "^1.6.2"
},
"devDependencies": {
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@vitejs/plugin-react": "^4.2.0",
"typescript": "^5.6.3",
"vite": "^5.0.6"
}
}

View File

@@ -1,19 +0,0 @@
import { Routes, Route } from 'react-router-dom'
import HomePage from './components/HomePage'
import TenantSignup from './components/TenantSignup'
import CallbackHandler from './components/CallbackHandler'
function App() {
return (
<div className="App">
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/signup/:tenantId" element={<TenantSignup />} />
<Route path="/callback" element={<CallbackHandler />} />
</Routes>
</div>
)
}
export default App

View File

@@ -1,22 +0,0 @@
import React, { useEffect } from 'react'
const CallbackHandler: React.FC = () => {
useEffect(() => {
// This component is no longer needed since we removed Auth0 from landing page
// Redirect to main app
window.location.href = 'https://admin.motovaultpro.com'
}, [])
return (
<div style={{
padding: '2rem',
textAlign: 'center',
fontFamily: 'Arial, sans-serif'
}}>
<h2>Redirecting...</h2>
<p>Please wait while we redirect you to MotoVaultPro.</p>
</div>
)
}
export default CallbackHandler

View File

@@ -1,55 +0,0 @@
import React from 'react'
const HomePage: React.FC = () => {
const handleLogin = () => {
// Redirect directly to admin tenant for login
window.location.href = 'https://admin.motovaultpro.com'
}
return (
<div style={{ padding: '2rem', fontFamily: 'Arial, sans-serif' }}>
<header style={{ textAlign: 'center', marginBottom: '3rem' }}>
<h1>MotoVaultPro</h1>
<p>The complete vehicle management platform for automotive professionals</p>
</header>
<main style={{ maxWidth: '800px', margin: '0 auto' }}>
<section style={{ marginBottom: '3rem' }}>
<h2>Features</h2>
<ul>
<li>Vehicle inventory management</li>
<li>Maintenance tracking and scheduling</li>
<li>Fuel log analytics</li>
<li>Service station locator</li>
<li>Multi-tenant architecture for teams</li>
</ul>
</section>
<section style={{ textAlign: 'center' }}>
<h2>Get Started</h2>
<p>Already have an account?</p>
<button
onClick={handleLogin}
style={{
padding: '1rem 2rem',
fontSize: '1.1rem',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Access Your Dashboard
</button>
<p style={{ marginTop: '2rem' }}>
Need to join a team? Contact your tenant administrator for an invitation.
</p>
</section>
</main>
</div>
)
}
export default HomePage

View File

@@ -1,109 +0,0 @@
import React, { useEffect, useState } from 'react'
import { useParams } from 'react-router-dom'
import { useAuth0 } from '@auth0/auth0-react'
import axios from 'axios'
interface TenantInfo {
id: string
name: string
status: string
}
const TenantSignup: React.FC = () => {
const { tenantId } = useParams<{ tenantId: string }>()
const { loginWithRedirect } = useAuth0()
const [tenant, setTenant] = useState<TenantInfo | null>(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
const fetchTenant = async () => {
try {
const response = await axios.get(
`${import.meta.env.VITE_TENANTS_API_URL}/api/v1/tenants/${tenantId}`
)
setTenant(response.data)
} catch (err) {
setError('Tenant not found or not accepting signups')
} finally {
setLoading(false)
}
}
if (tenantId) {
fetchTenant()
}
}, [tenantId])
const handleSignup = async () => {
await loginWithRedirect({
authorizationParams: {
screen_hint: 'signup',
redirect_uri: `${window.location.origin}/callback`
}
})
}
if (loading) {
return <div style={{ padding: '2rem' }}>Loading...</div>
}
if (error || !tenant) {
return (
<div style={{ padding: '2rem', textAlign: 'center' }}>
<h2>Tenant Not Found</h2>
<p>{error}</p>
<a href="/">Return to Homepage</a>
</div>
)
}
return (
<div style={{ padding: '2rem', maxWidth: '600px', margin: '0 auto', fontFamily: 'Arial, sans-serif' }}>
<header style={{ textAlign: 'center', marginBottom: '2rem' }}>
<h1>Join {tenant.name}</h1>
<p>Create your account to get started</p>
</header>
<main>
<div style={{
border: '1px solid #ddd',
borderRadius: '8px',
padding: '2rem',
backgroundColor: '#f9f9f9'
}}>
<h3>What happens next?</h3>
<ol>
<li>Create your account with Auth0</li>
<li>Your signup request will be sent to the tenant administrator</li>
<li>Once approved, you'll receive access to {tenant.name}</li>
<li>Login at <code>{tenant.id}.motovaultpro.com</code></li>
</ol>
<div style={{ textAlign: 'center', marginTop: '2rem' }}>
<button
onClick={handleSignup}
style={{
padding: '1rem 2rem',
fontSize: '1.1rem',
backgroundColor: '#28a745',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Create Account for {tenant.name}
</button>
</div>
</div>
<div style={{ textAlign: 'center', marginTop: '2rem' }}>
<a href="/"> Back to Homepage</a>
</div>
</main>
</div>
)
}
export default TenantSignup

View File

@@ -1,12 +0,0 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
)

View File

@@ -1,11 +0,0 @@
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_AUTH0_DOMAIN: string
readonly VITE_AUTH0_CLIENT_ID: string
readonly VITE_TENANTS_API_URL: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}

View File

@@ -1,21 +0,0 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@@ -1,9 +0,0 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler"
},
"include": ["vite.config.ts"]
}

View File

@@ -1,14 +0,0 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
host: true,
port: 3000
},
build: {
outDir: 'dist',
sourcemap: true
}
})

View File

@@ -1,333 +0,0 @@
# Auth0 Multi-Tenant Configuration Guide
This document provides step-by-step instructions for configuring Auth0 for the multi-tenant MotoVaultPro platform.
## Overview
The multi-tenant architecture requires:
- **Landing Page**: `motovaultpro.com` - Entry point with tenant selection
- **Admin Tenant**: `admin.motovaultpro.com` - Admin access to all tenants
- **Regular Tenants**: `{tenant-id}.motovaultpro.com` - Isolated tenant access
- **Signup Workflow**: Tenant-specific signup with admin approval
## Auth0 Application Configuration
### 1. Application Settings
**Application Type**: Single Page Application (SPA)
**Allowed Callback URLs**:
```
# Development URLs
http://localhost:3002/callback
http://admin.motovaultpro.local/callback
http://demo-tenant.motovaultpro.local/callback
# Production URLs
https://motovaultpro.com/callback
https://admin.motovaultpro.com/callback
https://demo-tenant.motovaultpro.com/callback
# Add additional tenant subdomains as needed:
https://{tenant-id}.motovaultpro.com/callback
```
**Allowed Logout URLs**:
```
# Development
http://localhost:3002
http://admin.motovaultpro.local
http://demo-tenant.motovaultpro.local
# Production
https://motovaultpro.com
https://admin.motovaultpro.com
https://demo-tenant.motovaultpro.com
https://{tenant-id}.motovaultpro.com
```
**Allowed Web Origins**:
```
# Development
http://localhost:3002
http://admin.motovaultpro.local:3000
http://demo-tenant.motovaultpro.local:3000
# Production
https://motovaultpro.com
https://admin.motovaultpro.com
https://demo-tenant.motovaultpro.com
https://{tenant-id}.motovaultpro.com
```
### 2. JWT Configuration
**JWT Signature Algorithm**: RS256
**OIDC Conformant**: Enabled
### 3. Advanced Settings
**Grant Types**:
- Authorization Code
- Refresh Token
- Implicit (for development only)
## Auth0 Rules Configuration
### Rule 1: Add Tenant Context to JWT
Create a new Rule in Auth0 Dashboard > Auth Pipeline > Rules:
```javascript
function addTenantContext(user, context, callback) {
const namespace = 'https://motovaultpro.com/';
// Extract tenant_id from user metadata (set during signup)
let tenantId = user.user_metadata && user.user_metadata.tenant_id;
// For existing users without tenant metadata, default to admin
if (!tenantId) {
tenantId = 'admin';
// Optionally update user metadata
user.user_metadata = user.user_metadata || {};
user.user_metadata.tenant_id = tenantId;
}
// Check signup status for non-admin tenants
const signupStatus = user.user_metadata && user.user_metadata.signup_status;
if (tenantId !== 'admin' && signupStatus !== 'approved') {
// Block login for unapproved users
return callback(new UnauthorizedError('Account pending approval'));
}
// Add tenant context to tokens
context.idToken[namespace + 'tenant_id'] = tenantId;
context.accessToken[namespace + 'tenant_id'] = tenantId;
context.idToken[namespace + 'signup_status'] = signupStatus || 'approved';
callback(null, user, context);
}
```
### Rule 2: Tenant-Specific User Metadata
```javascript
function setTenantMetadata(user, context, callback) {
const namespace = 'https://motovaultpro.com/';
// If this is a signup and connection is Username-Password-Authentication
if (context.stats.loginsCount === 1 && context.connection === 'Username-Password-Authentication') {
// Extract tenant from redirect_uri or state parameter
const redirectUri = context.request.query.redirect_uri || '';
const tenantMatch = redirectUri.match(/([a-z0-9-]+)\.motovaultpro\.(com|local)/);
if (tenantMatch) {
const tenantId = tenantMatch[1];
// Set initial user metadata
user.user_metadata = user.user_metadata || {};
user.user_metadata.tenant_id = tenantId;
// Set signup status (pending for regular tenants, approved for admin)
user.user_metadata.signup_status = tenantId === 'admin' ? 'approved' : 'pending';
// Update user metadata in Auth0
auth0.users.updateUserMetadata(user.user_id, user.user_metadata);
}
}
callback(null, user, context);
}
```
## Tenant Signup Flow Configuration
### 1. Signup URLs
**Tenant-Specific Signup**:
```
https://motovaultpro.com/signup/{tenant-id}
```
**Process**:
1. User visits tenant-specific signup URL
2. Landing page validates tenant exists
3. Redirects to Auth0 with tenant context
4. Auth0 Rule sets tenant_id in user metadata
5. User account created with status="pending"
6. Tenant admin receives notification
7. Admin approves/rejects via tenant management API
### 2. Auth0 Hosted Login Customization
Add custom CSS and JavaScript to Auth0 Universal Login to support tenant context:
**Custom CSS** (Dashboard > Universal Login > Advanced Options):
```css
.tenant-signup-info {
background: #f8f9fa;
padding: 15px;
border-radius: 5px;
margin-bottom: 20px;
border-left: 4px solid #007bff;
}
```
**Custom JavaScript**:
```javascript
// Extract tenant from URL parameters
const urlParams = new URLSearchParams(window.location.search);
const redirectUri = urlParams.get('redirect_uri') || '';
const tenantMatch = redirectUri.match(/([a-z0-9-]+)\.motovaultpro\.(com|local)/);
if (tenantMatch && tenantMatch[1] !== 'admin') {
const tenantName = tenantMatch[1].replace('-', ' ').toUpperCase();
// Add tenant information to signup form
const container = document.querySelector('.auth0-lock-header');
if (container) {
const info = document.createElement('div');
info.className = 'tenant-signup-info';
info.innerHTML = `
<strong>Signing up for: ${tenantName}</strong><br>
<small>Your account will require admin approval before you can access the system.</small>
`;
container.appendChild(info);
}
}
```
## JWT Token Format
After successful authentication, JWT tokens will include:
**ID Token Claims**:
```json
{
"sub": "auth0|user-123",
"email": "user@example.com",
"https://motovaultpro.com/tenant_id": "demo-tenant",
"https://motovaultpro.com/signup_status": "approved",
"iat": 1699123456,
"exp": 1699127056
}
```
**Access Token Claims**:
```json
{
"sub": "auth0|user-123",
"https://motovaultpro.com/tenant_id": "demo-tenant",
"scope": "openid profile email",
"iat": 1699123456,
"exp": 1699127056
}
```
## Backend JWT Validation
Services should validate JWT tokens and extract tenant context:
```typescript
// Example JWT validation middleware
import jwt from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';
const client = jwksClient({
jwksUri: `https://${AUTH0_DOMAIN}/.well-known/jwks.json`
});
function getKey(header: any, callback: any) {
client.getSigningKey(header.kid, (err, key) => {
if (err) return callback(err);
const signingKey = key.getPublicKey();
callback(null, signingKey);
});
}
export const validateJWT = (token: string): Promise<any> => {
return new Promise((resolve, reject) => {
jwt.verify(token, getKey, {
audience: process.env.AUTH0_AUDIENCE,
issuer: `https://${process.env.AUTH0_DOMAIN}/`,
algorithms: ['RS256']
}, (err, decoded) => {
if (err) return reject(err);
resolve(decoded);
});
});
};
// Extract tenant from validated JWT
export const getTenantFromToken = (decodedToken: any): string => {
return decodedToken['https://motovaultpro.com/tenant_id'] || 'admin';
};
```
## Environment Variables
Configure the following environment variables for each service:
**Platform Services**:
```env
AUTH0_DOMAIN=your-domain.auth0.com
AUTH0_AUDIENCE=https://api.motovaultpro.com
```
**Landing Page Service**:
```env
VITE_AUTH0_DOMAIN=your-domain.auth0.com
VITE_AUTH0_CLIENT_ID=your-client-id
VITE_TENANTS_API_URL=http://mvp-platform-tenants:8000
```
**Admin/Tenant Services**:
```env
REACT_APP_AUTH0_DOMAIN=your-domain.auth0.com
REACT_APP_AUTH0_CLIENT_ID=your-client-id
REACT_APP_AUTH0_AUDIENCE=https://api.motovaultpro.com
REACT_APP_TENANT_ID=admin # or specific tenant ID
```
## Testing the Configuration
### 1. Test Admin Login
```bash
# Visit admin tenant
open http://admin.motovaultpro.local
# Should redirect to Auth0, login, then return to admin app
```
### 2. Test Tenant Signup
```bash
# Visit tenant signup
open http://motovaultpro.local/signup/demo-tenant
# Complete signup, verify pending status
curl -H "Authorization: Bearer admin-token" \
http://localhost:8001/api/v1/signups
```
### 3. Test Approval Workflow
```bash
# Approve signup
curl -X PUT -H "Authorization: Bearer admin-token" \
http://localhost:8001/api/v1/signups/1/approve
# User should now be able to login to tenant
open http://demo-tenant.motovaultpro.local
```
## Production Deployment Notes
1. **SSL Certificates**: Ensure wildcard SSL certificate for `*.motovaultpro.com`
2. **DNS Configuration**: Set up wildcard DNS or individual A records per tenant
3. **Auth0 Environment**: Use production Auth0 tenant with proper security settings
4. **Rate Limiting**: Configure Auth0 rate limiting for signup endpoints
5. **Monitoring**: Set up Auth0 logs monitoring for failed login attempts
This configuration provides a secure, scalable multi-tenant authentication system with proper tenant isolation and admin approval workflows.

View File

@@ -1,525 +0,0 @@
"""
MVP Platform Tenants Service - FastAPI Application
Handles tenant management, signup approvals, and multi-tenant infrastructure.
"""
from fastapi import FastAPI, HTTPException, Depends, Header
from fastapi.middleware.cors import CORSMiddleware
import asyncpg
import os
import json
import httpx
from typing import Optional, List, Dict
from pydantic import BaseModel
from datetime import datetime
import logging
from jose import jwt, jwk
from jose.exceptions import JWTError, ExpiredSignatureError
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI(
title="MVP Platform Tenants Service",
description="Multi-tenant management and signup approval service",
version="1.0.0"
)
# CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Configure appropriately for production
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Auth0 configuration
AUTH0_DOMAIN = os.getenv("AUTH0_DOMAIN")
AUTH0_AUDIENCE = os.getenv("AUTH0_AUDIENCE", "https://api.motovaultpro.com")
# Cache for JWKS keys (in production, use Redis)
_jwks_cache = {}
_jwks_cache_expiry = 0
# Database connection
DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://platform_user:platform_pass@platform-postgres:5432/platform")
# Helper function to parse JSON settings
def parse_json_field(value):
if isinstance(value, str):
try:
return json.loads(value)
except json.JSONDecodeError:
return {}
return value or {}
# Models
class TenantCreate(BaseModel):
id: str
name: str
subdomain: str
admin_user_id: Optional[str] = None
settings: dict = {}
class TenantResponse(BaseModel):
id: str
name: str
subdomain: str
status: str
admin_user_id: Optional[str]
settings: dict
created_at: datetime
updated_at: datetime
@classmethod
def from_db_row(cls, row):
data = dict(row)
data['settings'] = parse_json_field(data.get('settings'))
return cls(**data)
class SignupRequest(BaseModel):
user_email: str
user_auth0_id: Optional[str] = None
class SignupResponse(BaseModel):
id: int
tenant_id: str
user_email: str
user_auth0_id: Optional[str]
status: str
requested_at: datetime
approved_by: Optional[str] = None
approved_at: Optional[datetime] = None
rejected_at: Optional[datetime] = None
rejection_reason: Optional[str] = None
class SignupApproval(BaseModel):
reason: Optional[str] = None
# JWT Authentication functions
async def get_jwks() -> Dict:
"""Fetch JWKS from Auth0 with caching"""
global _jwks_cache, _jwks_cache_expiry
import time
current_time = time.time()
# Return cached JWKS if not expired (cache for 1 hour)
if _jwks_cache and current_time < _jwks_cache_expiry:
return _jwks_cache
if not AUTH0_DOMAIN:
raise HTTPException(status_code=500, detail="Auth0 configuration missing")
try:
async with httpx.AsyncClient() as client:
response = await client.get(f"https://{AUTH0_DOMAIN}/.well-known/jwks.json")
response.raise_for_status()
jwks = response.json()
# Cache the JWKS for 1 hour
_jwks_cache = jwks
_jwks_cache_expiry = current_time + 3600
return jwks
except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to fetch JWKS: {str(e)}")
async def get_signing_key(kid: str) -> str:
"""Get signing key for the given kid"""
jwks = await get_jwks()
for key in jwks.get("keys", []):
if key.get("kid") == kid:
return jwk.construct(key).key
raise HTTPException(status_code=401, detail="Unable to find appropriate key")
async def verify_jwt(token: str) -> Dict:
"""Verify and decode JWT token"""
if not AUTH0_DOMAIN or not AUTH0_AUDIENCE:
raise HTTPException(status_code=500, detail="Auth0 configuration missing")
try:
# Get the kid from token header
unverified_header = jwt.get_unverified_header(token)
kid = unverified_header.get("kid")
if not kid:
raise HTTPException(status_code=401, detail="Token header missing kid")
# Get the signing key
signing_key = await get_signing_key(kid)
# Verify and decode the token
payload = jwt.decode(
token,
signing_key,
algorithms=["RS256"],
audience=AUTH0_AUDIENCE,
issuer=f"https://{AUTH0_DOMAIN}/"
)
return payload
except ExpiredSignatureError:
raise HTTPException(status_code=401, detail="Token has expired")
except JWTError as e:
raise HTTPException(status_code=401, detail=f"Invalid token: {str(e)}")
except Exception as e:
raise HTTPException(status_code=401, detail=f"Token validation failed: {str(e)}")
# Mock authentication for development/testing
async def mock_auth_user(authorization: str) -> Dict:
"""Mock authentication for testing purposes"""
if not authorization or not authorization.startswith("Bearer "):
raise HTTPException(status_code=401, detail="Authorization header required")
token = authorization.split(" ")[1]
if token == "admin-token":
return {
"sub": "admin-user",
"email": "admin@motovaultpro.com",
"https://motovaultpro.com/tenant_id": "admin",
"https://motovaultpro.com/signup_status": "approved"
}
elif token.startswith("tenant-"):
tenant_id = token.replace("tenant-", "", 1).replace("-token", "")
return {
"sub": f"{tenant_id}-admin",
"email": f"admin@{tenant_id}.com",
"https://motovaultpro.com/tenant_id": tenant_id,
"https://motovaultpro.com/signup_status": "approved"
}
raise HTTPException(status_code=401, detail="Invalid token")
async def get_current_user(authorization: str = Header(None)):
"""Extract and validate JWT from Authorization header"""
if not authorization:
raise HTTPException(status_code=401, detail="Authorization header required")
try:
scheme, token = authorization.split(" ", 1)
if scheme.lower() != "bearer":
raise HTTPException(status_code=401, detail="Invalid authentication scheme")
# Try real JWT validation first, fallback to mock for development
try:
if AUTH0_DOMAIN and AUTH0_AUDIENCE:
payload = await verify_jwt(token)
else:
payload = await mock_auth_user(authorization)
except HTTPException:
# Fallback to mock authentication for development
payload = await mock_auth_user(authorization)
# Extract tenant info from JWT claims
tenant_id = payload.get("https://motovaultpro.com/tenant_id", "admin")
user_id = payload.get("sub", "")
email = payload.get("email", "")
return {
"sub": user_id,
"tenant_id": tenant_id,
"email": email,
"payload": payload
}
except ValueError:
raise HTTPException(status_code=401, detail="Invalid authorization header format")
async def get_admin_user(current_user: dict = Depends(get_current_user)):
if current_user.get("tenant_id") != "admin":
raise HTTPException(status_code=403, detail="Admin access required")
return current_user
async def get_tenant_admin(current_user: dict = Depends(get_current_user)):
if not current_user.get("tenant_id"):
raise HTTPException(status_code=401, detail="Tenant authentication required")
return current_user
# Health check
@app.get("/health")
async def health_check():
try:
conn = await asyncpg.connect(DATABASE_URL)
await conn.execute("SELECT 1")
await conn.close()
return {
"status": "healthy",
"database": "connected",
"service": "mvp-platform-tenants",
"version": "1.0.0"
}
except Exception as e:
logger.error(f"Health check failed: {e}")
raise HTTPException(status_code=503, detail="Service unavailable")
# Tenant management endpoints
@app.post("/api/v1/tenants", response_model=TenantResponse)
async def create_tenant(
tenant_data: TenantCreate,
current_user: dict = Depends(get_admin_user)
):
"""Create new tenant (admin only)"""
conn = await asyncpg.connect(DATABASE_URL)
try:
# Check if tenant already exists
existing = await conn.fetchrow(
"SELECT id FROM tenants WHERE id = $1 OR subdomain = $2",
tenant_data.id, tenant_data.subdomain
)
if existing:
raise HTTPException(status_code=409, detail="Tenant ID or subdomain already exists")
# Insert new tenant
result = await conn.fetchrow(
"""
INSERT INTO tenants (id, name, subdomain, admin_user_id, settings)
VALUES ($1, $2, $3, $4, $5)
RETURNING *
""",
tenant_data.id,
tenant_data.name,
tenant_data.subdomain,
tenant_data.admin_user_id,
json.dumps(tenant_data.settings)
)
return TenantResponse.from_db_row(result)
finally:
await conn.close()
@app.get("/api/v1/tenants", response_model=List[TenantResponse])
async def list_tenants(current_user: dict = Depends(get_admin_user)):
"""List all tenants (admin only)"""
conn = await asyncpg.connect(DATABASE_URL)
try:
results = await conn.fetch("SELECT * FROM tenants ORDER BY created_at DESC")
return [TenantResponse.from_db_row(row) for row in results]
finally:
await conn.close()
@app.get("/api/v1/tenants/{tenant_id}", response_model=TenantResponse)
async def get_tenant(tenant_id: str):
"""Get tenant details (public endpoint for validation)"""
conn = await asyncpg.connect(DATABASE_URL)
try:
result = await conn.fetchrow("SELECT * FROM tenants WHERE id = $1", tenant_id)
if not result:
raise HTTPException(status_code=404, detail="Tenant not found")
return TenantResponse.from_db_row(result)
finally:
await conn.close()
@app.put("/api/v1/tenants/{tenant_id}", response_model=TenantResponse)
async def update_tenant(
tenant_id: str,
tenant_data: TenantCreate,
current_user: dict = Depends(get_admin_user)
):
"""Update tenant settings (admin only)"""
conn = await asyncpg.connect(DATABASE_URL)
try:
result = await conn.fetchrow(
"""
UPDATE tenants
SET name = $2, admin_user_id = $3, settings = $4, updated_at = CURRENT_TIMESTAMP
WHERE id = $1
RETURNING *
""",
tenant_id,
tenant_data.name,
tenant_data.admin_user_id,
json.dumps(tenant_data.settings)
)
if not result:
raise HTTPException(status_code=404, detail="Tenant not found")
return TenantResponse.from_db_row(result)
finally:
await conn.close()
# Signup management endpoints
@app.post("/api/v1/tenants/{tenant_id}/signups", response_model=SignupResponse)
async def request_signup(tenant_id: str, signup_data: SignupRequest):
"""Request signup approval for a tenant (public endpoint)"""
conn = await asyncpg.connect(DATABASE_URL)
try:
# Verify tenant exists and accepts signups
tenant = await conn.fetchrow(
"SELECT id, status FROM tenants WHERE id = $1", tenant_id
)
if not tenant:
raise HTTPException(status_code=404, detail="Tenant not found")
if tenant['status'] != 'active':
raise HTTPException(status_code=400, detail="Tenant not accepting signups")
# Check for existing signup
existing = await conn.fetchrow(
"SELECT id FROM tenant_signups WHERE tenant_id = $1 AND user_email = $2",
tenant_id, signup_data.user_email
)
if existing:
raise HTTPException(status_code=409, detail="Signup request already exists")
# Create signup request
result = await conn.fetchrow(
"""
INSERT INTO tenant_signups (tenant_id, user_email, user_auth0_id)
VALUES ($1, $2, $3)
RETURNING *
""",
tenant_id,
signup_data.user_email,
signup_data.user_auth0_id
)
logger.info(f"New signup request: {signup_data.user_email} for tenant {tenant_id}")
return SignupResponse(**dict(result))
finally:
await conn.close()
@app.get("/api/v1/tenants/{tenant_id}/signups", response_model=List[SignupResponse])
async def get_tenant_signups(
tenant_id: str,
status: Optional[str] = "pending",
current_user: dict = Depends(get_tenant_admin)
):
"""List signups for a tenant (tenant admin only)"""
# Verify user has access to this tenant
if current_user.get("tenant_id") != tenant_id and current_user.get("tenant_id") != "admin":
raise HTTPException(status_code=403, detail="Access denied to this tenant")
conn = await asyncpg.connect(DATABASE_URL)
try:
query = "SELECT * FROM tenant_signups WHERE tenant_id = $1"
params = [tenant_id]
if status:
query += " AND status = $2"
params.append(status)
query += " ORDER BY requested_at DESC"
results = await conn.fetch(query, *params)
return [SignupResponse(**dict(row)) for row in results]
finally:
await conn.close()
@app.get("/api/v1/signups", response_model=List[SignupResponse])
async def get_all_signups(
status: Optional[str] = "pending",
current_user: dict = Depends(get_admin_user)
):
"""List all signups across all tenants (admin only)"""
conn = await asyncpg.connect(DATABASE_URL)
try:
query = "SELECT * FROM tenant_signups"
params = []
if status:
query += " WHERE status = $1"
params.append(status)
query += " ORDER BY requested_at DESC"
results = await conn.fetch(query, *params)
return [SignupResponse(**dict(row)) for row in results]
finally:
await conn.close()
@app.put("/api/v1/signups/{signup_id}/approve")
async def approve_signup(
signup_id: int,
current_user: dict = Depends(get_tenant_admin)
):
"""Approve a signup request (tenant admin only)"""
conn = await asyncpg.connect(DATABASE_URL)
try:
# Get signup details to verify tenant access
signup = await conn.fetchrow(
"SELECT * FROM tenant_signups WHERE id = $1", signup_id
)
if not signup:
raise HTTPException(status_code=404, detail="Signup not found")
# Verify user has access to approve this signup
if (current_user.get("tenant_id") != signup['tenant_id'] and
current_user.get("tenant_id") != "admin"):
raise HTTPException(status_code=403, detail="Access denied to this tenant")
result = await conn.fetchrow(
"""
UPDATE tenant_signups
SET status = 'approved', approved_by = $2, approved_at = CURRENT_TIMESTAMP
WHERE id = $1 AND status = 'pending'
RETURNING *
""",
signup_id,
current_user['sub']
)
if not result:
raise HTTPException(status_code=404, detail="Signup not found or already processed")
# TODO: Update Auth0 user metadata to set signup_status = 'approved'
logger.info(f"Approved signup {signup_id} for user {result['user_email']} by {current_user['sub']}")
return {"status": "approved", "signup_id": signup_id}
finally:
await conn.close()
@app.put("/api/v1/signups/{signup_id}/reject")
async def reject_signup(
signup_id: int,
approval_data: SignupApproval,
current_user: dict = Depends(get_tenant_admin)
):
"""Reject a signup request (tenant admin only)"""
conn = await asyncpg.connect(DATABASE_URL)
try:
# Get signup details to verify tenant access
signup = await conn.fetchrow(
"SELECT * FROM tenant_signups WHERE id = $1", signup_id
)
if not signup:
raise HTTPException(status_code=404, detail="Signup not found")
# Verify user has access to reject this signup
if (current_user.get("tenant_id") != signup['tenant_id'] and
current_user.get("tenant_id") != "admin"):
raise HTTPException(status_code=403, detail="Access denied to this tenant")
reason = approval_data.reason or "No reason provided"
result = await conn.fetchrow(
"""
UPDATE tenant_signups
SET status = 'rejected', approved_by = $2, rejected_at = CURRENT_TIMESTAMP, rejection_reason = $3
WHERE id = $1 AND status = 'pending'
RETURNING *
""",
signup_id,
current_user['sub'],
reason
)
if not result:
raise HTTPException(status_code=404, detail="Signup not found or already processed")
logger.info(f"Rejected signup {signup_id} for user {result['user_email']}: {reason}")
return {"status": "rejected", "signup_id": signup_id, "reason": reason}
finally:
await conn.close()
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)

View File

@@ -1,21 +0,0 @@
FROM python:3.11-slim
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y \
gcc \
&& rm -rf /var/lib/apt/lists/*
# Copy requirements and install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY api/ .
# Expose port
EXPOSE 8000
# Run the application
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]

View File

@@ -1,7 +0,0 @@
fastapi==0.104.1
uvicorn[standard]==0.24.0
asyncpg==0.29.0
pydantic==2.5.0
python-jose[cryptography]==3.3.0
python-multipart==0.0.6
httpx==0.25.2

View File

@@ -1,41 +0,0 @@
-- Tenant registry schema for MVP Platform Tenants Service
-- Creates core tenant management tables
-- Tenant registry
CREATE TABLE IF NOT EXISTS tenants (
id VARCHAR(100) PRIMARY KEY, -- 'admin', 'acme-corp', etc.
name VARCHAR(255) NOT NULL, -- Display name
subdomain VARCHAR(100) UNIQUE NOT NULL, -- Same as id for simplicity
status VARCHAR(50) DEFAULT 'active', -- active, pending, suspended
admin_user_id VARCHAR(255), -- Auth0 user ID of tenant admin
settings JSONB DEFAULT '{}', -- Tenant-specific configuration
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Create indexes for performance
CREATE INDEX IF NOT EXISTS idx_tenants_status ON tenants(status);
CREATE INDEX IF NOT EXISTS idx_tenants_admin_user ON tenants(admin_user_id);
-- Tenant signup approval workflow
CREATE TABLE IF NOT EXISTS tenant_signups (
id SERIAL PRIMARY KEY,
tenant_id VARCHAR(100) REFERENCES tenants(id),
user_email VARCHAR(255) NOT NULL,
user_auth0_id VARCHAR(255), -- Auth0 user ID after signup
status VARCHAR(50) DEFAULT 'pending', -- pending, approved, rejected
requested_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
approved_by VARCHAR(255), -- Auth0 ID of approving admin
approved_at TIMESTAMP,
rejected_at TIMESTAMP,
rejection_reason TEXT
);
-- Create indexes for signup queries
CREATE INDEX IF NOT EXISTS idx_tenant_signups_tenant_status ON tenant_signups(tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_tenant_signups_user_email ON tenant_signups(user_email);
-- Initial admin tenant data
INSERT INTO tenants (id, name, subdomain, status, admin_user_id)
VALUES ('admin', 'Admin Tenant', 'admin', 'active', NULL)
ON CONFLICT (id) DO NOTHING;

View File

@@ -1,75 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
TENANT_ID=${1:-}
if [[ -z "$TENANT_ID" ]]; then
echo "Usage: $0 <tenant-id>" >&2
exit 1
fi
if ! [[ "$TENANT_ID" =~ ^[a-z0-9-]+$ ]]; then
echo "Error: tenant-id must be lowercase alphanumeric and dashes (e.g., acme-corp)" >&2
exit 1
fi
COMPOSE_FILE="docker-compose.yml"
echo "Appending services for tenant '$TENANT_ID' to $COMPOSE_FILE..."
cat >> "$COMPOSE_FILE" <<YAML
${TENANT_ID}-backend:
build: ./backend
environment:
- TENANT_ID=${TENANT_ID}
- DATABASE_URL=postgresql://motovault_user:\${DB_PASSWORD}@${TENANT_ID}-postgres:5432/motovault
- REDIS_URL=redis://${TENANT_ID}-redis:6379
- PLATFORM_TENANTS_API_URL=http://mvp-platform-tenants:8000
- PLATFORM_VEHICLES_API_URL=http://mvp-platform-vehicles-api:8000
- PLATFORM_VEHICLES_API_KEY=\${PLATFORM_VEHICLES_API_KEY:-mvp-platform-vehicles-secret-key}
depends_on:
- ${TENANT_ID}-postgres
- ${TENANT_ID}-redis
${TENANT_ID}-frontend:
build: ./frontend
environment:
- VITE_API_BASE_URL=http://${TENANT_ID}-backend:3001
- VITE_TENANT_ID=${TENANT_ID}
- VITE_AUTH0_DOMAIN=\${VITE_AUTH0_DOMAIN:-motovaultpro.us.auth0.com}
- VITE_AUTH0_CLIENT_ID=\${VITE_AUTH0_CLIENT_ID:-replace-me}
- VITE_AUTH0_AUDIENCE=\${VITE_AUTH0_AUDIENCE:-https://api.motovaultpro.com}
depends_on:
- ${TENANT_ID}-backend
${TENANT_ID}-postgres:
image: postgres:15-alpine
environment:
POSTGRES_DB: motovault
POSTGRES_USER: motovault_user
POSTGRES_PASSWORD: \${DB_PASSWORD:-localdev123}
POSTGRES_INITDB_ARGS: "--encoding=UTF8"
volumes:
- ./backend/src/_system/migrations:/docker-entrypoint-initdb.d
- ${TENANT_ID}_postgres_data:/var/lib/postgresql/data
${TENANT_ID}-redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- ${TENANT_ID}_redis_data:/data
YAML
echo "Adding volumes for tenant '$TENANT_ID'..."
cat >> "$COMPOSE_FILE" <<YAML
${TENANT_ID}_postgres_data:
${TENANT_ID}_redis_data:
YAML
echo "Tenant '${TENANT_ID}' provisioned. Run 'docker compose up -d' to start services."

View File

@@ -1,43 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd)"
cd "$ROOT_DIR"
SERVICE_MSSQL="mvp-platform-vehicles-mssql"
SERVICE_ETL="mvp-platform-vehicles-etl"
MSSQL_VOLUME="platform_vehicles_mssql_data"
echo "[monthly-etl] Starting MSSQL (profile: mssql-monthly)"
docker compose --profile mssql-monthly up -d "$SERVICE_MSSQL"
echo "[monthly-etl] Waiting for MSSQL to accept connections..."
ATTEMPTS=120 # up to ~10 minutes (120 * 5s)
SLEEP=5
for i in $(seq 1 $ATTEMPTS); do
if docker compose exec -T "$SERVICE_MSSQL" /opt/mssql-tools18/bin/sqlcmd -C -S localhost -U sa -P 'Platform123!' -Q "SELECT 1" >/dev/null 2>&1; then
echo "[monthly-etl] MSSQL is ready"
break
fi
echo "[monthly-etl] MSSQL not ready yet... ($i/$ATTEMPTS)"
sleep "$SLEEP"
done
if ! docker compose exec -T "$SERVICE_MSSQL" /opt/mssql-tools18/bin/sqlcmd -C -S localhost -U sa -P 'Platform123!' -Q "SELECT 1" >/dev/null 2>&1; then
echo "[monthly-etl] ERROR: MSSQL did not become ready in time" >&2
exit 1
fi
cleanup() {
echo "[monthly-etl] Stopping and removing MSSQL container..."
docker compose stop "$SERVICE_MSSQL" >/dev/null 2>&1 || true
docker compose rm -f "$SERVICE_MSSQL" >/dev/null 2>&1 || true
echo "[monthly-etl] Removing MSSQL data volume ($MSSQL_VOLUME)..."
docker volume rm "$MSSQL_VOLUME" >/dev/null 2>&1 || true
}
trap cleanup EXIT
echo "[monthly-etl] Running ETL pipeline (build-catalog)..."
docker compose run --rm "$SERVICE_ETL" python -m etl.main build-catalog
echo "[monthly-etl] Monthly ETL completed successfully."