Docs Cleanup
This commit is contained in:
@@ -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": []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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`
|
||||||
|
|
||||||
|
|||||||
@@ -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`
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Binary file not shown.
@@ -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;"
|
|
||||||
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
@@ -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}
|
||||||
|
|||||||
@@ -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
|
|
||||||
524
docs/ARCHITECTURE-OVERVIEW.md
Normal file
524
docs/ARCHITECTURE-OVERVIEW.md
Normal 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`
|
||||||
317
docs/PROMPTS.md
317
docs/PROMPTS.md
@@ -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)
|
||||||
@@ -268,313 +264,4 @@ mvp-platform-services/{service}/
|
|||||||
- Testing: `docs/TESTING.md`
|
- Testing: `docs/TESTING.md`
|
||||||
- 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.
|
|
||||||
|
|
||||||
---
|
|
||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
334
docs/TENANT-REMNANTS-ANALYSIS.md
Normal file
334
docs/TENANT-REMNANTS-ANALYSIS.md
Normal 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.
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
This document explains the end‑to‑end 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 production‑only development.
|
This document explains the end‑to‑end 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 production‑only 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, production‑only workflow, AI‑friendly code layout and docs.
|
- Goal: Predictable year→make→model→trim→engine cascades, production‑only workflow, AI‑friendly 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 (non‑destructive): apply `005_seed_specific_vehicles.sql` and flush Redis cache.
|
- Platform seed reapply (non‑destructive): 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 auto‑migrate is succeeding; check `docker compose logs backend`.
|
- Run `make migrate` or ensure backend container auto‑migrate 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.
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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.
|
|
||||||
@@ -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)"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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).
|
|
||||||
@@ -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}}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -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}}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -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"}}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -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}}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -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}}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -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}}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -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}}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -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"}}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -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}}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
```
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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;"]
|
|
||||||
@@ -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>
|
|
||||||
@@ -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";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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>
|
|
||||||
)
|
|
||||||
11
mvp-platform-services/landing/src/vite-env.d.ts
vendored
11
mvp-platform-services/landing/src/vite-env.d.ts
vendored
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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" }]
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"composite": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"module": "ESNext",
|
|
||||||
"moduleResolution": "bundler"
|
|
||||||
},
|
|
||||||
"include": ["vite.config.ts"]
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -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.
|
|
||||||
@@ -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)
|
|
||||||
@@ -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"]
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
@@ -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."
|
|
||||||
|
|
||||||
@@ -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."
|
|
||||||
Reference in New Issue
Block a user