MVP Build

This commit is contained in:
Eric Gullickson
2025-08-09 12:47:15 -05:00
parent 2e8816df7f
commit 8f5117a4e2
92 changed files with 5910 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
/**
* @ai-summary Orchestrates all feature migrations in dependency order
*/
import { Pool } from 'pg';
import { readFileSync, readdirSync } from 'fs';
import { join } from 'path';
import { env } from '../../core/config/environment';
const pool = new Pool({
host: env.DB_HOST,
port: env.DB_PORT,
database: env.DB_NAME,
user: env.DB_USER,
password: env.DB_PASSWORD,
});
// Define migration order based on dependencies
const MIGRATION_ORDER = [
'vehicles', // Primary entity, no dependencies
'fuel-logs', // Depends on vehicles
'maintenance', // Depends on vehicles
'stations', // Independent
];
async function runFeatureMigrations(featureName: string) {
const migrationDir = join(__dirname, '../../features', featureName, 'migrations');
try {
const files = readdirSync(migrationDir)
.filter(f => f.endsWith('.sql'))
.sort();
for (const file of files) {
const sql = readFileSync(join(migrationDir, file), 'utf-8');
console.log(`Running migration: ${featureName}/${file}`);
await pool.query(sql);
console.log(`✅ Completed: ${featureName}/${file}`);
}
} catch (error) {
console.error(`❌ Failed migration for ${featureName}:`, error);
throw error;
}
}
async function main() {
try {
console.log('Starting migration orchestration...');
// Create migrations tracking table
await pool.query(`
CREATE TABLE IF NOT EXISTS _migrations (
id SERIAL PRIMARY KEY,
feature VARCHAR(100) NOT NULL,
file VARCHAR(255) NOT NULL,
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(feature, file)
);
`);
// Run migrations in order
for (const feature of MIGRATION_ORDER) {
console.log(`\nMigrating feature: ${feature}`);
await runFeatureMigrations(feature);
}
console.log('\n✅ All migrations completed successfully');
} catch (error) {
console.error('Migration failed:', error);
process.exit(1);
} finally {
await pool.end();
}
}
if (require.main === module) {
main();
}

View File

@@ -0,0 +1,60 @@
/**
* @ai-summary Generates combined schema from all feature migrations
*/
import { readFileSync, readdirSync, writeFileSync } from 'fs';
import { join } from 'path';
const FEATURES_DIR = join(__dirname, '../../features');
const OUTPUT_FILE = join(__dirname, 'combined-schema.sql');
function collectFeatureMigrations(): string[] {
const schemas: string[] = [];
const features = readdirSync(FEATURES_DIR);
for (const feature of features) {
const migrationDir = join(FEATURES_DIR, feature, 'migrations');
try {
const files = readdirSync(migrationDir)
.filter(f => f.endsWith('.sql'))
.sort();
schemas.push(`-- =====================================`);
schemas.push(`-- Feature: ${feature}`);
schemas.push(`-- =====================================\n`);
for (const file of files) {
const content = readFileSync(join(migrationDir, file), 'utf-8');
schemas.push(`-- File: ${file}`);
schemas.push(content);
schemas.push('');
}
} catch (error) {
console.warn(`No migrations found for ${feature}`);
}
}
return schemas;
}
function main() {
console.log('Generating combined schema...');
const header = `-- MotoVaultPro Combined Schema
-- Generated: ${new Date().toISOString()}
-- This file is auto-generated from feature migrations
-- DO NOT EDIT DIRECTLY
`;
const schemas = collectFeatureMigrations();
const combined = header + schemas.join('\n');
writeFileSync(OUTPUT_FILE, combined);
console.log(`✅ Schema generated: ${OUTPUT_FILE}`);
}
if (require.main === module) {
main();
}