9.3 KiB
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 backend (Fastify + TypeScript) includes an integrated platform module that shares Postgres and Redis with the rest of the stack.
- Goal: Predictable year→make→model→trim→engine cascades, production‑only workflow, AI‑friendly code layout and docs.
Platform Vehicles Module
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).
Dropdown API (Bearer auth required)
Prefix: /api/vehicles/dropdown
GET /years→[number](latest to oldest model years)GET /makes?year={year}→{ id, name }[](makes available in that year)GET /models?year={year}&make_id={make}→{ id, name }[](models filtered by year + make)GET /trims?year={year}&make_id={make}&model_id={model}→{ id, name }[](trims for the selection)GET /engines?year={year}&make_id={make}&model_id={model}&trim_id={trim}→{ id, name }[](engines for the trim)GET /transmissions?year={year}&make_id={make}&model_id={model}→{ id, name }[](Automatic,Manual)
Selection order is enforced: each endpoint requires the IDs returned by the previous stage, so users never see invalid combinations (e.g., 2023 Chevrolet excludes the S-10, 1999 GMC trims exclude AT4X, etc.).
Platform module (internal bridge)
Prefix: /api/platform
- Same hierarchical endpoints as above, but responses are wrapped (
{ makes: [...] },{ models: [...] }) for service-to-service integrations. - VIN decode endpoint:
GET /api/platform/vehicle?vin={vin}
Authentication
- Auth0 JWT via
Authorization: Bearer ${JWT_TOKEN}(required for both/api/vehicles/*and/api/platform/*) - Configured in backend:
src/core/plugins/auth.plugin.tswith JWKS validation
Caching (Redis)
- Keys:
platform:years,platform:vehicle-data:makes:{year},platform:vehicle-data:models:{year}:{make},platform:vehicle-data:trims:{year}:{model},platform:vehicle-data:engines:{year}:{model}:{trim} - Dropdown TTL: 6 hours (
21600s) - VIN decode TTL: 7 days (
604800s) viaplatform:vin-decode:{vin} - Implementation:
backend/src/features/platform/domain/platform-cache.service.ts
Seeds & Specific Examples
Platform seed migrations (TypeScript backend):
- Schema definition (
backend/src/features/platform/migrations/001_create_platform_schema.sql) - Constraints and indexes (
backend/src/features/platform/migrations/002_create_indexes.sql) - Sample vehicle data (
backend/src/features/platform/migrations/003_seed_vehicles.sql) Seeds are auto-migrated on backend container start viabackend/src/_system/migrations/run-all.ts.
Clear platform cache:
docker compose exec -T mvp-redis sh -lc "redis-cli FLUSHALL"- Or restart containers:
make rebuild
MotoVaultPro Backend (Application Service)
Proxy Dropdown Endpoints
Vehicles service simply re-emits the data returned by Platform VehicleDataService, normalizing it to { id, name }[] arrays for frontend consumption. Redis caching and Postgres lookups all remain centralized in the platform module.
Platform Integration
VehiclesServicelazily instantiatesVehicleDataServiceviagetVehicleDataService(), guaranteeing a shared cache.- Each dropdown call passes the shared Postgres pool (
getPool()) and propagates selection context (year/make/model/trim). - Transmission dropdown is intentionally static (
Automatic,Manual) until richer metadata is available.
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
_migrationstable and skips already executed files - Idempotent at file level: Safe to re-run migration system multiple times
- Wait/retry for DB readiness to avoid flapping on cold starts
- Reads base dir from
- 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).
- Engines load only after a trim is selected (requires
- 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/api/vehicles/dropdown/transmissions
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 indomain/vehicles.types.ts - App DB migrations:
backend/src/features/vehicles/migrations/*.sql(auto‑migrated on backend start)
Add a new field (example: bodyStyle)
- DB:
ALTER TABLE vehicles ADD COLUMN IF NOT EXISTS body_style VARCHAR(100);in a new migration file. - Backend: add
bodyStyle?: string;to types; include in repository insert/update mapping asbody_style. - Frontend: add
bodyStyleto Zod schema and a new input bound viaregister('bodyStyle'). - 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 (includes platform module):
docker compose up -d --build backend
Logs & Health
- Backend:
https://motovaultpro.com/api/health– shows status/feature list, including platform readiness - Logs:
make logs-backend,make logs-frontend
Common Reset Sequences
- Platform seed reapply (non‑destructive): apply
005_seed_specific_vehicles.sqland flush Redis cache. - Platform reset (WARNING - DESTRUCTIVE to shared resources):
docker compose rm -sf mvp-postgres mvp-redisdocker volume rm motovaultpro_postgres_data motovaultpro_redis_datadocker compose up -d mvp-postgres mvp-redis mvp-backend- Note: This will destroy ALL application data, not just platform data, as database and cache are shared
Security Summary
- Platform Module: Auth0 JWT via
Authorization: Bearer ${JWT_TOKEN}required on all/api/platform/*endpoints. - Vehicles Feature: Auth0 JWT required on all protected
/api/vehicles/*routes. - Health Check:
/api/healthis unauthenticated (Traefik readiness probe).
CI Summary
- Workflow
.github/workflows/ci.ymlbuilds 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/vehicles500s (migrations not run or DB unavailable). - Run
make migrateor ensure backend container auto‑migrate is succeeding; checkdocker compose logs backend.
- Check backend
- Dropdowns not updating after seed:
- Run specific seed SQL (see above) and
redis-cli FLUSHALLon shared Redis (mvp-redis).
- Run specific seed SQL (see above) and
- Backend flapping on start after rebuild:
- Ensure Postgres is up; the runner now waits/retries, but confirm logs.
Notable Files
- Platform schema & seeds: maintained by database admins (legacy FastAPI scripts available on request)
- Platform API integration:
backend/src/features/platform/api/* - Backend dropdown proxy:
backend/src/features/vehicles/api/* - Backend platform module:
backend/src/features/platform/* - Backend migrations runner:
backend/src/_system/migrations/run-all.ts - Frontend vehicles UI:
frontend/src/features/vehicles/*