Improved docs for future AI
This commit is contained in:
229
docs/database-schema.md
Normal file
229
docs/database-schema.md
Normal file
@@ -0,0 +1,229 @@
|
||||
# Database Schema Overview
|
||||
|
||||
Complete database schema for MotoVaultPro Modified Feature Capsule architecture.
|
||||
|
||||
## Migration System
|
||||
|
||||
### Migration Order (Dependencies)
|
||||
1. **vehicles** - Primary entity, no dependencies
|
||||
2. **fuel-logs** - Depends on vehicles (vehicle_id FK)
|
||||
3. **maintenance** - Depends on vehicles (vehicle_id FK)
|
||||
4. **stations** - Independent feature
|
||||
|
||||
### Migration Tracking
|
||||
- **Table**: `_migrations`
|
||||
- **Purpose**: Tracks executed migrations per feature
|
||||
- **Location**: Created by `backend/src/_system/migrations/run-all.ts`
|
||||
|
||||
## Core Tables
|
||||
|
||||
### vehicles
|
||||
Primary entity for all vehicle data.
|
||||
|
||||
```sql
|
||||
vehicles (
|
||||
id UUID PRIMARY KEY,
|
||||
user_id VARCHAR(255) NOT NULL,
|
||||
vin VARCHAR(17) NOT NULL,
|
||||
make VARCHAR(100),
|
||||
model VARCHAR(100),
|
||||
year INTEGER,
|
||||
nickname VARCHAR(100),
|
||||
color VARCHAR(50),
|
||||
license_plate VARCHAR(20),
|
||||
odometer_reading INTEGER DEFAULT 0,
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
deleted_at TIMESTAMP WITH TIME ZONE, -- Soft delete
|
||||
created_at TIMESTAMP WITH TIME ZONE,
|
||||
updated_at TIMESTAMP WITH TIME ZONE,
|
||||
|
||||
CONSTRAINT unique_user_vin UNIQUE(user_id, vin)
|
||||
)
|
||||
```
|
||||
|
||||
**Indexes**: user_id, vin, is_active, created_at
|
||||
**Triggers**: auto-update updated_at column
|
||||
|
||||
### vin_cache
|
||||
Caches NHTSA vPIC API responses for 30 days.
|
||||
|
||||
```sql
|
||||
vin_cache (
|
||||
vin VARCHAR(17) PRIMARY KEY,
|
||||
make VARCHAR(100),
|
||||
model VARCHAR(100),
|
||||
year INTEGER,
|
||||
engine_type VARCHAR(100),
|
||||
body_type VARCHAR(100),
|
||||
raw_data JSONB,
|
||||
cached_at TIMESTAMP WITH TIME ZONE
|
||||
)
|
||||
```
|
||||
|
||||
**Indexes**: cached_at (for cleanup)
|
||||
**TTL**: 30 days (application-managed)
|
||||
|
||||
### fuel_logs
|
||||
Tracks fuel purchases and efficiency.
|
||||
|
||||
```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),
|
||||
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
|
||||
|
||||
### stations
|
||||
Gas station locations and details.
|
||||
|
||||
```sql
|
||||
stations (
|
||||
id UUID PRIMARY KEY,
|
||||
google_place_id VARCHAR(255) UNIQUE,
|
||||
name VARCHAR(200) NOT NULL,
|
||||
address TEXT,
|
||||
latitude DECIMAL(10,8),
|
||||
longitude DECIMAL(11,8),
|
||||
phone VARCHAR(20),
|
||||
website VARCHAR(255),
|
||||
created_at TIMESTAMP WITH TIME ZONE,
|
||||
updated_at TIMESTAMP WITH TIME ZONE
|
||||
)
|
||||
```
|
||||
|
||||
**External Source**: Google Maps Places API
|
||||
**Cache Strategy**: 1 hour TTL via Redis
|
||||
|
||||
### maintenance
|
||||
Vehicle maintenance records and scheduling.
|
||||
|
||||
```sql
|
||||
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
|
||||
description TEXT,
|
||||
due_date DATE,
|
||||
due_mileage INTEGER,
|
||||
completed_date DATE,
|
||||
completed_mileage INTEGER,
|
||||
cost DECIMAL(8,2),
|
||||
service_location VARCHAR(200),
|
||||
notes TEXT,
|
||||
is_completed BOOLEAN DEFAULT false,
|
||||
created_at TIMESTAMP WITH TIME ZONE,
|
||||
updated_at TIMESTAMP WITH TIME ZONE
|
||||
)
|
||||
```
|
||||
|
||||
**Foreign Keys**: vehicle_id → vehicles.id
|
||||
**Indexes**: user_id, vehicle_id, due_date, is_completed
|
||||
|
||||
## Relationships
|
||||
|
||||
```
|
||||
vehicles (1) ──── (many) fuel_logs
|
||||
│
|
||||
└──── (many) maintenance
|
||||
|
||||
stations (independent - no FK relationships)
|
||||
```
|
||||
|
||||
## Data Constraints
|
||||
|
||||
### User Data Isolation
|
||||
- All user data tables include `user_id` column
|
||||
- Application enforces user-scoped queries
|
||||
- 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
|
||||
|
||||
### VIN Validation
|
||||
- Exactly 17 characters
|
||||
- Cannot contain letters I, O, or Q
|
||||
- Application-level checksum validation
|
||||
- Unique per user (same VIN can exist for different users)
|
||||
|
||||
## Caching Strategy
|
||||
|
||||
### Application-Level Caching (Redis)
|
||||
- **VIN decodes**: 30 days (key: `vpic:vin:{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}`)
|
||||
|
||||
### Database-Level Caching
|
||||
- **vin_cache table**: Persistent 30-day cache for vPIC API results
|
||||
- **Cleanup**: Application-managed, removes entries older than 30 days
|
||||
|
||||
## Migration Commands
|
||||
|
||||
### Run All Migrations
|
||||
```bash
|
||||
# In container
|
||||
npm run migrate:all
|
||||
|
||||
# Via Docker
|
||||
make migrate
|
||||
```
|
||||
|
||||
### Run Single Feature
|
||||
```bash
|
||||
# In container
|
||||
npm run migrate:feature vehicles
|
||||
|
||||
# Individual features
|
||||
npm run migrate:feature fuel-logs
|
||||
npm run migrate:feature maintenance
|
||||
npm run migrate:feature stations
|
||||
```
|
||||
|
||||
### Migration Files
|
||||
- **Location**: `backend/src/features/[feature]/migrations/`
|
||||
- **Format**: `001_descriptive_name.sql`
|
||||
- **Order**: Lexicographic sorting (001, 002, etc.)
|
||||
|
||||
## Database Connection
|
||||
|
||||
### Development (Docker)
|
||||
- **Host**: postgres (container name)
|
||||
- **Port**: 5432
|
||||
- **Database**: motovaultpro
|
||||
- **User**: postgres
|
||||
- **Password**: localdev123
|
||||
|
||||
### Connection Pool
|
||||
- **Implementation**: pg (node-postgres)
|
||||
- **Pool Size**: Default (10 connections)
|
||||
- **Idle Timeout**: 30 seconds
|
||||
- **Location**: `backend/src/core/config/database.ts`
|
||||
|
||||
## Backup Strategy
|
||||
|
||||
### Development
|
||||
- **Docker Volume**: `postgres_data`
|
||||
- **Persistence**: Survives container restarts
|
||||
- **Reset**: `make clean` removes all data
|
||||
|
||||
### Production Considerations
|
||||
- Regular pg_dump backups
|
||||
- Point-in-time recovery
|
||||
- Read replicas for analytics
|
||||
- Connection pooling (PgBouncer)
|
||||
Reference in New Issue
Block a user