Merge branch 'main' of github.com:ericgullickson/motovaultpro
This commit is contained in:
@@ -398,8 +398,11 @@ docker ps
|
||||
docker logs mvp-backend -f
|
||||
docker logs mvp-postgres -f
|
||||
|
||||
# Test health endpoints
|
||||
curl http://localhost:3001/health # Backend (includes platform module)
|
||||
# Test health endpoints (via Traefik)
|
||||
curl https://motovaultpro.com/api/health # Backend (includes platform module)
|
||||
|
||||
# Or from within backend container
|
||||
docker compose exec mvp-backend curl http://localhost:3001/health
|
||||
```
|
||||
|
||||
### Database Access
|
||||
|
||||
@@ -66,27 +66,30 @@ vin_cache (
|
||||
**TTL**: 30 days (application-managed)
|
||||
|
||||
### fuel_logs
|
||||
Tracks fuel purchases and efficiency.
|
||||
Tracks fuel purchases and efficiency metrics.
|
||||
|
||||
```sql
|
||||
fuel_logs (
|
||||
id UUID PRIMARY KEY,
|
||||
user_id VARCHAR(255) NOT NULL,
|
||||
vehicle_id UUID NOT NULL REFERENCES vehicles(id),
|
||||
date DATE NOT NULL,
|
||||
odometer_reading INTEGER NOT NULL,
|
||||
gallons DECIMAL(8,3) NOT NULL,
|
||||
price_per_gallon DECIMAL(6,3),
|
||||
total_cost DECIMAL(8,2),
|
||||
station_name VARCHAR(200),
|
||||
vehicle_id UUID NOT NULL REFERENCES vehicles(id) ON DELETE CASCADE,
|
||||
date_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
odometer INTEGER,
|
||||
trip_distance DECIMAL(10,2),
|
||||
fuel_type VARCHAR(50),
|
||||
fuel_grade VARCHAR(50),
|
||||
fuel_units DECIMAL(10,3) NOT NULL,
|
||||
cost_per_unit DECIMAL(10,3) NOT NULL,
|
||||
total_cost DECIMAL(10,2),
|
||||
location_data VARCHAR(500),
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP WITH TIME ZONE,
|
||||
updated_at TIMESTAMP WITH TIME ZONE
|
||||
)
|
||||
```
|
||||
|
||||
**Foreign Keys**: vehicle_id → vehicles.id
|
||||
**Indexes**: user_id, vehicle_id, date
|
||||
**Foreign Keys**: vehicle_id → vehicles.id (ON DELETE CASCADE)
|
||||
**Indexes**: user_id, vehicle_id, date_time, created_at
|
||||
|
||||
### stations
|
||||
Gas station locations and details.
|
||||
@@ -107,7 +110,8 @@ stations (
|
||||
```
|
||||
|
||||
**External Source**: Google Maps Places API
|
||||
**Cache Strategy**: 1 hour TTL via Redis
|
||||
**Storage**: Persisted in PostgreSQL with station_cache table
|
||||
**Cache Strategy**: Postgres-based cache with TTL management
|
||||
|
||||
### maintenance
|
||||
Vehicle maintenance records and scheduling.
|
||||
@@ -116,8 +120,9 @@ Vehicle maintenance records and scheduling.
|
||||
maintenance (
|
||||
id UUID PRIMARY KEY,
|
||||
user_id VARCHAR(255) NOT NULL,
|
||||
vehicle_id UUID NOT NULL REFERENCES vehicles(id),
|
||||
type VARCHAR(100) NOT NULL, -- oil_change, tire_rotation, etc
|
||||
vehicle_id UUID NOT NULL REFERENCES vehicles(id) ON DELETE CASCADE,
|
||||
type VARCHAR(100) NOT NULL,
|
||||
category VARCHAR(50),
|
||||
description TEXT,
|
||||
due_date DATE,
|
||||
due_mileage INTEGER,
|
||||
@@ -132,8 +137,9 @@ maintenance (
|
||||
)
|
||||
```
|
||||
|
||||
**Foreign Keys**: vehicle_id → vehicles.id
|
||||
**Foreign Keys**: vehicle_id → vehicles.id (ON DELETE CASCADE)
|
||||
**Indexes**: user_id, vehicle_id, due_date, is_completed
|
||||
**Constraints**: Unique(vehicle_id, type), Check(category IN valid values)
|
||||
|
||||
## Relationships
|
||||
|
||||
@@ -153,9 +159,10 @@ stations (independent - no FK relationships)
|
||||
- No cross-user data access possible
|
||||
|
||||
### Referential Integrity
|
||||
- fuel_logs.vehicle_id → vehicles.id (CASCADE on update, RESTRICT on delete)
|
||||
- maintenance.vehicle_id → vehicles.id (CASCADE on update, RESTRICT on delete)
|
||||
- Soft deletes on vehicles (deleted_at) preserve referential data
|
||||
- fuel_logs.vehicle_id → vehicles.id (ON DELETE CASCADE)
|
||||
- maintenance.vehicle_id → vehicles.id (ON DELETE CASCADE)
|
||||
- Cascading deletes ensure related logs/maintenance are removed when vehicle is deleted
|
||||
- Soft deletes on vehicles (deleted_at) may result in orphaned hard-deleted related records
|
||||
|
||||
### VIN Validation
|
||||
- Exactly 17 characters
|
||||
@@ -166,14 +173,16 @@ stations (independent - no FK relationships)
|
||||
## Caching Strategy
|
||||
|
||||
### Application-Level Caching (Redis)
|
||||
- **VIN decodes**: 30 days (key: `vpic:vin:{vin}`)
|
||||
- **Platform dropdown data**: 6 hours (key: `dropdown:{dataType}:{params}`)
|
||||
- **VIN decodes**: 7 days (key: `vin:decode:{vin}`)
|
||||
- **User vehicle lists**: 5 minutes (key: `vehicles:user:{userId}`)
|
||||
- **Station searches**: 1 hour (key: `stations:search:{query}`)
|
||||
- **Maintenance upcoming**: 1 hour (key: `maintenance:upcoming:{userId}`)
|
||||
- **Fuel logs per vehicle**: 5 minutes (key: `fuel-logs:vehicle:{vehicleId}:{unitSystem}`)
|
||||
- **Vehicle statistics**: Real-time (no caching, fresh queries)
|
||||
- **Maintenance data**: Unit system-aware caching where applicable
|
||||
|
||||
### Database-Level Caching
|
||||
- **vin_cache table**: Persistent 30-day cache for vPIC API results
|
||||
- **Cleanup**: Application-managed, removes entries older than 30 days
|
||||
- **vin_cache table**: Persistent cache for VIN decodes
|
||||
- **Cleanup**: Application-managed based on TTL strategy
|
||||
|
||||
## Migration Commands
|
||||
|
||||
|
||||
@@ -21,59 +21,5 @@ Project documentation hub for the 5-container single-tenant architecture with in
|
||||
|
||||
## Notes
|
||||
|
||||
- Canonical URLs: Frontend `https://motovaultpro.com`, Backend health `http://localhost:3001/health`.
|
||||
- Feature test coverage: Basic test structure exists for vehicles and documents features; other features have placeholder tests.
|
||||
|
||||
|
||||
## Cleanup Notes
|
||||
> Documentation Audit
|
||||
|
||||
- Documented commands make test/make test-frontend appear across README.md:12-17, backend/README.md:20-38, docs/TESTING.md:24-49, AI-INDEX.md:8, and frontend/
|
||||
README.md:8-28; the Makefile only advertises them in help (Makefile:11-12) with no corresponding targets, so the instructions currently break.
|
||||
- README.md:27 and AI-INDEX.md:19 point folks to http://localhost:3001/health, but docker-compose.yml:77-135 never exposes that port, meaning the reachable
|
||||
probe is https://motovaultpro.com/api/health via Traefik.
|
||||
- docs/TESTING.md:11-99,169-175 commit to full per-feature suites and fixtures such as vehicles.fixtures.json, yet backend/src/features/fuel-logs/tests and
|
||||
backend/src/features/maintenance/tests contain no files (see find output), and backend/src/features/vehicles/tests/fixtures is empty.
|
||||
- Backend fuel-log docs still describe the legacy contract (gallons, pricePerGallon, mpg field) in backend/src/features/fuel-logs/README.md:20-78, but the
|
||||
code now accepts/returns dateTime, fuelUnits, costPerUnit, efficiency, etc. (backend/src/features/fuel-logs/domain/fuel-logs.service.ts:17-320).
|
||||
|
||||
Security & Platform
|
||||
|
||||
- docs/VEHICLES-API.md:35-36 and 149-151 still require an API key, while the platform routes enforce Auth0 JWTs via fastify.authenticate (backend/src/
|
||||
features/platform/api/platform.routes.ts:20-42); there’s no API key configuration in the repo.
|
||||
- docs/VEHICLES-API.md:38-41 promises 1-hour Redis TTLs, but PlatformCacheService stores dropdown data for six hours and successful VIN decodes for seven days
|
||||
(backend/src/features/platform/domain/platform-cache.service.ts:27-110).
|
||||
- docs/SECURITY.md:15-16 claims “Unauthenticated Endpoints – None,” yet /health and /api/health are open (backend/src/app.ts:69-86); docs/SECURITY.md:25-
|
||||
29 also states Postgres connections are encrypted even though the pool uses a plain postgresql:// URL without SSL options (backend/src/core/config/config-
|
||||
loader.ts:213-218; backend/src/core/config/database.ts:1-16).
|
||||
- docs/SECURITY.md:21-23 references the old FastAPI VIN service, but VIN decoding now lives entirely in TypeScript (backend/src/features/platform/domain/vin-
|
||||
decode.service.ts:1-114).
|
||||
|
||||
Feature Guides
|
||||
|
||||
- backend/src/features/vehicles/README.md:15-108 still references an implemented dropdown proxy, a platform-vehicles client folder, and a platform-
|
||||
vehicles.client.test.ts, yet the service methods remain TODO stubs returning empty arrays (backend/src/features/vehicles/domain/vehicles.service.ts:165-193)
|
||||
and there is no such client or test file in the tree.
|
||||
- docs/VEHICLES-API.md:58-97 says the frontend consumes /api/vehicles/dropdown/*, but the current client hits /platform/* and expects raw arrays (frontend/
|
||||
src/features/vehicles/api/vehicles.api.ts:35-69) while the backend responds with wrapped objects like { makes: [...] } (backend/src/features/platform/api/
|
||||
platform.controller.ts:48-94), so either the docs or the code path needs realignment.
|
||||
- backend/src/features/fuel-logs/README.md:150-153 advertises a fuel-stats:vehicle:{vehicleId} Redis cache and response fields like totalLogs/averageMpg, but
|
||||
getVehicleStats performs fresh queries and returns { logCount, totalFuelUnits, totalCost, averageCostPerUnit, totalDistance, averageEfficiency, unitLabels }
|
||||
with no caching (backend/src/features/fuel-logs/domain/fuel-logs.service.ts:226-320).
|
||||
- backend/src/features/documents/README.md:4,23-25 describes S3-compatible storage and a core/middleware/user-context dependency; in reality uploads go to
|
||||
the filesystem adapter (backend/src/core/storage/storage.service.ts:1-48; backend/src/core/storage/adapters/filesystem.adapter.ts:1-86) and there is no user-
|
||||
context module in backend/src/core.
|
||||
- docs/DATABASE-SCHEMA.md:109-111 asserts station caching happens in Redis, but Station data is persisted in Postgres tables such as station_cache
|
||||
(backend/src/features/stations/data/stations.repository.ts:11-115), and docs/DATABASE-SCHEMA.md:155-157 mentions “RESTRICT on delete” even though
|
||||
migrations use ON DELETE CASCADE (backend/src/features/fuel-logs/migrations/001_create_fuel_logs_table.sql:18-21; backend/src/features/maintenance/
|
||||
migrations/002_recreate_maintenance_tables.sql:21-43).
|
||||
|
||||
Questions
|
||||
|
||||
- Do we want to add the missing make test / make test-frontend automation (so the documented workflow survives), or should the documentation be rewritten to
|
||||
direct people to the existing docker compose exec ... npm test commands?
|
||||
- For the vehicles dropdown flow, should the docs be updated to call out the current TODOs, or is finishing the proxy implementation (and aligning the
|
||||
frontend/client responses) a higher priority?
|
||||
|
||||
Suggested next steps: decide on the build/test command strategy, refresh the security/platform documentation to match the Auth0 setup and real cache
|
||||
behaviour, and schedule a pass over the feature READMEs (vehicles, fuel logs, documents) so they match the implemented API contracts.
|
||||
- Canonical URLs: Frontend `https://motovaultpro.com`, Backend health `https://motovaultpro.com/api/health`.
|
||||
- Feature test coverage: Basic test structure exists for vehicles and documents features; other features have placeholder tests.
|
||||
@@ -13,20 +13,21 @@
|
||||
- Stations endpoints (`/api/stations*`)
|
||||
|
||||
### Unauthenticated Endpoints
|
||||
- None
|
||||
- Health check: `/api/health` (Traefik readiness probe, no JWT required)
|
||||
- Health check: `/health` (internal Fastify health endpoint)
|
||||
|
||||
## Data Security
|
||||
|
||||
### VIN Handling
|
||||
- VIN validation using industry-standard check digit algorithm
|
||||
- VIN decoding via integrated MVP Platform service (FastAPI) with shared database and caching
|
||||
- VIN decoding via integrated VIN decode service (TypeScript/Node.js) with shared database and caching
|
||||
- No VIN storage in logs (mask as needed in logging)
|
||||
|
||||
### Database Security
|
||||
- User data isolation via userId foreign keys
|
||||
- Soft deletes for audit trail
|
||||
- No cascading deletes to prevent data loss
|
||||
- Encrypted connections to PostgreSQL
|
||||
- Cascading deletes configured where appropriate (CASCADE constraints enforced in migrations)
|
||||
- PostgreSQL connections run within internal Docker network (unencrypted, network-isolated)
|
||||
|
||||
## Infrastructure Security
|
||||
|
||||
|
||||
@@ -21,20 +21,18 @@ backend/src/features/[name]/tests/
|
||||
|
||||
## Docker Testing Workflow
|
||||
|
||||
### Primary Test Command
|
||||
```bash
|
||||
# Run all tests (backend + frontend) in containers
|
||||
make test
|
||||
```
|
||||
### Backend Testing
|
||||
|
||||
This executes:
|
||||
- Backend: `docker compose exec mvp-backend npm test`
|
||||
- Frontend: runs Jest in a disposable Node container mounting `./frontend`
|
||||
|
||||
### Feature-Specific Testing
|
||||
```bash
|
||||
# Test single feature (complete isolation)
|
||||
# Enter backend container shell
|
||||
make shell-backend
|
||||
|
||||
# Inside container:
|
||||
|
||||
# Test all features
|
||||
npm test
|
||||
|
||||
# Test single feature (complete isolation)
|
||||
npm test -- features/vehicles
|
||||
|
||||
# Test specific test type
|
||||
@@ -44,8 +42,21 @@ npm test -- features/vehicles/tests/integration
|
||||
# Test with coverage
|
||||
npm test -- features/vehicles --coverage
|
||||
|
||||
# Frontend only
|
||||
make test-frontend
|
||||
# Watch mode
|
||||
npm run test:watch
|
||||
```
|
||||
|
||||
### Frontend Testing
|
||||
|
||||
```bash
|
||||
# From project root, run tests in frontend container
|
||||
docker compose exec mvp-frontend npm test
|
||||
|
||||
# Watch mode
|
||||
docker compose exec mvp-frontend npm run test:watch
|
||||
|
||||
# With coverage
|
||||
docker compose exec mvp-frontend npm test -- --coverage
|
||||
```
|
||||
|
||||
### Test Environment Setup
|
||||
@@ -247,12 +258,14 @@ npm test -- --detectOpenHandles
|
||||
### Pre-commit Testing
|
||||
All tests must pass before commits:
|
||||
```bash
|
||||
# Run linting and tests
|
||||
# Backend: Enter shell and run tests
|
||||
make shell-backend
|
||||
npm run lint
|
||||
npm test
|
||||
|
||||
# In Docker environment
|
||||
make test
|
||||
# Frontend: Run tests from project root
|
||||
docker compose exec mvp-frontend npm run lint
|
||||
docker compose exec mvp-frontend npm test
|
||||
```
|
||||
|
||||
### Feature Development Workflow
|
||||
|
||||
@@ -32,26 +32,26 @@ Notes:
|
||||
- Trims/engines include `id` to enable the next hop in the UI.
|
||||
|
||||
### Authentication
|
||||
- Header: `Authorization: Bearer ${API_KEY}`
|
||||
- API env: `API_KEY`
|
||||
- Auth0 JWT via `Authorization: Bearer ${JWT_TOKEN}` (required for all platform endpoints)
|
||||
- Configured in backend: `src/core/plugins/auth.plugin.ts` with JWKS validation
|
||||
|
||||
### Caching (Redis)
|
||||
- Keys: `dropdown:years`, `dropdown:makes:{year}`, `dropdown:models:{year}:{make}`, `dropdown:trims:{year}:{model}`, `dropdown:engines:{year}:{model}:{trim}`
|
||||
- Default TTL: 1 hour (3600 seconds)
|
||||
- **Configurable**: Set via `CACHE_TTL` environment variable in seconds
|
||||
- Dropdown data TTL: 6 hours (21600 seconds)
|
||||
- VIN decode cache TTL: 7 days (604800 seconds)
|
||||
- Cache key format for VIN decodes: `vin:decode:{vin}`
|
||||
- Implementation: `backend/src/features/platform/domain/platform-cache.service.ts`
|
||||
|
||||
### Seeds & Specific Examples
|
||||
Legacy FastAPI SQL seed scripts covered:
|
||||
- Base schema (`001_schema.sql`)
|
||||
- Constraints/indexes (`002_constraints_indexes.sql`)
|
||||
- Minimal Honda/Toyota scaffolding (`003_seed_minimal.sql`)
|
||||
- Chevrolet/GMC examples (`004_seed_filtered_makes.sql`)
|
||||
- Targeted sample vehicles (`005_seed_specific_vehicles.sql`)
|
||||
Contact the data team for access to these archival scripts if reseeding is required.
|
||||
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 via `backend/src/_system/migrations/run-all.ts`.
|
||||
|
||||
Reapply seeds on an existing volume:
|
||||
- `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"`
|
||||
Clear platform cache:
|
||||
- `docker compose exec -T mvp-redis sh -lc "redis-cli FLUSHALL"`
|
||||
- Or restart containers: `make rebuild`
|
||||
|
||||
## MotoVaultPro Backend (Application Service)
|
||||
|
||||
@@ -147,8 +147,9 @@ VIN/License rule
|
||||
- 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.
|
||||
- App Backend: Auth0 JWT required on all protected `/api/*` routes.
|
||||
- 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/health` is unauthenticated (Traefik readiness probe).
|
||||
|
||||
## CI Summary
|
||||
- Workflow `.github/workflows/ci.yml` builds backend/frontend/platform API.
|
||||
|
||||
Reference in New Issue
Block a user