diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 72954f7..47bcd86 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -60,7 +60,8 @@ "Bash(tree:*)", "Bash(npm run lint)", "Bash(cat:*)", - "Bash(./scripts/export-database.sh --help)" + "Bash(./scripts/export-database.sh --help)", + "Bash(xargs:*)" ], "deny": [] } diff --git a/.env.development b/.env.development index 7ce67a0..2d14e55 100644 --- a/.env.development +++ b/.env.development @@ -7,14 +7,12 @@ VITE_AUTH0_DOMAIN=motovaultpro.us.auth0.com VITE_AUTH0_CLIENT_ID=yspR8zdnSxmV8wFIghHynQ08iXAPoQJ3 VITE_AUTH0_AUDIENCE=https://api.motovaultpro.com VITE_API_BASE_URL=/api -VITE_TENANT_ID=admin # Docker Compose Development Configuration # These variables are used by docker-compose for container build args only AUTH0_DOMAIN=motovaultpro.us.auth0.com AUTH0_CLIENT_ID=yspR8zdnSxmV8wFIghHynQ08iXAPoQJ3 AUTH0_AUDIENCE=https://api.motovaultpro.com -TENANT_ID=admin # NOTE: Backend services no longer use this file # Backend configuration comes from: diff --git a/AGENTS.md b/AGENTS.md deleted file mode 120000 index 681311e..0000000 --- a/AGENTS.md +++ /dev/null @@ -1 +0,0 @@ -CLAUDE.md \ No newline at end of file diff --git a/AI-INDEX.md b/AI-INDEX.md index 5dc7c89..bcfbacd 100644 --- a/AI-INDEX.md +++ b/AI-INDEX.md @@ -16,7 +16,7 @@ - Core Backend Modules: `backend/src/core/` (see `backend/src/core/README.md`). - Frontend Overview: `frontend/README.md`. - URLs and Hosts: - - Frontend: `https://admin.motovaultpro.com` + - Frontend: `https://motovaultpro.com` - 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` diff --git a/README.md b/README.md index 69410b9..b172d57 100644 --- a/README.md +++ b/README.md @@ -25,5 +25,5 @@ make test # backend + frontend tests - Backend core: `backend/src/core/README.md` ## URLs and Hosts -- Frontend: `https://admin.motovaultpro.com` +- Frontend: `https://motovaultpro.com` - Backend health: `http://localhost:3001/health` \ No newline at end of file diff --git a/backend/README.md b/backend/README.md index cbbace2..56da99e 100644 --- a/backend/README.md +++ b/backend/README.md @@ -53,7 +53,7 @@ make test - `config-loader.ts` - Environment variable loading and validation - `database.ts` - PostgreSQL connection pool - `redis.ts` - Redis client and cache service -- `tenant.ts` - Tenant configuration utilities +- `user-context.ts` - User context extraction utilities ### Security (Fastify Plugins) - `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 ### Middleware -- `src/core/middleware/tenant.ts` - Tenant extraction and validation +- `src/core/middleware/user-context.ts` - User ID extraction from JWT ### Storage - `src/core/storage/` - Storage abstractions diff --git a/backend/src/core/README.md b/backend/src/core/README.md index fe6be68..37af905 100644 --- a/backend/src/core/README.md +++ b/backend/src/core/README.md @@ -4,7 +4,7 @@ - `config-loader.ts` — Load and validate environment variables - `database.ts` — PostgreSQL connection pool - `redis.ts` — Redis client and cache helpers -- `tenant.ts` — Tenant configuration utilities +- `user-context.ts` — User context utilities ## Plugins (`src/core/plugins/`) - `auth.plugin.ts` — Auth0 JWT via JWKS (@fastify/jwt, get-jwks) @@ -15,7 +15,7 @@ - `logger.ts` — Structured logging (Winston) ## Middleware -- `middleware/tenant.ts` — Tenant extraction/validation +- `middleware/user-context.ts` — User ID extraction from JWT ## Storage (`src/core/storage/`) - `storage.service.ts` — Storage abstraction diff --git a/backend/src/features/documents/README.md b/backend/src/features/documents/README.md index 0bad646..a6268a5 100644 --- a/backend/src/features/documents/README.md +++ b/backend/src/features/documents/README.md @@ -21,7 +21,7 @@ Secure vehicle document management with S3-compatible storage. Metadata and file - **tests/** - All feature tests ## Dependencies -- Internal: core/auth, core/middleware/tenant, core/storage +- Internal: core/auth, core/middleware/user-context, core/storage - Database: documents table ## Quick Commands diff --git a/config/app/production.yml.example b/config/app/production.yml.example index 7d0e9e2..610611c 100755 --- a/config/app/production.yml.example +++ b/config/app/production.yml.example @@ -1,7 +1,6 @@ # MotoVaultPro application ConfigMap template server: port: 3001 - tenant_id: admin database: host: admin-postgres diff --git a/database-exports/schema_20251102.sql.gz b/database-exports/schema_20251102.sql.gz deleted file mode 100644 index 961910e..0000000 Binary files a/database-exports/schema_20251102.sql.gz and /dev/null differ diff --git a/database-exports/schema_20251102_import_instructions.txt b/database-exports/schema_20251102_import_instructions.txt deleted file mode 100644 index e10e0c3..0000000 --- a/database-exports/schema_20251102_import_instructions.txt +++ /dev/null @@ -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;" - diff --git a/database-exports/schema_20251102_metadata.json b/database-exports/schema_20251102_metadata.json deleted file mode 100644 index ee421f1..0000000 --- a/database-exports/schema_20251102_metadata.json +++ /dev/null @@ -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" -} diff --git a/docker-compose.yml b/docker-compose.yml index 4763845..7fe43f8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -48,7 +48,6 @@ services: container_name: mvp-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} diff --git a/docker-compose.yml.backup-phase1-20251101 b/docker-compose.yml.backup-phase1-20251101 deleted file mode 100644 index df2c664..0000000 --- a/docker-compose.yml.backup-phase1-20251101 +++ /dev/null @@ -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 \ No newline at end of file diff --git a/docs/ARCHITECTURE-OVERVIEW.md b/docs/ARCHITECTURE-OVERVIEW.md new file mode 100644 index 0000000..7a3d386 --- /dev/null +++ b/docs/ARCHITECTURE-OVERVIEW.md @@ -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 ) +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 +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 ) +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` diff --git a/docs/PROMPTS.md b/docs/PROMPTS.md index e1e609e..cb40699 100644 --- a/docs/PROMPTS.md +++ b/docs/PROMPTS.md @@ -91,8 +91,7 @@ Agent: Quality Enforcer Agent 6. Delete old code when replacing (no commented code) 7. Use meaningful variable names (`userID` not `id`) 8. ALL quality gates must pass (all green policy) -9. Platform services are independent microservices -10. Feature capsules are self-contained modules +9. Feature capsules are self-contained modules ## Making Changes @@ -114,7 +113,6 @@ Agent: Quality Enforcer Agent **Agent**: Platform Service Agent - Service: `mvp-platform-services/{service}/` - API: `mvp-platform-services/{service}/api/` -- ETL: `mvp-platform-services/{service}/etl/` - After changes: `make rebuild` then check service health ### Database Changes @@ -214,7 +212,6 @@ Each service is independent: mvp-platform-services/{service}/ ├── api/ # FastAPI application ├── database/ # SQLAlchemy models + migrations -├── etl/ # Data pipelines └── tests/ # Service tests ``` @@ -223,7 +220,6 @@ mvp-platform-services/{service}/ - **Auth**: Frontend uses Auth0, backend validates JWTs - **Database**: PostgreSQL with user-isolated data (user_id scoping) - **Platform APIs**: Authenticated via API keys (service-to-service) -- **File uploads**: MinIO S3-compatible storage - **Caching**: Redis with feature-specific TTL strategies - **Testing**: Jest (backend/frontend), pytest (platform services) - **Docker-First**: All development in containers (production-only) @@ -268,313 +264,4 @@ mvp-platform-services/{service}/ - Testing: `docs/TESTING.md` - Context Loading: `.ai/context.json` - Development Guidelines: `CLAUDE.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. - - --- \ No newline at end of file +- Feature Documentation: `backend/src/features/{feature}/README.md` \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 468a657..5acd24b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ # 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 @@ -20,6 +20,6 @@ Project documentation hub for the hybrid platform (platform microservices) and m ## Notes -- Canonical URLs: Frontend `https://admin.motovaultpro.com`, Backend health `http://localhost:3001/health`. -- Hosts entry required: `127.0.0.1 motovaultpro.com admin.motovaultpro.com`. +- Canonical URLs: Frontend `https://motovaultpro.com`, Backend health `http://localhost:3001/health`. +- 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. diff --git a/docs/SECURITY.md b/docs/SECURITY.md index 1ea819d..36e492c 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -19,7 +19,7 @@ ### VIN Handling - 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) ### Database Security diff --git a/docs/TENANT-REMNANTS-ANALYSIS.md b/docs/TENANT-REMNANTS-ANALYSIS.md new file mode 100644 index 0000000..9efa8f0 --- /dev/null +++ b/docs/TENANT-REMNANTS-ANALYSIS.md @@ -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: `} />` + - **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. diff --git a/docs/VEHICLES-API.md b/docs/VEHICLES-API.md index dd4a038..6e3c182 100644 --- a/docs/VEHICLES-API.md +++ b/docs/VEHICLES-API.md @@ -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. ## 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. ## 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) 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` -- Clear platform cache: `docker compose exec -T mvp-platform-vehicles-redis sh -lc "redis-cli FLUSHALL"` +- `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-redis sh -lc "redis-cli FLUSHALL"` ## MotoVaultPro Backend (Application Service) @@ -135,21 +135,22 @@ VIN/License rule ### Rebuild a single service - Frontend: `docker compose up -d --build frontend` - 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 - Backend: `/health` – shows status/feature list - Platform: `/health` – shows database/cache status - Logs: - `make logs-backend`, `make logs-frontend` - - `docker compose logs -f mvp-platform-vehicles-api` + - `docker compose logs -f mvp-platform` ### Common Reset Sequences - Platform seed reapply (non‑destructive): apply `005_seed_specific_vehicles.sql` and flush Redis cache. -- Platform reset (destructive only to platform DB/cache): - - `docker compose rm -sf mvp-platform-vehicles-db mvp-platform-vehicles-redis` - - `docker volume rm motovaultpro_platform_vehicles_data motovaultpro_platform_vehicles_redis_data` - - `docker compose up -d mvp-platform-vehicles-db mvp-platform-vehicles-redis mvp-platform-vehicles-api` +- Platform reset (WARNING - DESTRUCTIVE to shared resources): + - `docker compose rm -sf mvp-postgres mvp-redis` + - `docker volume rm motovaultpro_postgres_data motovaultpro_redis_data` + - `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 - 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). - Run `make migrate` or ensure backend container auto‑migrate is succeeding; check `docker compose logs backend`. - 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: - Ensure Postgres is up; the runner now waits/retries, but confirm logs. diff --git a/docs/redesign/AGENT-MANIFEST.md b/docs/redesign/AGENT-MANIFEST.md deleted file mode 100644 index 062151c..0000000 --- a/docs/redesign/AGENT-MANIFEST.md +++ /dev/null @@ -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 diff --git a/docs/redesign/DEPENDENCY-GRAPH.md b/docs/redesign/DEPENDENCY-GRAPH.md deleted file mode 100644 index a721cb7..0000000 --- a/docs/redesign/DEPENDENCY-GRAPH.md +++ /dev/null @@ -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. diff --git a/docs/redesign/EXECUTION-STATE.json b/docs/redesign/EXECUTION-STATE.json deleted file mode 100644 index 0c44391..0000000 --- a/docs/redesign/EXECUTION-STATE.json +++ /dev/null @@ -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)" - ] -} diff --git a/docs/redesign/FILE-MANIFEST.md b/docs/redesign/FILE-MANIFEST.md deleted file mode 100644 index 640513f..0000000 --- a/docs/redesign/FILE-MANIFEST.md +++ /dev/null @@ -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 diff --git a/docs/redesign/PHASE-01-DOCKER-COMPOSE.md b/docs/redesign/PHASE-01-DOCKER-COMPOSE.md deleted file mode 100644 index dd4b9cd..0000000 --- a/docs/redesign/PHASE-01-DOCKER-COMPOSE.md +++ /dev/null @@ -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). diff --git a/docs/redesign/PHASE-02-REMOVE-TENANT.md b/docs/redesign/PHASE-02-REMOVE-TENANT.md deleted file mode 100644 index 1fce43f..0000000 --- a/docs/redesign/PHASE-02-REMOVE-TENANT.md +++ /dev/null @@ -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}} -} -``` diff --git a/docs/redesign/PHASE-03-FILESYSTEM-STORAGE.md b/docs/redesign/PHASE-03-FILESYSTEM-STORAGE.md deleted file mode 100644 index f924e4d..0000000 --- a/docs/redesign/PHASE-03-FILESYSTEM-STORAGE.md +++ /dev/null @@ -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 { - 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 { - const filePath = path.join(this.basePath, key); - return createReadStream(filePath); - } - - async deleteObject(bucket: string, key: string): Promise { - const filePath = path.join(this.basePath, key); - await fs.unlink(filePath); - } - - async headObject(bucket: string, key: string): Promise { - 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 { - // 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}} -} -``` diff --git a/docs/redesign/PHASE-04-CONFIG-CLEANUP.md b/docs/redesign/PHASE-04-CONFIG-CLEANUP.md deleted file mode 100644 index 5b82c0d..0000000 --- a/docs/redesign/PHASE-04-CONFIG-CLEANUP.md +++ /dev/null @@ -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"}} -} -``` diff --git a/docs/redesign/PHASE-05-NETWORK-SIMPLIFICATION.md b/docs/redesign/PHASE-05-NETWORK-SIMPLIFICATION.md deleted file mode 100644 index 137608c..0000000 --- a/docs/redesign/PHASE-05-NETWORK-SIMPLIFICATION.md +++ /dev/null @@ -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}} -} -``` diff --git a/docs/redesign/PHASE-06-BACKEND-UPDATES.md b/docs/redesign/PHASE-06-BACKEND-UPDATES.md deleted file mode 100644 index 63679bf..0000000 --- a/docs/redesign/PHASE-06-BACKEND-UPDATES.md +++ /dev/null @@ -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}} -} -``` diff --git a/docs/redesign/PHASE-07-DATABASE-UPDATES.md b/docs/redesign/PHASE-07-DATABASE-UPDATES.md deleted file mode 100644 index fecc7d5..0000000 --- a/docs/redesign/PHASE-07-DATABASE-UPDATES.md +++ /dev/null @@ -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}} -} -``` diff --git a/docs/redesign/PHASE-08-PLATFORM-SERVICE.md b/docs/redesign/PHASE-08-PLATFORM-SERVICE.md deleted file mode 100644 index f18f83a..0000000 --- a/docs/redesign/PHASE-08-PLATFORM-SERVICE.md +++ /dev/null @@ -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}} -} -``` diff --git a/docs/redesign/PHASE-09-DOCUMENTATION.md b/docs/redesign/PHASE-09-DOCUMENTATION.md deleted file mode 100644 index 342b9ca..0000000 --- a/docs/redesign/PHASE-09-DOCUMENTATION.md +++ /dev/null @@ -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"}} -} -``` diff --git a/docs/redesign/PHASE-10-FRONTEND-UPDATES.md b/docs/redesign/PHASE-10-FRONTEND-UPDATES.md deleted file mode 100644 index c398e99..0000000 --- a/docs/redesign/PHASE-10-FRONTEND-UPDATES.md +++ /dev/null @@ -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: -// -// -// -``` - -### 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}} -} -``` diff --git a/docs/redesign/PHASE-11-TESTING.md b/docs/redesign/PHASE-11-TESTING.md deleted file mode 100644 index 1854e6a..0000000 --- a/docs/redesign/PHASE-11-TESTING.md +++ /dev/null @@ -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 < 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 -``` diff --git a/docs/redesign/VALIDATION-CHECKLIST.md b/docs/redesign/VALIDATION-CHECKLIST.md deleted file mode 100644 index 8be9788..0000000 --- a/docs/redesign/VALIDATION-CHECKLIST.md +++ /dev/null @@ -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 diff --git a/docs/redesign/VALIDATION-REPORT-20251101.md b/docs/redesign/VALIDATION-REPORT-20251101.md deleted file mode 100644 index a77d723..0000000 --- a/docs/redesign/VALIDATION-REPORT-20251101.md +++ /dev/null @@ -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 diff --git a/mvp-platform-services/landing/Dockerfile b/mvp-platform-services/landing/Dockerfile deleted file mode 100644 index 914efc5..0000000 --- a/mvp-platform-services/landing/Dockerfile +++ /dev/null @@ -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;"] diff --git a/mvp-platform-services/landing/index.html b/mvp-platform-services/landing/index.html deleted file mode 100644 index 0d867a5..0000000 --- a/mvp-platform-services/landing/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - MotoVaultPro - Vehicle Management Platform - - -
- - - diff --git a/mvp-platform-services/landing/nginx.conf b/mvp-platform-services/landing/nginx.conf deleted file mode 100644 index 6d258ac..0000000 --- a/mvp-platform-services/landing/nginx.conf +++ /dev/null @@ -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"; - } -} diff --git a/mvp-platform-services/landing/nginx.conf.backup b/mvp-platform-services/landing/nginx.conf.backup deleted file mode 100644 index 95f88d4..0000000 --- a/mvp-platform-services/landing/nginx.conf.backup +++ /dev/null @@ -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"; - } -} diff --git a/mvp-platform-services/landing/package.json b/mvp-platform-services/landing/package.json deleted file mode 100644 index bbe3447..0000000 --- a/mvp-platform-services/landing/package.json +++ /dev/null @@ -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" - } -} diff --git a/mvp-platform-services/landing/src/App.tsx b/mvp-platform-services/landing/src/App.tsx deleted file mode 100644 index 4cee551..0000000 --- a/mvp-platform-services/landing/src/App.tsx +++ /dev/null @@ -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 ( -
- - } /> - } /> - } /> - -
- ) -} - -export default App diff --git a/mvp-platform-services/landing/src/components/CallbackHandler.tsx b/mvp-platform-services/landing/src/components/CallbackHandler.tsx deleted file mode 100644 index 725d8c3..0000000 --- a/mvp-platform-services/landing/src/components/CallbackHandler.tsx +++ /dev/null @@ -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 ( -
-

Redirecting...

-

Please wait while we redirect you to MotoVaultPro.

-
- ) -} - -export default CallbackHandler diff --git a/mvp-platform-services/landing/src/components/HomePage.tsx b/mvp-platform-services/landing/src/components/HomePage.tsx deleted file mode 100644 index 4b6597b..0000000 --- a/mvp-platform-services/landing/src/components/HomePage.tsx +++ /dev/null @@ -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 ( -
-
-

MotoVaultPro

-

The complete vehicle management platform for automotive professionals

-
- -
-
-

Features

-
    -
  • Vehicle inventory management
  • -
  • Maintenance tracking and scheduling
  • -
  • Fuel log analytics
  • -
  • Service station locator
  • -
  • Multi-tenant architecture for teams
  • -
-
- -
-

Get Started

-

Already have an account?

- - -

- Need to join a team? Contact your tenant administrator for an invitation. -

-
-
-
- ) -} - -export default HomePage diff --git a/mvp-platform-services/landing/src/components/TenantSignup.tsx b/mvp-platform-services/landing/src/components/TenantSignup.tsx deleted file mode 100644 index 4c46bdd..0000000 --- a/mvp-platform-services/landing/src/components/TenantSignup.tsx +++ /dev/null @@ -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(null) - const [loading, setLoading] = useState(true) - const [error, setError] = useState(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
Loading...
- } - - if (error || !tenant) { - return ( -
-

Tenant Not Found

-

{error}

- Return to Homepage -
- ) - } - - return ( -
-
-

Join {tenant.name}

-

Create your account to get started

-
- -
-
-

What happens next?

-
    -
  1. Create your account with Auth0
  2. -
  3. Your signup request will be sent to the tenant administrator
  4. -
  5. Once approved, you'll receive access to {tenant.name}
  6. -
  7. Login at {tenant.id}.motovaultpro.com
  8. -
- -
- -
-
- - -
-
- ) -} - -export default TenantSignup diff --git a/mvp-platform-services/landing/src/main.tsx b/mvp-platform-services/landing/src/main.tsx deleted file mode 100644 index 9c86559..0000000 --- a/mvp-platform-services/landing/src/main.tsx +++ /dev/null @@ -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( - - - - - -) diff --git a/mvp-platform-services/landing/src/vite-env.d.ts b/mvp-platform-services/landing/src/vite-env.d.ts deleted file mode 100644 index 840403f..0000000 --- a/mvp-platform-services/landing/src/vite-env.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -/// - -interface ImportMetaEnv { - readonly VITE_AUTH0_DOMAIN: string - readonly VITE_AUTH0_CLIENT_ID: string - readonly VITE_TENANTS_API_URL: string -} - -interface ImportMeta { - readonly env: ImportMetaEnv -} diff --git a/mvp-platform-services/landing/tsconfig.json b/mvp-platform-services/landing/tsconfig.json deleted file mode 100644 index 3934b8f..0000000 --- a/mvp-platform-services/landing/tsconfig.json +++ /dev/null @@ -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" }] -} diff --git a/mvp-platform-services/landing/tsconfig.node.json b/mvp-platform-services/landing/tsconfig.node.json deleted file mode 100644 index 494bfe0..0000000 --- a/mvp-platform-services/landing/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/mvp-platform-services/landing/vite.config.ts b/mvp-platform-services/landing/vite.config.ts deleted file mode 100644 index 3dfdd70..0000000 --- a/mvp-platform-services/landing/vite.config.ts +++ /dev/null @@ -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 - } -}) diff --git a/mvp-platform-services/tenants/AUTH0-CONFIG.md b/mvp-platform-services/tenants/AUTH0-CONFIG.md deleted file mode 100644 index 1672a5d..0000000 --- a/mvp-platform-services/tenants/AUTH0-CONFIG.md +++ /dev/null @@ -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 = ` - Signing up for: ${tenantName}
- Your account will require admin approval before you can access the system. - `; - 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 => { - 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. diff --git a/mvp-platform-services/tenants/api/main.py b/mvp-platform-services/tenants/api/main.py deleted file mode 100644 index 362d4e8..0000000 --- a/mvp-platform-services/tenants/api/main.py +++ /dev/null @@ -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) diff --git a/mvp-platform-services/tenants/docker/Dockerfile.api b/mvp-platform-services/tenants/docker/Dockerfile.api deleted file mode 100644 index 7606d06..0000000 --- a/mvp-platform-services/tenants/docker/Dockerfile.api +++ /dev/null @@ -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"] diff --git a/mvp-platform-services/tenants/requirements.txt b/mvp-platform-services/tenants/requirements.txt deleted file mode 100644 index 9ba70cf..0000000 --- a/mvp-platform-services/tenants/requirements.txt +++ /dev/null @@ -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 diff --git a/mvp-platform-services/tenants/sql/schema/001_tenants_schema.sql b/mvp-platform-services/tenants/sql/schema/001_tenants_schema.sql deleted file mode 100644 index 41e3e5c..0000000 --- a/mvp-platform-services/tenants/sql/schema/001_tenants_schema.sql +++ /dev/null @@ -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; diff --git a/scripts/provision-tenant.sh b/scripts/provision-tenant.sh deleted file mode 100755 index f889d83..0000000 --- a/scripts/provision-tenant.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -TENANT_ID=${1:-} - -if [[ -z "$TENANT_ID" ]]; then - echo "Usage: $0 " >&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" <> "$COMPOSE_FILE" </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."