pipedrive / src /lib /db /seed.ts
ppEmiliano's picture
Add full CRM application with HF Spaces Docker deployment
ea8dde3
import Database from "better-sqlite3";
import { hashSync } from "bcryptjs";
import path from "path";
import fs from "fs";
const dataDir = path.join(process.cwd(), "data");
if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true });
const dbPath = path.join(dataDir, "crm.db");
const sqlite = new Database(dbPath);
sqlite.pragma("journal_mode = WAL");
sqlite.pragma("foreign_keys = ON");
function seed() {
console.log("Seeding database...");
sqlite.exec(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
password_hash TEXT NOT NULL,
created_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS companies (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
domain TEXT,
phone TEXT,
address TEXT,
notes TEXT,
user_id INTEGER NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS contacts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
email TEXT,
phone TEXT,
job_title TEXT,
company_id INTEGER REFERENCES companies(id),
user_id INTEGER NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS pipelines (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
user_id INTEGER NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS pipeline_stages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
position INTEGER NOT NULL,
probability INTEGER NOT NULL DEFAULT 0,
pipeline_id INTEGER NOT NULL REFERENCES pipelines(id),
created_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS deals (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
value REAL NOT NULL DEFAULT 0,
status TEXT NOT NULL DEFAULT 'open',
position INTEGER NOT NULL DEFAULT 0,
expected_close_date TEXT,
stage_id INTEGER NOT NULL REFERENCES pipeline_stages(id),
contact_id INTEGER REFERENCES contacts(id),
company_id INTEGER REFERENCES companies(id),
pipeline_id INTEGER NOT NULL REFERENCES pipelines(id),
user_id INTEGER NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS activities (
id INTEGER PRIMARY KEY AUTOINCREMENT,
type TEXT NOT NULL,
subject TEXT NOT NULL,
description TEXT,
due_date TEXT,
is_done INTEGER NOT NULL DEFAULT 0,
deal_id INTEGER REFERENCES deals(id),
contact_id INTEGER REFERENCES contacts(id),
company_id INTEGER REFERENCES companies(id),
user_id INTEGER NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
`);
// Check if already seeded
const existing = sqlite.prepare("SELECT COUNT(*) as cnt FROM users").get() as { cnt: number };
if (existing.cnt > 0) {
console.log("Database already seeded, skipping.");
return;
}
const now = new Date().toISOString();
// Seed user
const userResult = sqlite
.prepare("INSERT INTO users (email, name, password_hash, created_at) VALUES (?, ?, ?, ?) RETURNING id")
.get("admin@local.host", "Admin User", hashSync("admin123", 10), now) as { id: number };
const userId = userResult.id;
// Seed pipeline
const pipResult = sqlite
.prepare("INSERT INTO pipelines (name, user_id, created_at) VALUES (?, ?, ?) RETURNING id")
.get("Sales Pipeline", userId, now) as { id: number };
const pipelineId = pipResult.id;
// Seed stages
const stageData = [
{ name: "Lead In", position: 0, probability: 10 },
{ name: "Contact Made", position: 1, probability: 25 },
{ name: "Proposal Sent", position: 2, probability: 50 },
{ name: "Negotiation", position: 3, probability: 75 },
{ name: "Won", position: 4, probability: 100 },
{ name: "Lost", position: 5, probability: 0 },
];
const stageInsert = sqlite.prepare(
"INSERT INTO pipeline_stages (name, position, probability, pipeline_id, created_at) VALUES (?, ?, ?, ?, ?) RETURNING id"
);
const stageIds: number[] = [];
for (const s of stageData) {
const r = stageInsert.get(s.name, s.position, s.probability, pipelineId, now) as { id: number };
stageIds.push(r.id);
}
// Seed companies
const companyData = [
{ name: "Acme Corp", domain: "acme.com", phone: "+1-555-0100", address: "123 Main St, New York, NY", notes: "Enterprise client" },
{ name: "TechStart Inc", domain: "techstart.io", phone: "+1-555-0200", address: "456 Innovation Dr, San Francisco, CA", notes: "Series B startup" },
{ name: "Global Media", domain: "globalmedia.com", phone: "+1-555-0300", address: "789 Broadway, New York, NY", notes: "Media conglomerate" },
{ name: "DataFlow Systems", domain: "dataflow.dev", phone: "+1-555-0400", address: "321 Tech Park, Austin, TX", notes: "Data analytics company" },
{ name: "GreenEnergy Co", domain: "greenenergy.com", phone: "+1-555-0500", address: "555 Solar Way, Denver, CO", notes: "Renewable energy" },
{ name: "HealthPlus", domain: "healthplus.org", phone: "+1-555-0600", address: "100 Medical Dr, Boston, MA", notes: "Healthcare provider" },
{ name: "FinanceHub", domain: "financehub.com", phone: "+1-555-0700", address: "200 Wall St, New York, NY", notes: "Financial services" },
{ name: "EduLearn", domain: "edulearn.com", phone: "+1-555-0800", address: "300 Campus Rd, Chicago, IL", notes: "EdTech platform" },
{ name: "RetailMax", domain: "retailmax.com", phone: "+1-555-0900", address: "400 Commerce Ave, Seattle, WA", notes: "E-commerce retailer" },
{ name: "BuildRight", domain: "buildright.com", phone: "+1-555-1000", address: "500 Construction Blvd, Phoenix, AZ", notes: "Construction firm" },
{ name: "CloudNine", domain: "cloudnine.io", phone: "+1-555-1100", address: "600 Cloud Ln, Portland, OR", notes: "Cloud infrastructure" },
{ name: "FoodFresh", domain: "foodfresh.com", phone: "+1-555-1200", address: "700 Farm Rd, Sacramento, CA", notes: "Food delivery service" },
{ name: "AutoDrive", domain: "autodrive.com", phone: "+1-555-1300", address: "800 Motor Way, Detroit, MI", notes: "Automotive tech" },
{ name: "SafeGuard", domain: "safeguard.com", phone: "+1-555-1400", address: "900 Security Blvd, Washington, DC", notes: "Cybersecurity firm" },
{ name: "TravelWise", domain: "travelwise.com", phone: "+1-555-1500", address: "150 Journey St, Miami, FL", notes: "Travel booking platform" },
{ name: "SmartHome", domain: "smarthome.com", phone: "+1-555-1600", address: "250 IoT Ave, San Jose, CA", notes: "Smart home devices" },
{ name: "BioGenix", domain: "biogenix.com", phone: "+1-555-1700", address: "350 Bio Ln, San Diego, CA", notes: "Biotech research" },
{ name: "LogiTrack", domain: "logitrack.com", phone: "+1-555-1800", address: "450 Shipping Rd, Memphis, TN", notes: "Logistics & tracking" },
{ name: "MediaBuzz", domain: "mediabuzz.com", phone: "+1-555-1900", address: "550 Content St, Los Angeles, CA", notes: "Digital marketing agency" },
{ name: "LegalEdge", domain: "legaledge.com", phone: "+1-555-2000", address: "650 Court Ave, Philadelphia, PA", notes: "Legal tech platform" },
];
const companyInsert = sqlite.prepare(
"INSERT INTO companies (name, domain, phone, address, notes, user_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING id"
);
const companyIds: number[] = [];
for (const c of companyData) {
const r = companyInsert.get(c.name, c.domain, c.phone, c.address, c.notes, userId, now, now) as { id: number };
companyIds.push(r.id);
}
// Seed contacts
const contactData = [
{ firstName: "John", lastName: "Smith", email: "john@acme.com", phone: "+1-555-0101", jobTitle: "CEO", compIdx: 0 },
{ firstName: "Sarah", lastName: "Johnson", email: "sarah@acme.com", phone: "+1-555-0102", jobTitle: "VP Sales", compIdx: 0 },
{ firstName: "Mike", lastName: "Chen", email: "mike@techstart.io", phone: "+1-555-0201", jobTitle: "CTO", compIdx: 1 },
{ firstName: "Emily", lastName: "Davis", email: "emily@techstart.io", phone: "+1-555-0202", jobTitle: "Product Manager", compIdx: 1 },
{ firstName: "David", lastName: "Wilson", email: "david@globalmedia.com", phone: "+1-555-0301", jobTitle: "Head of Marketing", compIdx: 2 },
{ firstName: "Lisa", lastName: "Brown", email: "lisa@dataflow.dev", phone: "+1-555-0401", jobTitle: "Data Scientist", compIdx: 3 },
{ firstName: "James", lastName: "Taylor", email: "james@greenenergy.com", phone: "+1-555-0501", jobTitle: "Operations Director", compIdx: 4 },
{ firstName: "Anna", lastName: "Martinez", email: "anna@healthplus.org", phone: "+1-555-0601", jobTitle: "IT Director", compIdx: 5 },
{ firstName: "Robert", lastName: "Anderson", email: "robert@financehub.com", phone: "+1-555-0701", jobTitle: "CFO", compIdx: 6 },
{ firstName: "Jennifer", lastName: "Thomas", email: "jennifer@edulearn.com", phone: "+1-555-0801", jobTitle: "Head of Partnerships", compIdx: 7 },
{ firstName: "William", lastName: "Jackson", email: "william@retailmax.com", phone: "+1-555-0901", jobTitle: "Procurement Lead", compIdx: 8 },
{ firstName: "Patricia", lastName: "White", email: "patricia@buildright.com", phone: "+1-555-1001", jobTitle: "Project Manager", compIdx: 9 },
{ firstName: "Daniel", lastName: "Harris", email: "daniel@cloudnine.io", phone: "+1-555-1101", jobTitle: "Solutions Architect", compIdx: 10 },
{ firstName: "Karen", lastName: "Clark", email: "karen@foodfresh.com", phone: "+1-555-1201", jobTitle: "Supply Chain Manager", compIdx: 11 },
{ firstName: "Matthew", lastName: "Lewis", email: "matthew@autodrive.com", phone: "+1-555-1301", jobTitle: "Engineering Lead", compIdx: 12 },
{ firstName: "Nancy", lastName: "Robinson", email: "nancy@safeguard.com", phone: "+1-555-1401", jobTitle: "CISO", compIdx: 13 },
{ firstName: "Andrew", lastName: "Walker", email: "andrew@travelwise.com", phone: "+1-555-1501", jobTitle: "Business Development", compIdx: 14 },
{ firstName: "Betty", lastName: "Young", email: "betty@smarthome.com", phone: "+1-555-1601", jobTitle: "Product Lead", compIdx: 15 },
{ firstName: "Christopher", lastName: "King", email: "chris@biogenix.com", phone: "+1-555-1701", jobTitle: "Research Director", compIdx: 16 },
{ firstName: "Susan", lastName: "Wright", email: "susan@logitrack.com", phone: "+1-555-1801", jobTitle: "Operations Manager", compIdx: 17 },
{ firstName: "Mark", lastName: "Hill", email: "mark@mediabuzz.com", phone: "+1-555-1901", jobTitle: "Creative Director", compIdx: 18 },
{ firstName: "Sandra", lastName: "Scott", email: "sandra@legaledge.com", phone: "+1-555-2001", jobTitle: "Managing Partner", compIdx: 19 },
{ firstName: "Kevin", lastName: "Green", email: "kevin@acme.com", phone: "+1-555-0103", jobTitle: "CFO", compIdx: 0 },
{ firstName: "Donna", lastName: "Adams", email: "donna@techstart.io", phone: "+1-555-0203", jobTitle: "Designer", compIdx: 1 },
{ firstName: "Brian", lastName: "Nelson", email: "brian@globalmedia.com", phone: "+1-555-0302", jobTitle: "Editor in Chief", compIdx: 2 },
{ firstName: "Carol", lastName: "Baker", email: "carol@dataflow.dev", phone: "+1-555-0402", jobTitle: "VP Engineering", compIdx: 3 },
{ firstName: "George", lastName: "Gonzalez", email: "george@greenenergy.com", phone: "+1-555-0502", jobTitle: "Sales Director", compIdx: 4 },
{ firstName: "Dorothy", lastName: "Perez", email: "dorothy@healthplus.org", phone: "+1-555-0602", jobTitle: "CEO", compIdx: 5 },
{ firstName: "Timothy", lastName: "Roberts", email: "timothy@financehub.com", phone: "+1-555-0702", jobTitle: "Risk Manager", compIdx: 6 },
{ firstName: "Helen", lastName: "Turner", email: "helen@edulearn.com", phone: "+1-555-0802", jobTitle: "Content Lead", compIdx: 7 },
{ firstName: "Jason", lastName: "Phillips", email: "jason@retailmax.com", phone: "+1-555-0902", jobTitle: "CTO", compIdx: 8 },
{ firstName: "Ruth", lastName: "Campbell", email: "ruth@buildright.com", phone: "+1-555-1002", jobTitle: "CEO", compIdx: 9 },
{ firstName: "Gary", lastName: "Parker", email: "gary@cloudnine.io", phone: "+1-555-1102", jobTitle: "DevOps Lead", compIdx: 10 },
{ firstName: "Sharon", lastName: "Evans", email: "sharon@foodfresh.com", phone: "+1-555-1202", jobTitle: "Marketing Director", compIdx: 11 },
{ firstName: "Ronald", lastName: "Edwards", email: "ronald@autodrive.com", phone: "+1-555-1302", jobTitle: "CEO", compIdx: 12 },
{ firstName: "Laura", lastName: "Collins", email: "laura@safeguard.com", phone: "+1-555-1402", jobTitle: "VP Sales", compIdx: 13 },
{ firstName: "Frank", lastName: "Stewart", email: "frank@travelwise.com", phone: "+1-555-1502", jobTitle: "CTO", compIdx: 14 },
{ firstName: "Virginia", lastName: "Sanchez", email: "virginia@smarthome.com", phone: "+1-555-1602", jobTitle: "CEO", compIdx: 15 },
{ firstName: "Paul", lastName: "Morris", email: "paul@biogenix.com", phone: "+1-555-1702", jobTitle: "VP Sales", compIdx: 16 },
{ firstName: "Deborah", lastName: "Rogers", email: "deborah@logitrack.com", phone: "+1-555-1802", jobTitle: "CEO", compIdx: 17 },
{ firstName: "Stephen", lastName: "Reed", email: "stephen@mediabuzz.com", phone: "+1-555-1902", jobTitle: "Account Manager", compIdx: 18 },
{ firstName: "Margaret", lastName: "Cook", email: "margaret@legaledge.com", phone: "+1-555-2002", jobTitle: "Senior Counsel", compIdx: 19 },
{ firstName: "Raymond", lastName: "Morgan", email: "raymond@acme.com", phone: "+1-555-0104", jobTitle: "Sales Rep", compIdx: 0 },
{ firstName: "Cynthia", lastName: "Bell", email: "cynthia@techstart.io", phone: "+1-555-0204", jobTitle: "Marketing Lead", compIdx: 1 },
{ firstName: "Edward", lastName: "Murphy", email: "edward@globalmedia.com", phone: "+1-555-0303", jobTitle: "Sales Rep", compIdx: 2 },
{ firstName: "Kathleen", lastName: "Bailey", email: "kathleen@dataflow.dev", phone: "+1-555-0403", jobTitle: "Account Executive", compIdx: 3 },
{ firstName: "Dennis", lastName: "Rivera", email: "dennis@greenenergy.com", phone: "+1-555-0503", jobTitle: "Account Manager", compIdx: 4 },
{ firstName: "Angela", lastName: "Cooper", email: "angela@healthplus.org", phone: "+1-555-0603", jobTitle: "Sales Manager", compIdx: 5 },
{ firstName: "Patrick", lastName: "Richardson", email: "patrick@financehub.com", phone: "+1-555-0703", jobTitle: "VP Products", compIdx: 6 },
{ firstName: "Marie", lastName: "Cox", email: "marie@edulearn.com", phone: "+1-555-0803", jobTitle: "CEO", compIdx: 7 },
];
const contactInsert = sqlite.prepare(
"INSERT INTO contacts (first_name, last_name, email, phone, job_title, company_id, user_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING id"
);
const contactIds: number[] = [];
for (const c of contactData) {
const r = contactInsert.get(c.firstName, c.lastName, c.email, c.phone, c.jobTitle, companyIds[c.compIdx], userId, now, now) as { id: number };
contactIds.push(r.id);
}
// Seed deals
const dealInsert = sqlite.prepare(
"INSERT INTO deals (title, value, status, position, expected_close_date, stage_id, contact_id, company_id, pipeline_id, user_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
);
const dealData = [
{ title: "Acme Enterprise License", value: 125000, stIdx: 3, cIdx: 0, coIdx: 0, days: -5 },
{ title: "TechStart Platform Integration", value: 45000, stIdx: 2, cIdx: 2, coIdx: 1, days: 10 },
{ title: "Global Media Ad Campaign", value: 85000, stIdx: 1, cIdx: 4, coIdx: 2, days: 15 },
{ title: "DataFlow Analytics Suite", value: 62000, stIdx: 0, cIdx: 5, coIdx: 3, days: 20 },
{ title: "GreenEnergy Monitoring System", value: 38000, stIdx: 2, cIdx: 6, coIdx: 4, days: 7 },
{ title: "HealthPlus EHR Integration", value: 95000, stIdx: 3, cIdx: 7, coIdx: 5, days: -2 },
{ title: "FinanceHub Trading Platform", value: 200000, stIdx: 1, cIdx: 8, coIdx: 6, days: 30 },
{ title: "EduLearn LMS Upgrade", value: 32000, stIdx: 0, cIdx: 9, coIdx: 7, days: 25 },
{ title: "RetailMax POS System", value: 55000, stIdx: 2, cIdx: 10, coIdx: 8, days: 12 },
{ title: "BuildRight Project Tracker", value: 28000, stIdx: 1, cIdx: 11, coIdx: 9, days: 18 },
{ title: "Acme Support Contract", value: 48000, stIdx: 4, cIdx: 1, coIdx: 0, days: -30 },
{ title: "CloudNine Migration", value: 72000, stIdx: 3, cIdx: 12, coIdx: 10, days: 5 },
{ title: "FoodFresh Route Optimization", value: 41000, stIdx: 0, cIdx: 13, coIdx: 11, days: 22 },
{ title: "AutoDrive Fleet Management", value: 110000, stIdx: 2, cIdx: 14, coIdx: 12, days: 8 },
{ title: "SafeGuard Security Audit", value: 65000, stIdx: 1, cIdx: 15, coIdx: 13, days: 14 },
{ title: "TravelWise Booking Engine", value: 88000, stIdx: 5, cIdx: 16, coIdx: 14, days: -15 },
{ title: "SmartHome API Integration", value: 35000, stIdx: 0, cIdx: 17, coIdx: 15, days: 28 },
{ title: "BioGenix Lab System", value: 150000, stIdx: 3, cIdx: 18, coIdx: 16, days: 3 },
{ title: "LogiTrack Delivery Platform", value: 58000, stIdx: 2, cIdx: 19, coIdx: 17, days: 11 },
{ title: "MediaBuzz Campaign Manager", value: 42000, stIdx: 1, cIdx: 20, coIdx: 18, days: 16 },
{ title: "LegalEdge Document System", value: 75000, stIdx: 0, cIdx: 21, coIdx: 19, days: 24 },
{ title: "TechStart Mobile App", value: 67000, stIdx: 4, cIdx: 3, coIdx: 1, days: -20 },
{ title: "FinanceHub Compliance Tool", value: 130000, stIdx: 2, cIdx: 28, coIdx: 6, days: 9 },
{ title: "GreenEnergy Dashboard", value: 25000, stIdx: 4, cIdx: 26, coIdx: 4, days: -10 },
{ title: "DataFlow ML Pipeline", value: 90000, stIdx: 1, cIdx: 25, coIdx: 3, days: 19 },
{ title: "HealthPlus Telehealth", value: 115000, stIdx: 5, cIdx: 27, coIdx: 5, days: -8 },
{ title: "RetailMax Inventory System", value: 47000, stIdx: 3, cIdx: 30, coIdx: 8, days: 6 },
{ title: "BuildRight Safety App", value: 33000, stIdx: 0, cIdx: 31, coIdx: 9, days: 21 },
{ title: "AutoDrive Diagnostics", value: 78000, stIdx: 4, cIdx: 34, coIdx: 12, days: -25 },
{ title: "SafeGuard Pen Testing", value: 52000, stIdx: 3, cIdx: 35, coIdx: 13, days: 4 },
];
dealData.forEach((d, idx) => {
const closeDate = new Date();
closeDate.setDate(closeDate.getDate() + d.days);
const status = d.stIdx === 4 ? "won" : d.stIdx === 5 ? "lost" : "open";
dealInsert.run(
d.title, d.value, status, idx,
closeDate.toISOString().split("T")[0],
stageIds[d.stIdx], contactIds[d.cIdx], companyIds[d.coIdx],
pipelineId, userId, now, now
);
});
// Seed activities
const actInsert = sqlite.prepare(
"INSERT INTO activities (type, subject, description, due_date, is_done, deal_id, contact_id, company_id, user_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
);
// Get deal IDs
const dealIds = (sqlite.prepare("SELECT id FROM deals ORDER BY id").all() as { id: number }[]).map(r => r.id);
const activityData = [
{ type: "call", subject: "Discovery call with John Smith", cIdx: 0, coIdx: 0, dIdx: 0, days: -3, done: 1 },
{ type: "email", subject: "Sent proposal to TechStart", cIdx: 2, coIdx: 1, dIdx: 1, days: -2, done: 1 },
{ type: "meeting", subject: "Demo with Global Media team", cIdx: 4, coIdx: 2, dIdx: 2, days: -1, done: 1 },
{ type: "task", subject: "Prepare pricing sheet for DataFlow", cIdx: 5, coIdx: 3, dIdx: 3, days: 0, done: 0 },
{ type: "note", subject: "GreenEnergy budget approved for Q2", cIdx: 6, coIdx: 4, dIdx: 4, days: -4, done: 1 },
{ type: "call", subject: "Follow-up with HealthPlus IT team", cIdx: 7, coIdx: 5, dIdx: 5, days: 1, done: 0 },
{ type: "email", subject: "Contract draft to FinanceHub", cIdx: 8, coIdx: 6, dIdx: 6, days: -1, done: 1 },
{ type: "meeting", subject: "Quarterly review with EduLearn", cIdx: 9, coIdx: 7, dIdx: 7, days: 2, done: 0 },
{ type: "task", subject: "Create RetailMax demo environment", cIdx: 10, coIdx: 8, dIdx: 8, days: 1, done: 0 },
{ type: "call", subject: "Intro call with BuildRight PM", cIdx: 11, coIdx: 9, dIdx: 9, days: -5, done: 1 },
{ type: "note", subject: "Acme contract signed - won!", cIdx: 1, coIdx: 0, dIdx: 10, days: -30, done: 1 },
{ type: "email", subject: "CloudNine migration timeline", cIdx: 12, coIdx: 10, dIdx: 11, days: 0, done: 0 },
{ type: "meeting", subject: "FoodFresh logistics walkthrough", cIdx: 13, coIdx: 11, dIdx: 12, days: 3, done: 0 },
{ type: "call", subject: "AutoDrive fleet requirements", cIdx: 14, coIdx: 12, dIdx: 13, days: -2, done: 1 },
{ type: "task", subject: "Prepare SafeGuard audit scope", cIdx: 15, coIdx: 13, dIdx: 14, days: 2, done: 0 },
{ type: "note", subject: "TravelWise deal lost - budget cut", cIdx: 16, coIdx: 14, dIdx: 15, days: -15, done: 1 },
{ type: "email", subject: "SmartHome API documentation", cIdx: 17, coIdx: 15, dIdx: 16, days: 1, done: 0 },
{ type: "meeting", subject: "BioGenix lab requirements workshop", cIdx: 18, coIdx: 16, dIdx: 17, days: 4, done: 0 },
{ type: "call", subject: "LogiTrack platform demo", cIdx: 19, coIdx: 17, dIdx: 18, days: -1, done: 1 },
{ type: "email", subject: "MediaBuzz campaign specs", cIdx: 20, coIdx: 18, dIdx: 19, days: 0, done: 0 },
{ type: "task", subject: "Draft LegalEdge proposal", cIdx: 21, coIdx: 19, dIdx: 20, days: 3, done: 0 },
{ type: "call", subject: "TechStart renewal discussion", cIdx: 3, coIdx: 1, dIdx: 21, days: -20, done: 1 },
{ type: "meeting", subject: "FinanceHub compliance review", cIdx: 28, coIdx: 6, dIdx: 22, days: 5, done: 0 },
{ type: "note", subject: "GreenEnergy dashboard delivered", cIdx: 26, coIdx: 4, dIdx: 23, days: -10, done: 1 },
{ type: "email", subject: "DataFlow ML requirements doc", cIdx: 25, coIdx: 3, dIdx: 24, days: -1, done: 1 },
{ type: "call", subject: "HealthPlus telehealth post-mortem", cIdx: 27, coIdx: 5, dIdx: 25, days: -7, done: 1 },
{ type: "task", subject: "Setup RetailMax test environment", cIdx: 30, coIdx: 8, dIdx: 26, days: 2, done: 0 },
{ type: "meeting", subject: "BuildRight safety demo", cIdx: 31, coIdx: 9, dIdx: 27, days: 6, done: 0 },
{ type: "note", subject: "AutoDrive diagnostics launched", cIdx: 34, coIdx: 12, dIdx: 28, days: -25, done: 1 },
{ type: "call", subject: "SafeGuard pen test scheduling", cIdx: 35, coIdx: 13, dIdx: 29, days: 1, done: 0 },
{ type: "email", subject: "Weekly pipeline update to team", cIdx: -1, coIdx: -1, dIdx: -1, days: -1, done: 1 },
{ type: "task", subject: "Update CRM contact records", cIdx: -1, coIdx: -1, dIdx: -1, days: 0, done: 0 },
{ type: "meeting", subject: "Sales team standup", cIdx: -1, coIdx: -1, dIdx: -1, days: 1, done: 0 },
{ type: "call", subject: "Follow up with Acme on expansion", cIdx: 0, coIdx: 0, dIdx: -1, days: 3, done: 0 },
{ type: "email", subject: "Send case study to TechStart", cIdx: 2, coIdx: 1, dIdx: -1, days: 2, done: 0 },
{ type: "task", subject: "Research competitor pricing", cIdx: -1, coIdx: -1, dIdx: -1, days: 4, done: 0 },
{ type: "meeting", subject: "Product roadmap review", cIdx: -1, coIdx: -1, dIdx: -1, days: 5, done: 0 },
{ type: "note", subject: "Q1 target reached - 85% of quota", cIdx: -1, coIdx: -1, dIdx: -1, days: -7, done: 1 },
{ type: "call", subject: "Cold call campaign - batch 12", cIdx: -1, coIdx: -1, dIdx: -1, days: 0, done: 0 },
{ type: "email", subject: "Newsletter to prospects", cIdx: -1, coIdx: -1, dIdx: -1, days: -2, done: 1 },
];
for (const a of activityData) {
const dueDate = new Date();
dueDate.setDate(dueDate.getDate() + a.days);
actInsert.run(
a.type, a.subject, null,
dueDate.toISOString().split("T")[0],
a.done,
a.dIdx >= 0 ? dealIds[a.dIdx] : null,
a.cIdx >= 0 ? contactIds[a.cIdx] : null,
a.coIdx >= 0 ? companyIds[a.coIdx] : null,
userId, now, now
);
}
console.log("Seeded: 1 user, 1 pipeline, 6 stages, 20 companies, 50 contacts, 30 deals, 40 activities");
}
seed();
sqlite.close();