- Express + EJS server-rendered app - Supabase PostgreSQL database - Auth: username/password with bcrypt - Dashboard with business stats - Load CRUD with filters - WhatsApp message parser - Payment tracking - Shipper & vehicle management - Reports (monthly, top shippers, routes) - Government-app aesthetic (tricolor theme) - Dark mode support - Docker + Coolify deployment ready - Seed data from existing business ledger (88 loads, 41 shippers, 70 vehicles)
122 lines
4.2 KiB
JavaScript
122 lines
4.2 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* FreightDesk Seed Script
|
|
* Reads supabase/seed_data.json and inserts into Supabase
|
|
* Also runs the schema migrations
|
|
*/
|
|
|
|
require('dotenv').config();
|
|
const { createClient } = require('@supabase/supabase-js');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const supabaseUrl = process.env.SUPABASE_URL;
|
|
const supabaseKey = process.env.SUPABASE_SERVICE_KEY || process.env.SUPABASE_KEY;
|
|
|
|
if (!supabaseUrl || !supabaseKey) {
|
|
console.error('Missing SUPABASE_URL or SUPABASE_KEY in .env');
|
|
process.exit(1);
|
|
}
|
|
|
|
const supabase = createClient(supabaseUrl, supabaseKey);
|
|
|
|
async function runMigrations() {
|
|
const migrationsDir = path.join(__dirname, '..', 'supabase', 'migrations');
|
|
const files = fs.readdirSync(migrationsDir).filter(f => f.endsWith('.sql')).sort();
|
|
|
|
for (const file of files) {
|
|
if (file.includes('seed')) continue; // Skip seed placeholder
|
|
console.log(`Running migration: ${file}`);
|
|
const sql = fs.readFileSync(path.join(migrationsDir, file), 'utf8');
|
|
|
|
// Split by semicolons and execute each statement
|
|
const statements = sql.split(';').filter(s => s.trim() && !s.trim().startsWith('--'));
|
|
for (const stmt of statements) {
|
|
if (stmt.trim()) {
|
|
const { error } = await supabase.rpc('exec_sql', { sql: stmt.trim() });
|
|
if (error && !error.message.includes('already exists')) {
|
|
console.warn(` Warning: ${error.message}`);
|
|
}
|
|
}
|
|
}
|
|
console.log(` Done.`);
|
|
}
|
|
}
|
|
|
|
async function seedData() {
|
|
const seedFile = path.join(__dirname, '..', 'supabase', 'seed_data.json');
|
|
if (!fs.existsSync(seedFile)) {
|
|
console.log('No seed_data.json found, skipping seed.');
|
|
return;
|
|
}
|
|
|
|
const seed = JSON.parse(fs.readFileSync(seedFile, 'utf-8'));
|
|
|
|
// Insert shippers
|
|
if (seed.shippers && seed.shippers.length > 0) {
|
|
console.log(`Inserting ${seed.shippers.length} shippers...`);
|
|
const { error } = await supabase.from('shippers').upsert(seed.shippers, { onConflict: 'id' });
|
|
if (error) console.error('Shippers error:', error.message);
|
|
else console.log(' Done.');
|
|
}
|
|
|
|
// Insert vehicles
|
|
if (seed.vehicles && seed.vehicles.length > 0) {
|
|
console.log(`Inserting ${seed.vehicles.length} vehicles...`);
|
|
const { error } = await supabase.from('vehicles').upsert(seed.vehicles, { onConflict: 'id' });
|
|
if (error) console.error('Vehicles error:', error.message);
|
|
else console.log(' Done.');
|
|
}
|
|
|
|
// Insert loads in batches
|
|
if (seed.loads && seed.loads.length > 0) {
|
|
console.log(`Inserting ${seed.loads.length} loads...`);
|
|
const batchSize = 20;
|
|
for (let i = 0; i < seed.loads.length; i += batchSize) {
|
|
const batch = seed.loads.slice(i, i + batchSize);
|
|
const { error } = await supabase.from('loads').upsert(batch, { onConflict: 'id' });
|
|
if (error) console.error(`Loads batch error (${i}-${i + batchSize}):`, error.message);
|
|
else console.log(` Batch ${Math.floor(i / batchSize) + 1} done.`);
|
|
}
|
|
}
|
|
|
|
// Update shipper totals
|
|
console.log('Updating shipper totals...');
|
|
for (const shipper of seed.shippers) {
|
|
const shipperLoads = seed.loads.filter(l => l.shipper_id === shipper.id);
|
|
const totals = shipperLoads.reduce((acc, l) => ({
|
|
freight: acc.freight + (l.freight_charged || 0),
|
|
commission: acc.commission + (l.commission || 0),
|
|
pending: acc.pending + (l.pending_from_shipper || 0),
|
|
}), { freight: 0, commission: 0, pending: 0 });
|
|
|
|
await supabase.from('shippers').update({
|
|
total_freight: totals.freight,
|
|
total_commission: totals.commission,
|
|
pending_amount: totals.pending,
|
|
}).eq('id', shipper.id);
|
|
}
|
|
console.log(' Done.');
|
|
}
|
|
|
|
async function main() {
|
|
console.log('=== FreightDesk Seeder ===\n');
|
|
|
|
try {
|
|
console.log('Step 1: Running migrations...');
|
|
// Note: For actual migration execution, use Supabase CLI or Dashboard SQL editor
|
|
// This is a simplified approach - run migrations manually in Supabase SQL Editor
|
|
console.log(' Please run the SQL migrations in Supabase SQL Editor first:');
|
|
console.log(' - supabase/migrations/001_initial_schema.sql\n');
|
|
|
|
console.log('Step 2: Seeding data...');
|
|
await seedData();
|
|
|
|
console.log('\n=== Seed complete! ===');
|
|
} catch (err) {
|
|
console.error('Fatal error:', err);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main();
|