# 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 migration files to prevent re-execution
- **Behavior**: Migration system is **idempotent at the file level** - will skip already executed files
- **SQL Statement Level**: Individual SQL statements within files may fail on re-run if they don't use `IF NOT EXISTS` clauses
- **Safety**: Safe to re-run the migration system; unsafe to manually re-run individual SQL files

## 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 metrics.

```sql
fuel_logs (
  id UUID PRIMARY KEY,
  user_id VARCHAR(255) NOT NULL,
  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 (ON DELETE CASCADE)
**Indexes**: user_id, vehicle_id, date_time, created_at

### 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
**Storage**: Persisted in PostgreSQL with station_cache table
**Cache Strategy**: Postgres-based cache with TTL management

### 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) ON DELETE CASCADE,
  type VARCHAR(100) NOT NULL,
  category VARCHAR(50),
  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 (ON DELETE CASCADE)
**Indexes**: user_id, vehicle_id, due_date, is_completed
**Constraints**: Unique(vehicle_id, type), Check(category IN valid values)

## 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 (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
- 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)
- **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}`)
- **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 cache for VIN decodes
- **Cleanup**: Application-managed based on TTL strategy

## Migration Commands

### Run All Migrations
```bash
# In container
npm run migrate:all

# Via Docker
make migrate
```
Single-feature migration is not implemented yet.

### Migration Files
- **Location**: `backend/src/features/[feature]/migrations/`
- **Format**: `001_descriptive_name.sql`
- **Order**: Lexicographic sorting (001, 002, etc.)

## Database Connection

### Development (Docker)
- **Host**: mvp-postgres (container name)
- **Port**: 5432 (internal), 5432 (external)
- **Database**: motovaultpro
- **User**: postgres
- **Password**: Loaded from secrets file `/run/secrets/postgres-password`

**Password Management**: All database passwords are managed via Docker secrets, mounted from host files:
- Application DB: `./secrets/app/postgres-password.txt`

### 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)
