mirror of
http://forgejo-oa09toasww4dgii9cj3gpzda.187.127.164.61.sslip.io/iamcoolvivek007/bharath.git
synced 2026-06-11 00:06:51 +00:00
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
87 lines
4.1 KiB
JavaScript
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);
|
|
});
|