import { pool } from '../db.js'; import crypto from 'crypto'; // Job templates for variety // Job templates for variety (Funny & Serious mix) const jobTemplates = [ // Tech Roles { title: 'Senior Stack Overflow Copy-Paster', skills: ['Ctrl+C', 'Ctrl+V', 'Google Fu'], salaryRange: [120000, 180000] }, // High salary { title: 'Full Stack Overflow Engineer', skills: ['JavaScript', 'Python', 'Chaos Engineering'], salaryRange: [90000, 150000] }, { title: 'Frontend Div Centerer', skills: ['CSS', 'Flexbox', 'Patience'], salaryRange: [70000, 120000] }, { title: 'Backend JSON Mover', skills: ['Node.js', 'Go', 'REST'], salaryRange: [85000, 140000] }, { title: 'Kubernetes YAML Herder', skills: ['Docker', 'K8s', 'Indentations'], salaryRange: [130000, 200000] }, { title: 'AI Prompt Whisperer', skills: ['ChatGPT', 'English', 'Imagination'], salaryRange: [60000, 300000] }, // Volatile salary { title: 'Legacy Code Archaeologist', skills: ['COBOL', 'Fortran', 'Dusting'], salaryRange: [150000, 250000] }, // Management & Product { title: 'Chief Meeting Scheduler', skills: ['Calendar', 'Zoom', 'Talking'], salaryRange: [100000, 160000] }, { title: 'Scrum Master of Puppets', skills: ['Jira', 'Whips', 'Post-its'], salaryRange: [90000, 140000] }, { title: 'Product Visionary (Dreamer)', skills: ['Keynote', 'Buzzwords', 'Optimism'], salaryRange: [110000, 190000] }, // Design { title: 'Pixel Perfect Pedant', skills: ['Figma', 'Zoom 800%', 'Eye Drops'], salaryRange: [80000, 130000] }, { title: 'UX Dark Pattern Architect', skills: ['Psychology', 'Manipulation', 'CSS'], salaryRange: [95000, 155000] }, // Financial (The "Banco Desaster" influence) { title: 'Creative Accountant', skills: ['Excel', 'Creativity', 'Obfuscation'], salaryRange: [100000, 500000] }, { title: 'High-Frequency Front-Runner', skills: ['C++', 'Low Latency', 'Moral Flexibility'], salaryRange: [200000, 800000] }, { title: 'Offshore Database Admin', skills: ['SQL', 'Boat Driving', 'Secrecy'], salaryRange: [120000, 180000] }, { title: 'Risk Ignoring Manager', skills: ['Coin Toss', 'Gut Feeling', 'Blindfolds'], salaryRange: [150000, 300000] } ]; const internationalLocations = [ 'New York, NY', 'San Francisco, CA', 'London, UK', 'Berlin, DE', 'Remote (Global)', 'Silicon Valley, CA', 'Austin, TX', 'Amsterdam, NL', 'Tokyo, JP', 'Singapore, SG', 'Dubai, UAE', 'Cayman Islands' ]; const workModes = ['onsite', 'hybrid', 'remote']; const levels = ['Junior', 'Mid-Level', 'Senior', 'Lead']; const benefits = [ 'Health Insurance', 'Dental Plan', 'Gym Membership', 'Stock Options', 'Remote Work', 'Flexible Hours', 'Annual Bonus', 'Education Budget', 'Meal Allowance', 'Transport Allowance', 'Home Office Setup', 'Wellness Program' ]; function getRandomItems(arr, count) { const shuffled = [...arr].sort(() => 0.5 - Math.random()); return shuffled.slice(0, count); } function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } export async function seedJobs() { console.log('💼 Seeding jobs (25 per company)...'); // Get company IDs from companies table (jobs.company_id references companies.id which is INT) const companiesRes = await pool.query('SELECT id, name FROM companies ORDER BY name'); const companies = companiesRes.rows; if (companies.length === 0) { console.log(' ⚠️ No companies found. Please seed companies first.'); return; } // Get a user from users table for created_by FK (INT) const seedUserRes = await pool.query("SELECT id FROM users LIMIT 1"); if (seedUserRes.rows.length === 0) { console.log(' ⚠️ No users found. Creating a system user...'); await pool.query(` INSERT INTO users (name, email, password_hash, role, status) VALUES ('System Seeder', 'system@gohorsejobs.com', '$2b$10$placeholder', 'admin', 'active') ON CONFLICT DO NOTHING `); } const userRes = await pool.query("SELECT id FROM users LIMIT 1"); const seedUserId = userRes.rows[0]?.id; let totalJobs = 0; try { // Process companies in chunks to avoid overwhelming the DB for (const company of companies) { const jobValues = []; const jobParams = []; let paramCounter = 1; // Generate 25 jobs per company for (let i = 0; i < 25; i++) { const template = jobTemplates[i % jobTemplates.length]; const level = levels[i % levels.length]; const workMode = workModes[i % 3]; // Even distribution: onsite, hybrid, remote const title = i < 33 ? `${level} ${template.title}` : template.title; const salaryMin = template.salaryRange[0] + getRandomInt(-2000, 2000); const salaryMax = template.salaryRange[1] + getRandomInt(-2000, 3000); const employmentTypes = ['full-time', 'part-time', 'contract', 'permanent', 'temporary', 'training']; const currencies = ['BRL', 'BRL', 'BRL', 'BRL', 'BRL', 'BRL', 'BRL', 'USD', 'USD', 'EUR']; // 70% BRL, 20% USD, 10% EUR const salaryTypes = ['hourly', 'daily', 'weekly', 'monthly', 'yearly']; const employmentType = employmentTypes[i % employmentTypes.length]; const currency = currencies[i % currencies.length]; const salaryType = salaryTypes[i % salaryTypes.length]; const workingHoursOptions = ['full-time', 'part-time', '']; const workingHours = workingHoursOptions[i % 3]; const salaryNegotiable = i % 10 === 0; // 10% negotiable // Prepare params for bulk insert jobParams.push( company.id, seedUserId, title, `We are looking for a talented ${title} to join our ${company.name} team. Your role as ${level} will be crucial.`, salaryNegotiable ? null : salaryMin, // If negotiable, min is null salaryNegotiable ? null : salaryMax, // If negotiable, max is null salaryType, currency, employmentType, workingHours, workMode === 'remote' ? 'Remote (Global)' : internationalLocations[i % internationalLocations.length], JSON.stringify(template.skills), JSON.stringify(getRandomItems(benefits, 4)), i % 5 === 0, // 20% offer visa support 'beginner', 'open', workMode, salaryNegotiable ); // ($1, $2, $3, ...), ($18, $19, ...) const placeHolders = []; for (let k = 0; k < 18; k++) { placeHolders.push(`$${paramCounter++}`); } jobValues.push(`(${placeHolders.join(',')})`); totalJobs++; } // Bulk Insert for this company if (jobValues.length > 0) { const query = ` INSERT INTO jobs (company_id, created_by, title, description, salary_min, salary_max, salary_type, currency, employment_type, working_hours, location, requirements, benefits, visa_support, language_level, status, work_mode, salary_negotiable) VALUES ${jobValues.join(',')} `; await pool.query(query, jobParams); } } console.log(` ✓ ${totalJobs} jobs seeded across ${companies.length} companies`); console.log(` 📊 Work mode distribution: ~33% onsite, ~33% hybrid, ~33% remote`); } catch (error) { console.error(' ❌ Error seeding jobs:', error.message); throw error; } }