Files
motovaultpro/docs/database-schema.md
Eric Gullickson e22d643ae3 Security Fixes
2025-08-24 14:39:50 -05:00

5.5 KiB

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: Created by backend/src/_system/migrations/run-all.ts (not yet used for skipping executed files)
  • Note: Some SQL files use IF NOT EXISTS. Re-running all migrations may fail on indexes without IF NOT EXISTS.

Core Tables

vehicles

Primary entity for all vehicle data.

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.

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.

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.

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.

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

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