chore: Update Documentation
All checks were successful
Deploy to Staging / Build Images (push) Successful in 2m19s
Deploy to Staging / Deploy to Staging (push) Successful in 27s
Deploy to Staging / Verify Staging (push) Successful in 5s
Deploy to Staging / Notify Staging Ready (push) Successful in 5s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
Mirror Base Images / Mirror Base Images (push) Successful in 29s
All checks were successful
Deploy to Staging / Build Images (push) Successful in 2m19s
Deploy to Staging / Deploy to Staging (push) Successful in 27s
Deploy to Staging / Verify Staging (push) Successful in 5s
Deploy to Staging / Notify Staging Ready (push) Successful in 5s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
Mirror Base Images / Mirror Base Images (push) Successful in 29s
This commit is contained in:
@@ -1,23 +1,133 @@
|
||||
# Database Schema Overview
|
||||
|
||||
Complete database schema for MotoVaultPro Modified Feature Capsule architecture.
|
||||
Complete database schema for MotoVaultPro 5-container architecture with 15 feature capsules.
|
||||
|
||||
## 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
|
||||
1. **admin** - Admin users and audit logs, no dependencies
|
||||
2. **user-profile** - User profiles, no dependencies
|
||||
3. **user-preferences** - User preferences, depends on user-profile
|
||||
4. **terms-agreement** - Terms acceptance audit, no dependencies
|
||||
5. **platform** - Vehicle lookup data (engines, transmissions, vehicle_options)
|
||||
6. **vehicles** - Primary vehicle entity, no dependencies
|
||||
7. **fuel-logs** - Depends on vehicles (vehicle_id FK)
|
||||
8. **maintenance** - Depends on vehicles (vehicle_id FK)
|
||||
9. **stations** - Independent feature (includes community_stations)
|
||||
10. **documents** - Depends on vehicles (vehicle_id FK)
|
||||
11. **notifications** - Email templates and logs, depends on maintenance/documents
|
||||
12. **backup** - Backup schedules, history, settings
|
||||
|
||||
Features without migrations: auth, onboarding, user-export
|
||||
|
||||
### 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
|
||||
## Admin Tables
|
||||
|
||||
### admin_users
|
||||
Admin role-based access control.
|
||||
|
||||
```sql
|
||||
admin_users (
|
||||
auth0_sub VARCHAR(255) PRIMARY KEY,
|
||||
email VARCHAR(255) NOT NULL UNIQUE,
|
||||
role VARCHAR(50) NOT NULL DEFAULT 'admin',
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
created_by VARCHAR(255) NOT NULL,
|
||||
revoked_at TIMESTAMP WITH TIME ZONE,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
```
|
||||
|
||||
**Indexes**: email, created_at, revoked_at
|
||||
**Triggers**: auto-update updated_at
|
||||
|
||||
### admin_audit_logs
|
||||
Audit trail for admin actions.
|
||||
|
||||
```sql
|
||||
admin_audit_logs (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
actor_admin_id VARCHAR(255) NOT NULL,
|
||||
target_admin_id VARCHAR(255),
|
||||
action VARCHAR(100) NOT NULL,
|
||||
resource_type VARCHAR(100),
|
||||
resource_id VARCHAR(255),
|
||||
context JSONB,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
```
|
||||
|
||||
**Indexes**: actor_admin_id, target_admin_id, action, created_at
|
||||
|
||||
## User Tables
|
||||
|
||||
### user_profiles
|
||||
User profile information with Auth0 integration.
|
||||
|
||||
```sql
|
||||
user_profiles (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
auth0_sub VARCHAR(255) NOT NULL UNIQUE,
|
||||
email VARCHAR(255) NOT NULL,
|
||||
display_name VARCHAR(100),
|
||||
notification_email VARCHAR(255),
|
||||
email_verified BOOLEAN DEFAULT false,
|
||||
onboarding_completed_at TIMESTAMP WITH TIME ZONE,
|
||||
subscription_tier VARCHAR(50) DEFAULT 'free',
|
||||
deactivated_at TIMESTAMP WITH TIME ZONE,
|
||||
deletion_requested_at TIMESTAMP WITH TIME ZONE,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
```
|
||||
|
||||
**Indexes**: auth0_sub
|
||||
**Triggers**: auto-update updated_at
|
||||
|
||||
### user_preferences
|
||||
User preference settings.
|
||||
|
||||
```sql
|
||||
user_preferences (
|
||||
id UUID PRIMARY KEY,
|
||||
user_id VARCHAR(255) NOT NULL UNIQUE,
|
||||
unit_system VARCHAR(20) DEFAULT 'imperial',
|
||||
currency_code VARCHAR(3) DEFAULT 'USD',
|
||||
time_zone VARCHAR(100) DEFAULT 'America/New_York',
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
```
|
||||
|
||||
**Indexes**: user_id
|
||||
|
||||
### terms_agreements
|
||||
Legal audit trail for T&C acceptance.
|
||||
|
||||
```sql
|
||||
terms_agreements (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id VARCHAR(255) NOT NULL,
|
||||
agreed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ip_address VARCHAR(45) NOT NULL,
|
||||
user_agent TEXT NOT NULL,
|
||||
terms_version VARCHAR(50) NOT NULL,
|
||||
terms_url VARCHAR(255) NOT NULL,
|
||||
terms_content_hash VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
```
|
||||
|
||||
**Indexes**: user_id
|
||||
**Invariant**: One record per user, created at signup
|
||||
|
||||
## Vehicle Tables
|
||||
|
||||
### vehicles
|
||||
Primary entity for all vehicle data.
|
||||
@@ -26,44 +136,29 @@ Primary entity for all vehicle data.
|
||||
vehicles (
|
||||
id UUID PRIMARY KEY,
|
||||
user_id VARCHAR(255) NOT NULL,
|
||||
vin VARCHAR(17) NOT NULL,
|
||||
vin VARCHAR(17),
|
||||
make VARCHAR(100),
|
||||
model VARCHAR(100),
|
||||
model VARCHAR(100),
|
||||
year INTEGER,
|
||||
trim VARCHAR(100),
|
||||
engine VARCHAR(100),
|
||||
transmission VARCHAR(100),
|
||||
nickname VARCHAR(100),
|
||||
color VARCHAR(50),
|
||||
license_plate VARCHAR(20),
|
||||
odometer_reading INTEGER DEFAULT 0,
|
||||
image_bucket VARCHAR(128),
|
||||
image_key VARCHAR(512),
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
deleted_at TIMESTAMP WITH TIME ZONE, -- Soft delete
|
||||
deleted_at TIMESTAMP WITH TIME ZONE,
|
||||
created_at TIMESTAMP WITH TIME ZONE,
|
||||
updated_at TIMESTAMP WITH TIME ZONE,
|
||||
|
||||
CONSTRAINT unique_user_vin UNIQUE(user_id, vin)
|
||||
updated_at TIMESTAMP WITH TIME ZONE
|
||||
)
|
||||
```
|
||||
|
||||
**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)
|
||||
**Triggers**: auto-update updated_at
|
||||
**Constraints**: VIN nullable (license plate can be used instead)
|
||||
|
||||
### fuel_logs
|
||||
Tracks fuel purchases and efficiency metrics.
|
||||
@@ -74,8 +169,8 @@ fuel_logs (
|
||||
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),
|
||||
odometer NUMERIC,
|
||||
trip_distance NUMERIC,
|
||||
fuel_type VARCHAR(50),
|
||||
fuel_grade VARCHAR(50),
|
||||
fuel_units DECIMAL(10,3) NOT NULL,
|
||||
@@ -88,11 +183,92 @@ fuel_logs (
|
||||
)
|
||||
```
|
||||
|
||||
**Foreign Keys**: vehicle_id → vehicles.id (ON DELETE CASCADE)
|
||||
**Foreign Keys**: vehicle_id -> vehicles.id (ON DELETE CASCADE)
|
||||
**Indexes**: user_id, vehicle_id, date_time, created_at
|
||||
|
||||
### maintenance_logs
|
||||
Completed maintenance records.
|
||||
|
||||
```sql
|
||||
maintenance_logs (
|
||||
id UUID PRIMARY KEY,
|
||||
user_id VARCHAR(255) NOT NULL,
|
||||
vehicle_id UUID NOT NULL REFERENCES vehicles(id) ON DELETE CASCADE,
|
||||
category VARCHAR(50) NOT NULL,
|
||||
subtypes TEXT[],
|
||||
service_date DATE NOT NULL,
|
||||
odometer INTEGER,
|
||||
cost DECIMAL(10,2),
|
||||
shop_name VARCHAR(200),
|
||||
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, service_date
|
||||
|
||||
### maintenance_schedules
|
||||
Recurring maintenance schedules with notification settings.
|
||||
|
||||
```sql
|
||||
maintenance_schedules (
|
||||
id UUID PRIMARY KEY,
|
||||
user_id VARCHAR(255) NOT NULL,
|
||||
vehicle_id UUID NOT NULL REFERENCES vehicles(id) ON DELETE CASCADE,
|
||||
category VARCHAR(50) NOT NULL,
|
||||
subtypes TEXT[],
|
||||
interval_months INTEGER,
|
||||
interval_miles INTEGER,
|
||||
last_service_date DATE,
|
||||
last_service_mileage INTEGER,
|
||||
next_due_date DATE,
|
||||
next_due_mileage INTEGER,
|
||||
email_notifications BOOLEAN DEFAULT false,
|
||||
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, next_due_date
|
||||
|
||||
### documents
|
||||
Vehicle document storage (insurance, registration, etc.).
|
||||
|
||||
```sql
|
||||
documents (
|
||||
id UUID PRIMARY KEY,
|
||||
user_id VARCHAR(255) NOT NULL,
|
||||
vehicle_id UUID NOT NULL REFERENCES vehicles(id) ON DELETE CASCADE,
|
||||
document_type VARCHAR(32) NOT NULL CHECK (document_type IN ('insurance','registration','manual')),
|
||||
title VARCHAR(200) NOT NULL,
|
||||
notes TEXT,
|
||||
details JSONB,
|
||||
storage_bucket VARCHAR(128),
|
||||
storage_key VARCHAR(512),
|
||||
file_name VARCHAR(255),
|
||||
content_type VARCHAR(128),
|
||||
file_size BIGINT,
|
||||
file_hash VARCHAR(128),
|
||||
issued_date DATE,
|
||||
expiration_date DATE,
|
||||
email_notifications BOOLEAN DEFAULT false,
|
||||
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW(),
|
||||
deleted_at TIMESTAMP WITHOUT TIME ZONE
|
||||
)
|
||||
```
|
||||
|
||||
**Foreign Keys**: vehicle_id -> vehicles.id (ON DELETE CASCADE)
|
||||
**Indexes**: user_id, vehicle_id, document_type, expiration_date
|
||||
|
||||
## Station Tables
|
||||
|
||||
### stations
|
||||
Gas station locations and details.
|
||||
Gas station locations from Google Maps.
|
||||
|
||||
```sql
|
||||
stations (
|
||||
@@ -104,51 +280,225 @@ stations (
|
||||
longitude DECIMAL(11,8),
|
||||
phone VARCHAR(20),
|
||||
website VARCHAR(255),
|
||||
has_93_octane BOOLEAN,
|
||||
photo_reference VARCHAR(500),
|
||||
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.
|
||||
### community_stations
|
||||
User-reported station information.
|
||||
|
||||
```sql
|
||||
maintenance (
|
||||
community_stations (
|
||||
id UUID PRIMARY KEY,
|
||||
station_id UUID REFERENCES stations(id),
|
||||
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
|
||||
has_93_octane BOOLEAN,
|
||||
reported_at TIMESTAMP WITH TIME ZONE,
|
||||
removed_at TIMESTAMP WITH TIME ZONE,
|
||||
removal_reason VARCHAR(100)
|
||||
)
|
||||
```
|
||||
|
||||
**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)
|
||||
**Foreign Keys**: station_id -> stations.id
|
||||
**Purpose**: Track user reports of 93 octane availability
|
||||
|
||||
## Platform Tables
|
||||
|
||||
### engines
|
||||
Engine specifications for vehicle catalog.
|
||||
|
||||
```sql
|
||||
engines (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
displacement VARCHAR(50),
|
||||
configuration VARCHAR(50),
|
||||
horsepower VARCHAR(100),
|
||||
torque VARCHAR(100),
|
||||
fuel_type VARCHAR(100),
|
||||
fuel_system VARCHAR(255),
|
||||
aspiration VARCHAR(100),
|
||||
specs_json JSONB,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
```
|
||||
|
||||
**Unique Index**: LOWER(name) - case-insensitive uniqueness
|
||||
**Indexes**: displacement, configuration
|
||||
|
||||
### transmissions
|
||||
Transmission specifications for vehicle catalog.
|
||||
|
||||
```sql
|
||||
transmissions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
type VARCHAR(100) NOT NULL,
|
||||
speeds VARCHAR(50),
|
||||
drive_type VARCHAR(100),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
```
|
||||
|
||||
**Unique Index**: LOWER(type) - case-insensitive uniqueness
|
||||
|
||||
### vehicle_options
|
||||
Denormalized vehicle lookup data for dropdown cascades.
|
||||
|
||||
```sql
|
||||
vehicle_options (
|
||||
id SERIAL PRIMARY KEY,
|
||||
year INTEGER NOT NULL,
|
||||
make VARCHAR(100) NOT NULL,
|
||||
model VARCHAR(255) NOT NULL,
|
||||
trim VARCHAR(255) NOT NULL,
|
||||
engine_id INTEGER REFERENCES engines(id) ON DELETE SET NULL,
|
||||
transmission_id INTEGER REFERENCES transmissions(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
```
|
||||
|
||||
**Foreign Keys**: engine_id -> engines.id, transmission_id -> transmissions.id
|
||||
**Unique Index**: (year, make, model, trim, engine_id, transmission_id)
|
||||
**Indexes**: Optimized for cascade queries (year, year+make, year+make+model, etc.)
|
||||
|
||||
## Notification Tables
|
||||
|
||||
### email_templates
|
||||
Admin-editable email templates.
|
||||
|
||||
```sql
|
||||
email_templates (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
template_key VARCHAR(50) NOT NULL UNIQUE CHECK (template_key IN (
|
||||
'maintenance_due_soon', 'maintenance_overdue',
|
||||
'document_expiring', 'document_expired'
|
||||
)),
|
||||
name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
subject VARCHAR(255) NOT NULL,
|
||||
body TEXT NOT NULL,
|
||||
variables JSONB DEFAULT '[]'::jsonb,
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
```
|
||||
|
||||
**Seeded Templates**: 4 predefined templates for maintenance and document notifications
|
||||
|
||||
### notification_logs
|
||||
Track sent email notifications.
|
||||
|
||||
```sql
|
||||
notification_logs (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id VARCHAR(255) NOT NULL,
|
||||
notification_type VARCHAR(20) NOT NULL CHECK (notification_type IN ('email', 'toast')),
|
||||
template_key VARCHAR(50) NOT NULL,
|
||||
recipient_email VARCHAR(255),
|
||||
subject VARCHAR(255),
|
||||
reference_type VARCHAR(50),
|
||||
reference_id UUID,
|
||||
status VARCHAR(20) DEFAULT 'sent' CHECK (status IN ('pending', 'sent', 'failed')),
|
||||
error_message TEXT,
|
||||
sent_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
```
|
||||
|
||||
**Indexes**: user_id, reference_type+reference_id, sent_at
|
||||
|
||||
## Backup Tables
|
||||
|
||||
### backup_schedules
|
||||
Scheduled backup configurations.
|
||||
|
||||
```sql
|
||||
backup_schedules (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(100) NOT NULL,
|
||||
frequency VARCHAR(20) NOT NULL CHECK (frequency IN ('hourly', 'daily', 'weekly', 'monthly')),
|
||||
cron_expression VARCHAR(50) NOT NULL,
|
||||
retention_count INTEGER NOT NULL DEFAULT 7,
|
||||
is_enabled BOOLEAN DEFAULT true,
|
||||
last_run_at TIMESTAMP WITH TIME ZONE,
|
||||
next_run_at TIMESTAMP WITH TIME ZONE,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
)
|
||||
```
|
||||
|
||||
**Indexes**: is_enabled, next_run_at
|
||||
|
||||
### backup_history
|
||||
Record of all backup operations.
|
||||
|
||||
```sql
|
||||
backup_history (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
schedule_id UUID REFERENCES backup_schedules(id) ON DELETE SET NULL,
|
||||
backup_type VARCHAR(20) NOT NULL CHECK (backup_type IN ('scheduled', 'manual')),
|
||||
filename VARCHAR(255) NOT NULL,
|
||||
file_path VARCHAR(500) NOT NULL,
|
||||
file_size_bytes BIGINT NOT NULL,
|
||||
database_tables_count INTEGER,
|
||||
documents_count INTEGER,
|
||||
status VARCHAR(20) NOT NULL CHECK (status IN ('in_progress', 'completed', 'failed')),
|
||||
error_message TEXT,
|
||||
started_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
completed_at TIMESTAMP WITH TIME ZONE,
|
||||
created_by VARCHAR(255),
|
||||
metadata JSONB DEFAULT '{}'
|
||||
)
|
||||
```
|
||||
|
||||
**Foreign Keys**: schedule_id -> backup_schedules.id (ON DELETE SET NULL)
|
||||
**Indexes**: status, started_at, schedule_id
|
||||
|
||||
### backup_settings
|
||||
Global backup configuration.
|
||||
|
||||
```sql
|
||||
backup_settings (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
setting_key VARCHAR(50) UNIQUE NOT NULL,
|
||||
setting_value TEXT NOT NULL,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
)
|
||||
```
|
||||
|
||||
**Default Settings**: email_on_success, email_on_failure, admin_email, max_backup_size_mb, compression_enabled
|
||||
|
||||
## Relationships
|
||||
|
||||
```
|
||||
vehicles (1) ──── (many) fuel_logs
|
||||
│
|
||||
└──── (many) maintenance
|
||||
user_profiles (1) ---- (1) user_preferences
|
||||
|
|
||||
+---- (1) terms_agreements
|
||||
|
||||
stations (independent - no FK relationships)
|
||||
vehicles (1) ---- (many) fuel_logs
|
||||
|
|
||||
+---- (many) maintenance_logs
|
||||
|
|
||||
+---- (many) maintenance_schedules
|
||||
|
|
||||
+---- (many) documents
|
||||
|
||||
stations (1) ---- (many) community_stations
|
||||
|
||||
vehicle_options (many) ---- (1) engines
|
||||
|
|
||||
+---- (1) transmissions
|
||||
|
||||
backup_schedules (1) ---- (many) backup_history
|
||||
```
|
||||
|
||||
## Data Constraints
|
||||
@@ -159,16 +509,16 @@ stations (independent - no FK relationships)
|
||||
- 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
|
||||
- fuel_logs, maintenance_logs, maintenance_schedules, documents -> vehicles.id (ON DELETE CASCADE)
|
||||
- community_stations -> stations.id
|
||||
- vehicle_options -> engines.id, transmissions.id (ON DELETE SET NULL)
|
||||
- backup_history -> backup_schedules.id (ON DELETE SET NULL)
|
||||
|
||||
### VIN Validation
|
||||
- Exactly 17 characters
|
||||
- 17 characters when provided (now optional)
|
||||
- Cannot contain letters I, O, or Q
|
||||
- Application-level checksum validation
|
||||
- Unique per user (same VIN can exist for different users)
|
||||
- Either VIN or license_plate required
|
||||
|
||||
## Caching Strategy
|
||||
|
||||
@@ -177,13 +527,8 @@ stations (independent - no FK relationships)
|
||||
- **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
|
||||
@@ -194,7 +539,6 @@ npm run migrate:all
|
||||
# Via Docker
|
||||
make migrate
|
||||
```
|
||||
Single-feature migration is not implemented yet.
|
||||
|
||||
### Migration Files
|
||||
- **Location**: `backend/src/features/[feature]/migrations/`
|
||||
@@ -205,29 +549,13 @@ Single-feature migration is not implemented yet.
|
||||
|
||||
### Development (Docker)
|
||||
- **Host**: mvp-postgres (container name)
|
||||
- **Port**: 5432 (internal), 5432 (external)
|
||||
- **Port**: 5432
|
||||
- **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)
|
||||
|
||||
Reference in New Issue
Block a user