bharath/webapp/seed.js
iamcoolvivek007 e9025a71eb v2.0: Major improvements - Security, Code Quality, UI/UX, Features
Security:
- Add CSRF protection on all forms
- Fix session config (resave:false, saveUninitialized:false)
- Secure cookie settings for production
- Input sanitization middleware
- Request logging middleware
- Security headers via Helmet

Code Quality:
- Async error handling on ALL route handlers
- Proper HTTP status codes (400, 401, 403, 404, 409, 500)
- Input validation on all forms (server-side)
- Username validation (3-30 chars, alphanumeric+underscore)
- Password min length increased to 6
- Generic error messages (no info leakage)
- Graceful shutdown on SIGTERM

UI/UX:
- Dark mode toggle with persistence
- Toast notifications for success/error
- Loading states on form submit
- Improved CSS with CSS variables
- Better desktop responsive design
- New 403 Forbidden page
- Pagination controls
- Improved header with desktop nav

Features:
- Pagination on all list pages (loads, trips, users, messages, etc.)
- Admin stats JSON endpoint
- Admin user delete route
- Load cancel route
- Mark invoice as paid route
- Search/filter preserved on loadboard

Database:
- Additional composite indexes for performance
- Updated timestamps trigger on trips
- Improved FULL migration script

DevEx:
- Development seed script (seed.js)
- Improved Dockerfile (non-root, healthcheck)
- Comprehensive .gitignore
- Updated README v2.0
2026-05-31 18:08:01 +00:00

87 lines
4.1 KiB
JavaScript

#!/usr/bin/env node
/**
* BharathTrucks — Development Seed Script
* Creates sample users and loads for local development
* Usage: node seed.js
*/
require('dotenv').config();
const { createClient } = require('@supabase/supabase-js');
const bcrypt = require('bcryptjs');
const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY);
async function seed() {
console.log('🌱 Seeding BharathTrucks database...\n');
const passwordHash = await bcrypt.hash('password123', 10);
const users = [
{ username: 'admin', name: 'Admin User', password_hash: await bcrypt.hash('admin123', 10), role: 'admin' },
{ username: 'driver_raj', name: 'Raj Kumar', password_hash: passwordHash, role: 'driver', phone: '9876543210', city: 'Mumbai', state: 'Maharashtra' },
{ username: 'driver_aman', name: 'Aman Singh', password_hash: passwordHash, role: 'driver', phone: '9876543211', city: 'Delhi', state: 'Delhi' },
{ username: 'shipper_agarwal', name: 'Agarwal Packers', password_hash: passwordHash, role: 'shipper', phone: '9876543212', city: 'Kolkata', state: 'West Bengal' },
{ username: 'broker_kahn', name: 'Kahn Transport', password_hash: passwordHash, role: 'broker', phone: '9876543213', city: 'Chennai', state: 'Tamil Nadu' },
];
// Insert users
const userIds = {};
for (const u of users) {
const { data, error } = await supabase.from('app_users').upsert(u, { onConflict: 'username' }).select().single();
if (data) {
userIds[u.username] = data.id;
console.log(` ✓ User: ${u.username} (${u.role})`);
} else if (error) {
console.log(`${u.username}: ${error.message}`);
}
}
const shipperId = userIds['shipper_agarwal'];
const brokerId = userIds['broker_kahn'];
const driver1 = userIds['driver_raj'];
const driver2 = userIds['driver_aman'];
if (shipperId) {
const loads = [
{ posted_by: shipperId, origin_city: 'Mumbai', destination_city: 'Delhi', weight_tons: 12, truck_type: 'container', material_type: 'Electronics', budget: 45000, pickup_date: new Date(Date.now() + 2*86400000).toISOString().split('T')[0], description: 'Electronics shipment, handle with care', is_urgent: true, status: 'open' },
{ posted_by: shipperId, origin_city: 'Chennai', destination_city: 'Bangalore', weight_tons: 8, truck_type: 'closed', material_type: 'Textiles', budget: 22000, pickup_date: new Date(Date.now() + 1*86400000).toISOString().split('T')[0], description: 'Textile goods', is_urgent: false, status: 'open' },
{ posted_by: shipperId, origin_city: 'Kolkata', destination_city: 'Mumbai', weight_tons: 20, truck_type: 'open', material_type: 'Steel', budget: 65000, pickup_date: new Date(Date.now() + 3*86400000).toISOString().split('T')[0], description: 'Steel coils', is_urgent: false, status: 'open' },
];
for (const l of loads) {
const { error } = await supabase.from('loads').insert(l);
if (!error) console.log(` ✓ Load: ${l.origin_city}${l.destination_city}`);
else console.log(` ⚠ Load error: ${error.message}`);
}
}
if (driver1 && driver2) {
// Get a load to bid on
const { data: load } = await supabase.from('loads').select('id').eq('status', 'open').limit(1).single();
if (load) {
await supabase.from('bids').insert([
{ load_id: load.id, driver_id: driver1, amount: 42000, note: 'Experienced driver with GPS' },
{ load_id: load.id, driver_id: driver2, amount: 41000, note: 'Best rates guaranteed' },
]);
console.log(' ✓ Sample bids created');
}
}
if (shipperId) {
await supabase.from('user_gamification').upsert([
{ user_id: shipperId, xp: 80, login_streak: 3 },
{ user_id: driver1, xp: 120, login_streak: 5 },
{ user_id: driver2, xp: 60, login_streak: 2 },
], { onConflict: 'user_id' });
console.log(' ✓ Gamification data seeded');
}
console.log('\n✅ Seed complete!');
console.log('\nDefault passwords:');
console.log(' admin → admin123');
console.log(' all other users → password123');
}
seed().catch(err => {
console.error('Seed failed:', err.message);
process.exit(1);
});