# Vehicles API – Platform Rebuild, App Integration, and Operations 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). - Goal: Predictable year→make→model→trim→engine cascades, production‑only workflow, AI‑friendly code layout and docs. ## Platform Vehicles Service ### Database Schema (Postgres schema: `vehicles`) - `make(id, name)` - `model(id, make_id → make.id, name)` - `model_year(id, model_id → model.id, year)` - `trim(id, model_year_id → model_year.id, name)` - `engine(id, name, code, displacement_l, cylinders, fuel_type, aspiration)` - `trim_engine(trim_id → trim.id, engine_id → engine.id)` - Optional (present, not exposed yet): `transmission`, `trim_transmission`, `performance` Idempotent constraints/indexes added where applicable (e.g., unique lower(name), unique(model_id, year), guarded `CREATE INDEX IF NOT EXISTS`, guarded trigger). ### API Endpoints (Bearer auth required) Prefix: `/api/v1/vehicles` - `GET /years` → `[number]` distinct years (desc) - `GET /makes?year={year}` → `{ makes: { id, name }[] }` - `GET /models?year={year}&make_id={make_id}` → `{ models: { id, name }[] }` - `GET /trims?year={year}&make_id={make_id}&model_id={model_id}` → `{ trims: { id, name }[] }` - `GET /engines?year={year}&make_id={make_id}&model_id={model_id}&trim_id={trim_id}` → `{ engines: { id, name }[] }` Notes: - `make_id` is maintained for a consistent query chain, but engines are enforced by `(year, model_id, trim_id)`. - Trims/engines include `id` to enable the next hop in the UI. ### Authentication - Header: `Authorization: Bearer ${API_KEY}` - API env: `API_KEY` - Backend env (consumer): `PLATFORM_VEHICLES_API_KEY` ### Caching (Redis) - Keys: `dropdown:years`, `dropdown:makes:{year}`, `dropdown:models:{year}:{make}`, `dropdown:trims:{year}:{model}`, `dropdown:engines:{year}:{model}:{trim}` - Default TTL: 6 hours ### Seeds & Specific Examples Seed files under `mvp-platform-services/vehicles/sql/schema/`: - `001_schema.sql` – base tables - `002_constraints_indexes.sql` – constraints/indexes - `003_seed_minimal.sql` – minimal Honda/Toyota scaffolding - `004_seed_filtered_makes.sql` – Chevrolet/GMC examples - `005_seed_specific_vehicles.sql` – requested examples: - 2023 GMC Sierra 1500 AT4x → Engine L87 (6.2L V8) - 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"` ## MotoVaultPro Backend (Application Service) ### Proxy Dropdown Endpoints Prefix: `/api/vehicles/dropdown` - `GET /years` → `[number]` (calls platform `/years`) - `GET /makes?year=YYYY` → `{ id, name }[]` - `GET /models?year=YYYY&make_id=ID` → `{ id, name }[]` - `GET /trims?year=YYYY&make_id=ID&model_id=ID` → `{ id, name }[]` - `GET /engines?year=YYYY&make_id=ID&model_id=ID&trim_id=ID` → `{ id, name }[]` Changes: - Engines route now requires `trim_id`. - New `/years` route for UI bootstrap. ### Platform Client & Integration - `PlatformVehiclesClient`: - Added `getYears()` - `getEngines(year, makeId, modelId, trimId)` to pass trim id - `PlatformIntegrationService` consumed by `VehiclesService` updated accordingly. ### Authentication (App) - Auth0 JWT enforced via Fastify + JWKS. No mock users. ### Migrations (Production‑Quality) - Migrations packaged in image under `/app/migrations/features/[feature]/migrations`. - Runner (`backend/src/_system/migrations/run-all.ts`): - Reads base dir from `MIGRATIONS_DIR` (env in Dockerfile) - Tracks executed files in `_migrations` (idempotent) - Wait/retry for DB readiness to avoid flapping on cold starts - Auto‑migrate on backend container start: `node dist/_system/migrations/run-all.js && npm start` - Manual: `make migrate` (runs runner inside the container) ## Frontend Changes - Vehicles form cascades: year → make → model → trim → engine. - Engines load only after a trim is selected (requires `trim_id`). - Validation updated: user must provide either a 17‑char VIN or a non‑empty license plate. - VIN Decode button still requires a valid 17‑char VIN. - APIs used: - `/api/vehicles/dropdown/years` - `/api/vehicles/dropdown/makes|models|trims|engines` ## Add Vehicle Form – Change/Add/Modify/Delete Fields (Fast Track) Where to edit - UI + validation: `frontend/src/features/vehicles/components/VehicleForm.tsx` - Frontend types: `frontend/src/features/vehicles/types/vehicles.types.ts` - Backend controller/service/repo: `backend/src/features/vehicles/api/vehicles.controller.ts`, `domain/vehicles.service.ts`, `data/vehicles.repository.ts`, types in `domain/vehicles.types.ts` - App DB migrations: `backend/src/features/vehicles/migrations/*.sql` (auto‑migrated on backend start) Add a new field (example: bodyStyle) 1) DB: `ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS body_style VARCHAR(100);` in a new migration file. 2) Backend: add `bodyStyle?: string;` to types; include in repository insert/update mapping as `body_style`. 3) Frontend: add `bodyStyle` to Zod schema and a new input bound via `register('bodyStyle')`. 4) Rebuild frontend/backend and verify in Network + logs. Modify an existing field - Update labels/placeholders in VehicleForm. - Update Zod schema for new validation rules; mirror on the server if desired. - Adjust service logic only if business behavior changes. Delete a field (safe path) - Remove from VehicleForm and frontend types. - Remove from backend types/repository mapping. - Optional migration to drop the column later. Dropdown ordering - Implemented in VehicleForm; current order is Year → Make → Model → Trim → Engine → Transmission (static). - Engine select is enabled only after a Trim is selected. VIN/License rule - Frontend Zod: either 17‑char VIN or non‑empty license plate; if no plate, VIN must be 17. - Backend controller enforces the same rule; service decodes/validates only when VIN is present. - Repository normalizes empty VIN to NULL to avoid unique collisions. ## Operations ### 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` ### 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` ### 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` ## Security Summary - Platform: `Authorization: Bearer ${API_KEY}` required on all `/api/v1/vehicles/*` endpoints. - App Backend: Auth0 JWT required on all protected `/api/*` routes. ## CI Summary - Workflow `.github/workflows/ci.yml` builds backend/frontend/platform API. - Runs backend lint/tests in a builder image on a stable network. ## Troubleshooting - Frontend shows generic “Server error” right after login: - 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. - Backend flapping on start after rebuild: - Ensure Postgres is up; the runner now waits/retries, but confirm logs. ## Notable Files - Platform schema & seeds: `mvp-platform-services/vehicles/sql/schema/001..005` - Platform API code: `mvp-platform-services/vehicles/api/*` - Backend dropdown proxy: `backend/src/features/vehicles/api/*` - Backend platform client: `backend/src/features/vehicles/external/platform-vehicles/*` - Backend migrations runner: `backend/src/_system/migrations/run-all.ts` - Frontend vehicles UI: `frontend/src/features/vehicles/*`