From f9231ab1268fe88bd1ce369c09cb775a6470a3be Mon Sep 17 00:00:00 2001 From: saridsa2 Date: Wed, 18 Mar 2026 12:42:43 +0530 Subject: [PATCH] =?UTF-8?q?feat:=20complete=20data=20seeder=20=E2=80=94=20?= =?UTF-8?q?5=20patient=20stories=20with=20linked=20campaigns,=20patients,?= =?UTF-8?q?=20leads,=20appointments,=20calls,=20activities,=20follow-ups?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/seed-data.ts | 407 +++++++++++++++++++++++++------------------ 1 file changed, 238 insertions(+), 169 deletions(-) diff --git a/scripts/seed-data.ts b/scripts/seed-data.ts index 2617ac4..c70126f 100644 --- a/scripts/seed-data.ts +++ b/scripts/seed-data.ts @@ -1,250 +1,319 @@ /** - * Seed script for Helix Engage — populates the platform with realistic demo data. + * Helix Engage — Platform Data Seeder + * Creates 5 patient stories with fully linked records. + * Run: cd helix-engage && npx tsx scripts/seed-data.ts * - * Field name mapping (SDK → Platform): + * Platform field mapping (SDK name → platform name): * Campaign: campaignType→typeCustom, campaignStatus→status, impressionCount→impressions, * clickCount→clicks, contactedCount→contacted, convertedCount→converted, leadCount→leadsGenerated - * Lead: leadSource→source, leadStatus→status, landingPageUrl→landingPage, - * firstContactedAt→firstContacted, lastContactedAt→lastContacted - * Call: callDirection→direction, durationSeconds→durationSec, recordingUrl→recording + * Lead: leadSource→source, leadStatus→status, firstContactedAt→firstContacted, + * lastContactedAt→lastContacted, landingPageUrl→landingPage + * Call: callDirection→direction, durationSeconds→durationSec * Appointment: durationMinutes→durationMin, appointmentStatus→status, roomNumber→room - * LeadActivity: durationSeconds→durationSec, activityNotes→notes - * FollowUp: followUpType→typeCustom, followUpStatus→status, followUpNotes→notes - * - * Run: cd helix-engage && npx tsx scripts/seed-data.ts + * FollowUp: followUpType→typeCustom, followUpStatus→status + * Patient: address→addressCustom + * NOTE: callNotes/visitNotes are RICH_TEXT — read-only, cannot seed */ -const GRAPHQL_URL = 'http://localhost:4000/graphql'; -const WORKSPACE_SUBDOMAIN = 'fortytwo-dev'; +const GQL = 'http://localhost:4000/graphql'; +const SUB = 'fortytwo-dev'; const ORIGIN = 'http://fortytwo-dev.localhost:4010'; -const EMAIL = 'dev@fortytwo.dev'; -const PASSWORD = 'tim@apple.dev'; - -function daysAgo(n: number): string { - const d = new Date(); d.setDate(d.getDate() - n); return d.toISOString(); -} -function daysFromNow(n: number, hour = 10): string { - const d = new Date(); d.setDate(d.getDate() + n); d.setHours(hour, 0, 0, 0); return d.toISOString(); -} -function hoursAgo(n: number): string { - const d = new Date(); d.setHours(d.getHours() - n); return d.toISOString(); -} let token = ''; -async function gql(query: string, variables?: Record): Promise { - const headers: Record = { - 'Content-Type': 'application/json', - 'X-Workspace-Subdomain': WORKSPACE_SUBDOMAIN, - }; - if (token) headers['Authorization'] = `Bearer ${token}`; - const res = await fetch(GRAPHQL_URL, { method: 'POST', headers, body: JSON.stringify({ query, variables }) }); - const data = await res.json(); - if (data.errors) { - console.error('GraphQL error:', JSON.stringify(data.errors[0], null, 2)); - throw new Error(data.errors[0]?.message ?? 'GraphQL error'); - } - return data.data; +function ago(days: number, hours = 0): string { + const d = new Date(); + d.setDate(d.getDate() - days); + d.setHours(d.getHours() - hours); + return d.toISOString(); } -async function refreshToken() { - const d1 = await gql(`mutation { getLoginTokenFromCredentials(email: "${EMAIL}", password: "${PASSWORD}", origin: "${ORIGIN}") { loginToken { token } } }`); +function future(days: number, hour = 10): string { + const d = new Date(); + d.setDate(d.getDate() + days); + d.setHours(hour, 0, 0, 0); + return d.toISOString(); +} + +async function gql(query: string, variables?: any) { + const h: Record = { 'Content-Type': 'application/json', 'X-Workspace-Subdomain': SUB }; + if (token) h['Authorization'] = `Bearer ${token}`; + const r = await fetch(GQL, { method: 'POST', headers: h, body: JSON.stringify({ query, variables }) }); + const d: any = await r.json(); + if (d.errors) { console.error('❌', d.errors[0].message); throw new Error(d.errors[0].message); } + return d.data; +} + +async function auth() { + const d1 = await gql(`mutation { getLoginTokenFromCredentials(email: "dev@fortytwo.dev", password: "tim@apple.dev", origin: "${ORIGIN}") { loginToken { token } } }`); const lt = d1.getLoginTokenFromCredentials.loginToken.token; const d2 = await gql(`mutation { getAuthTokensFromLoginToken(loginToken: "${lt}", origin: "${ORIGIN}") { tokens { accessOrWorkspaceAgnosticToken { token } } } }`); token = d2.getAuthTokensFromLoginToken.tokens.accessOrWorkspaceAgnosticToken.token; } -async function create(entity: string, data: Record): Promise { - const cap = entity.charAt(0).toUpperCase() + entity.slice(1); - const result = await gql(`mutation Create($data: ${cap}CreateInput!) { create${cap}(data: $data) { id } }`, { data }); - return result[`create${cap}`].id; +async function mk(entity: string, data: any): Promise { + const cap = entity[0].toUpperCase() + entity.slice(1); + const d = await gql(`mutation($data: ${cap}CreateInput!) { create${cap}(data: $data) { id } }`, { data }); + return d[`create${cap}`].id; } async function main() { - console.log('🌱 Starting Helix Engage data seed...\n'); + console.log('🌱 Seeding Helix Engage demo data...\n'); + await auth(); + console.log('✅ Auth OK\n'); - await refreshToken(); - console.log('✅ Authenticated\n'); - - // === CAMPAIGNS === - console.log('📢 Campaigns...'); - const wdId = await create('campaign', { - campaignName: "Women's Day Health Checkup", status: 'ACTIVE', platform: 'FACEBOOK', - startDate: daysAgo(14), endDate: daysFromNow(16), - budget: { amountMicros: 200000000000, currencyCode: 'INR' }, - amountSpent: { amountMicros: 130000000000, currencyCode: 'INR' }, + // ═══════════════ CAMPAIGNS ═══════════════ + console.log('📢 Campaigns'); + const wdCamp = await mk('campaign', { + name: "Women's Day Health Checkup", + campaignName: "Women's Day Health Checkup", + status: 'ACTIVE', platform: 'FACEBOOK', + startDate: ago(14), endDate: future(16), + budget: { amountMicros: 200_000_000_000, currencyCode: 'INR' }, + amountSpent: { amountMicros: 130_000_000_000, currencyCode: 'INR' }, impressions: 82000, clicks: 2100, targetCount: 500, contacted: 89, converted: 24, leadsGenerated: 148, externalCampaignId: 'fb_camp_28491', }); - console.log(` ✅ Women's Day: ${wdId}`); + console.log(` Women's Day: ${wdCamp}`); - const csId = await create('campaign', { - campaignName: 'Cervical Cancer Screening Drive', status: 'ACTIVE', platform: 'GOOGLE', - startDate: daysAgo(10), endDate: daysFromNow(28), - budget: { amountMicros: 150000000000, currencyCode: 'INR' }, - amountSpent: { amountMicros: 57500000000, currencyCode: 'INR' }, + const csCamp = await mk('campaign', { + name: 'Cervical Cancer Screening Drive', + campaignName: 'Cervical Cancer Screening Drive', + status: 'ACTIVE', platform: 'GOOGLE', + startDate: ago(10), endDate: future(28), + budget: { amountMicros: 150_000_000_000, currencyCode: 'INR' }, + amountSpent: { amountMicros: 57_500_000_000, currencyCode: 'INR' }, impressions: 45000, clicks: 1300, targetCount: 300, contacted: 31, converted: 8, leadsGenerated: 56, externalCampaignId: 'ggl_camp_44102', }); - console.log(` ✅ Cervical Screening: ${csId}`); + console.log(` Cervical Screening: ${csCamp}`); - const ivfId = await create('campaign', { - campaignName: 'IVF Consultation — Free First Visit', status: 'ACTIVE', platform: 'FACEBOOK', - startDate: daysAgo(23), endDate: daysFromNow(13), - budget: { amountMicros: 300000000000, currencyCode: 'INR' }, - amountSpent: { amountMicros: 246000000000, currencyCode: 'INR' }, + const ivfCamp = await mk('campaign', { + name: 'IVF Consultation — Free First Visit', + campaignName: 'IVF Consultation — Free First Visit', + status: 'ACTIVE', platform: 'FACEBOOK', + startDate: ago(23), endDate: future(13), + budget: { amountMicros: 300_000_000_000, currencyCode: 'INR' }, + amountSpent: { amountMicros: 246_000_000_000, currencyCode: 'INR' }, impressions: 156000, clicks: 4200, targetCount: 500, contacted: 198, converted: 52, leadsGenerated: 312, externalCampaignId: 'fb_camp_28555', }); - console.log(` ✅ IVF: ${ivfId}\n`); + console.log(` IVF: ${ivfCamp}\n`); - // Refresh token (short-lived JWT) - await refreshToken(); + await auth(); - // === LEADS === - console.log('👥 Leads...'); - const priyaId = await create('lead', { + // ═══════════════ PATIENTS ═══════════════ + console.log('🏥 Patients'); + const priyaPatient = await mk('patient', { + name: 'Priya Sharma', + fullName: { firstName: 'Priya', lastName: 'Sharma' }, + phones: { primaryPhoneNumber: '9949879837', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' }, + emails: { primaryEmail: 'priya.sharma@gmail.com' }, + dateOfBirth: '1994-05-15', + gender: 'FEMALE', + patientType: 'RETURNING', + }); + console.log(` Priya Sharma (IVF, returning): ${priyaPatient}`); + + const deepaPatient = await mk('patient', { + name: 'Deepa Rao', + fullName: { firstName: 'Deepa', lastName: 'Rao' }, + phones: { primaryPhoneNumber: '7654321098', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' }, + dateOfBirth: '1997-08-22', + gender: 'FEMALE', + patientType: 'NEW', + }); + console.log(` Deepa Rao (IVF, new): ${deepaPatient}`); + + const vijayPatient = await mk('patient', { + name: 'Vijay Nair', + fullName: { firstName: 'Vijay', lastName: 'Nair' }, + phones: { primaryPhoneNumber: '6543210987', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' }, + emails: { primaryEmail: 'vijay.n@gmail.com' }, + dateOfBirth: '1971-02-10', + gender: 'MALE', + patientType: 'RETURNING', + }); + console.log(` Vijay Nair (cardiology, regular): ${vijayPatient}\n`); + + await auth(); + + // ═══════════════ LEADS ═══════════════ + console.log('👥 Leads'); + + // Story 1: Priya — returning IVF patient (demo phone: 9949879837) + const priyaLead = await mk('lead', { + name: 'Priya Sharma', contactName: { firstName: 'Priya', lastName: 'Sharma' }, - contactPhone: { primaryPhoneNumber: '9876543210', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' }, + contactPhone: { primaryPhoneNumber: '9949879837', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' }, contactEmail: { primaryEmail: 'priya.sharma@gmail.com' }, source: 'FACEBOOK_AD', status: 'APPOINTMENT_SET', interestedService: 'IVF Consultation', assignedAgent: 'Rekha CC', spamScore: 5, isSpam: false, isDuplicate: false, - firstContacted: daysAgo(12), lastContacted: daysAgo(2), contactAttempts: 3, leadScore: 92, - aiSummary: 'Returning IVF patient. Had first consultation with Dr. Patel last week. Next appointment scheduled in 3 days. Very responsive — all calls answered.', + firstContacted: ago(12), lastContacted: ago(2), contactAttempts: 3, leadScore: 92, + aiSummary: 'Returning IVF patient. Had first consultation with Dr. Patel last week. Next appointment in 3 days. Very responsive — all 3 calls answered. Interested in premium IVF package.', aiSuggestedAction: 'Confirm upcoming appointment and discuss treatment timeline', - campaignId: ivfId, utmSource: 'facebook', utmMedium: 'paid', utmCampaign: 'ivf-free-consult', + campaignId: ivfCamp, patientId: priyaPatient, + utmSource: 'facebook', utmMedium: 'paid', utmCampaign: 'ivf-free-consult', }); - console.log(` ✅ Priya Sharma: ${priyaId}`); + console.log(` Priya Sharma (IVF, phone: 9949879837): ${priyaLead}`); - const raviId = await create('lead', { + // Story 2: Ravi — missed call, SLA breached (demo phone: 6309248884) + const raviLead = await mk('lead', { + name: 'Ravi Kumar', contactName: { firstName: 'Ravi', lastName: 'Kumar' }, - contactPhone: { primaryPhoneNumber: '8765432109', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' }, + contactPhone: { primaryPhoneNumber: '6309248884', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' }, contactEmail: { primaryEmail: 'ravi.k@yahoo.com' }, source: 'GOOGLE_AD', status: 'NEW', interestedService: 'Cervical Screening', assignedAgent: 'Rekha CC', spamScore: 8, isSpam: false, contactAttempts: 0, leadScore: 75, - aiSummary: 'New lead from Google Ads cervical screening campaign. Missed call yesterday — no callback yet. SLA breached.', + aiSummary: 'New lead from Google Ads cervical screening campaign. Missed call 18 hours ago — no callback. SLA breached. Urgent follow-up required.', aiSuggestedAction: 'Urgent callback — missed call SLA breached', - campaignId: csId, utmSource: 'google', utmMedium: 'paid', + campaignId: csCamp, utmSource: 'google', utmMedium: 'paid', }); - console.log(` ✅ Ravi Kumar: ${raviId}`); + console.log(` Ravi Kumar (missed call, phone: 6309248884): ${raviLead}`); - const deepaId = await create('lead', { + // Story 3: Deepa — walk-in converted + const deepaLead = await mk('lead', { + name: 'Deepa Rao', contactName: { firstName: 'Deepa', lastName: 'Rao' }, contactPhone: { primaryPhoneNumber: '7654321098', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' }, source: 'WALK_IN', status: 'CONVERTED', interestedService: 'IVF Package', - assignedAgent: 'Rekha CC', convertedAt: daysAgo(2), firstContacted: daysAgo(7), - lastContacted: daysAgo(2), contactAttempts: 2, leadScore: 88, - aiSummary: 'Walk-in converted to IVF patient. Completed first consultation with Dr. Patel 2 days ago.', + assignedAgent: 'Rekha CC', convertedAt: ago(2), firstContacted: ago(7), + lastContacted: ago(2), contactAttempts: 2, leadScore: 88, + aiSummary: 'Walk-in converted to IVF patient. Completed first consultation with Dr. Patel 2 days ago. Interested in premium IVF package.', aiSuggestedAction: 'Follow up on treatment plan discussion', - campaignId: ivfId, + campaignId: ivfCamp, patientId: deepaPatient, }); - console.log(` ✅ Deepa Rao: ${deepaId}`); + console.log(` Deepa Rao (converted walk-in): ${deepaLead}`); - const vijayId = await create('lead', { + // Story 4: Vijay — multi-visit cardiology + const vijayLead = await mk('lead', { + name: 'Vijay Nair', contactName: { firstName: 'Vijay', lastName: 'Nair' }, contactPhone: { primaryPhoneNumber: '6543210987', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' }, contactEmail: { primaryEmail: 'vijay.n@gmail.com' }, source: 'REFERRAL', status: 'APPOINTMENT_SET', interestedService: 'Cardiology Consultation', - assignedAgent: 'Rekha CC', firstContacted: daysAgo(20), lastContacted: daysAgo(3), + assignedAgent: 'Rekha CC', firstContacted: ago(20), lastContacted: ago(3), contactAttempts: 4, leadScore: 85, - aiSummary: 'Regular cardiology patient under Dr. Sharma. 2 completed visits. Has upcoming appointment. Cancelled once before.', + aiSummary: 'Regular cardiology patient under Dr. Sharma. 2 completed visits, good outcomes. Upcoming quarterly check-up in 5 days. Cancelled once before — confirm proactively.', aiSuggestedAction: 'Confirm upcoming appointment — previous cancellation history', + patientId: vijayPatient, }); - console.log(` ✅ Vijay Nair: ${vijayId}`); + console.log(` Vijay Nair (cardiology regular): ${vijayLead}`); - const kavithaId = await create('lead', { + // Story 5: Kavitha — fresh lead today + const kavithaLead = await mk('lead', { + name: 'Kavitha S', contactName: { firstName: 'Kavitha', lastName: 'S' }, - contactPhone: { primaryPhoneNumber: '9949879837', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' }, + contactPhone: { primaryPhoneNumber: '9845123456', primaryPhoneCallingCode: '+91', primaryPhoneCountryCode: 'IN' }, source: 'FACEBOOK_AD', status: 'NEW', interestedService: "Women's Health Checkup", spamScore: 3, isSpam: false, contactAttempts: 0, leadScore: 80, - aiSummary: "Brand new lead from today's Women's Day campaign. No contact yet.", + aiSummary: "Brand new lead from today's Women's Day Facebook campaign. Complete details provided. No contact yet.", aiSuggestedAction: 'Send WhatsApp template and assign to call center', - campaignId: wdId, utmSource: 'facebook', utmMedium: 'paid', + campaignId: wdCamp, utmSource: 'facebook', utmMedium: 'paid', }); - console.log(` ✅ Kavitha S: ${kavithaId}\n`); + console.log(` Kavitha S (fresh lead): ${kavithaLead}\n`); - await refreshToken(); + await auth(); - // === APPOINTMENTS === - console.log('📅 Appointments...'); - await create('appointment', { scheduledAt: daysAgo(5), durationMin: 30, appointmentType: 'CONSULTATION', status: 'COMPLETED', doctorName: 'Dr. Patel', department: 'Gynecology', reasonForVisit: 'IVF initial consultation' }); - console.log(' ✅ Priya completed'); - await create('appointment', { scheduledAt: daysFromNow(3, 10), durationMin: 45, appointmentType: 'FOLLOW_UP', status: 'SCHEDULED', doctorName: 'Dr. Patel', department: 'Gynecology', reasonForVisit: 'IVF follow-up — treatment plan' }); - console.log(' ✅ Priya upcoming'); - await create('appointment', { scheduledAt: daysAgo(2), durationMin: 30, appointmentType: 'CONSULTATION', status: 'COMPLETED', doctorName: 'Dr. Patel', department: 'Gynecology', reasonForVisit: 'IVF package consultation — walk-in' }); - console.log(' ✅ Deepa completed'); - await create('appointment', { scheduledAt: daysAgo(14), durationMin: 30, appointmentType: 'CONSULTATION', status: 'COMPLETED', doctorName: 'Dr. Sharma', department: 'Cardiology', reasonForVisit: 'Initial cardiology assessment' }); - console.log(' ✅ Vijay initial'); - await create('appointment', { scheduledAt: daysAgo(7), durationMin: 30, appointmentType: 'FOLLOW_UP', status: 'COMPLETED', doctorName: 'Dr. Sharma', department: 'Cardiology', reasonForVisit: 'Echocardiogram review' }); - console.log(' ✅ Vijay follow-up'); - await create('appointment', { scheduledAt: daysFromNow(5, 11), durationMin: 30, appointmentType: 'FOLLOW_UP', status: 'SCHEDULED', doctorName: 'Dr. Sharma', department: 'Cardiology', reasonForVisit: 'Quarterly check-up' }); - console.log(' ✅ Vijay upcoming\n'); + // ═══════════════ APPOINTMENTS (linked to patients) ═══════════════ + console.log('📅 Appointments'); + await mk('appointment', { name: 'Priya — IVF Consultation', scheduledAt: ago(5), durationMin: 30, appointmentType: 'CONSULTATION', status: 'COMPLETED', doctorName: 'Dr. Patel', department: 'Gynecology', reasonForVisit: 'IVF initial consultation — fertility assessment', patientId: priyaPatient }); + console.log(' Priya — completed IVF consultation (5d ago)'); + await mk('appointment', { name: 'Priya — IVF Follow-up', scheduledAt: future(3, 10), durationMin: 45, appointmentType: 'FOLLOW_UP', status: 'SCHEDULED', doctorName: 'Dr. Patel', department: 'Gynecology', reasonForVisit: 'IVF follow-up — treatment plan discussion', patientId: priyaPatient }); + console.log(' Priya — upcoming IVF follow-up (in 3d)'); + await mk('appointment', { name: 'Deepa — IVF Consultation', scheduledAt: ago(2), durationMin: 30, appointmentType: 'CONSULTATION', status: 'COMPLETED', doctorName: 'Dr. Patel', department: 'Gynecology', reasonForVisit: 'IVF package consultation — walk-in referral', patientId: deepaPatient }); + console.log(' Deepa — completed IVF consultation (2d ago)'); + await mk('appointment', { name: 'Vijay — Cardiology Initial', scheduledAt: ago(14), durationMin: 30, appointmentType: 'CONSULTATION', status: 'COMPLETED', doctorName: 'Dr. Sharma', department: 'Cardiology', reasonForVisit: 'Initial assessment — chest discomfort, family history', patientId: vijayPatient }); + console.log(' Vijay — completed initial cardiology (14d ago)'); + await mk('appointment', { name: 'Vijay — Echo Review', scheduledAt: ago(7), durationMin: 30, appointmentType: 'FOLLOW_UP', status: 'COMPLETED', doctorName: 'Dr. Sharma', department: 'Cardiology', reasonForVisit: 'Echocardiogram review — all clear', patientId: vijayPatient }); + console.log(' Vijay — completed echo review (7d ago)'); + await mk('appointment', { name: 'Vijay — Quarterly Check-up', scheduledAt: future(5, 11), durationMin: 30, appointmentType: 'FOLLOW_UP', status: 'SCHEDULED', doctorName: 'Dr. Sharma', department: 'Cardiology', reasonForVisit: 'Quarterly cardiology check-up', patientId: vijayPatient }); + console.log(' Vijay — upcoming quarterly (in 5d)\n'); - await refreshToken(); + await auth(); - // === CALLS === - console.log('📞 Calls...'); - await create('call', { direction: 'INBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: daysAgo(12), endedAt: daysAgo(12), durationSec: 240, disposition: 'INFO_PROVIDED', leadId: priyaId }); - console.log(' ✅ Priya enquiry'); - await create('call', { direction: 'OUTBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: daysAgo(6), endedAt: daysAgo(6), durationSec: 180, disposition: 'APPOINTMENT_BOOKED', leadId: priyaId }); - console.log(' ✅ Priya booked'); - await create('call', { direction: 'OUTBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: daysAgo(2), endedAt: daysAgo(2), durationSec: 120, disposition: 'FOLLOW_UP_SCHEDULED', leadId: priyaId }); - console.log(' ✅ Priya reminder'); - await create('call', { direction: 'INBOUND', callStatus: 'MISSED', agentName: 'Rekha CC', startedAt: hoursAgo(18), durationSec: 0, leadId: raviId }); - console.log(' ✅ Ravi missed'); - await create('call', { direction: 'INBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: daysAgo(7), endedAt: daysAgo(7), durationSec: 300, disposition: 'INFO_PROVIDED', leadId: deepaId }); - console.log(' ✅ Deepa enquiry'); - await create('call', { direction: 'OUTBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: daysAgo(3), endedAt: daysAgo(3), durationSec: 150, disposition: 'APPOINTMENT_BOOKED', leadId: deepaId }); - console.log(' ✅ Deepa booked'); - await create('call', { direction: 'INBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: daysAgo(20), endedAt: daysAgo(20), durationSec: 210, disposition: 'APPOINTMENT_BOOKED', leadId: vijayId }); - console.log(' ✅ Vijay initial'); - await create('call', { direction: 'OUTBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: daysAgo(10), endedAt: daysAgo(10), durationSec: 90, disposition: 'FOLLOW_UP_SCHEDULED', leadId: vijayId }); - console.log(' ✅ Vijay follow-up'); - await create('call', { direction: 'OUTBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: daysAgo(5), endedAt: daysAgo(5), durationSec: 0, disposition: 'NO_ANSWER', leadId: vijayId }); - console.log(' ✅ Vijay no-answer'); - await create('call', { direction: 'OUTBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: daysAgo(3), endedAt: daysAgo(3), durationSec: 180, disposition: 'APPOINTMENT_BOOKED', leadId: vijayId }); - console.log(' ✅ Vijay confirmed\n'); + // ═══════════════ CALLS (linked to leads) ═══════════════ + console.log('📞 Calls'); + // Priya: 3 calls + await mk('call', { name: 'Priya — IVF Enquiry', direction: 'INBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: ago(12), endedAt: ago(12), durationSec: 240, disposition: 'INFO_PROVIDED', leadId: priyaLead }); + console.log(' Priya — inbound enquiry (12d ago)'); + await mk('call', { name: 'Priya — Appt Booked', direction: 'OUTBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: ago(6), endedAt: ago(6), durationSec: 180, disposition: 'APPOINTMENT_BOOKED', leadId: priyaLead }); + console.log(' Priya — outbound, booked appointment (6d ago)'); + await mk('call', { name: 'Priya — Reminder', direction: 'OUTBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: ago(2), endedAt: ago(2), durationSec: 120, disposition: 'FOLLOW_UP_SCHEDULED', leadId: priyaLead }); + console.log(' Priya — outbound reminder (2d ago)'); - await refreshToken(); + // Ravi: 1 missed + await mk('call', { name: 'Ravi — Missed Call', direction: 'INBOUND', callStatus: 'MISSED', agentName: 'Rekha CC', startedAt: ago(0, 18), durationSec: 0, leadId: raviLead }); + console.log(' Ravi — missed inbound (18h ago)'); - // === LEAD ACTIVITIES === - console.log('📋 Activities...'); - const acts = [ - { activityType: 'STATUS_CHANGE', summary: 'Lead created from Facebook Ad — IVF campaign', occurredAt: daysAgo(14), performedBy: 'System', channel: 'SYSTEM', leadId: priyaId }, - { activityType: 'ASSIGNED', summary: 'Auto-assigned to Rekha CC', occurredAt: daysAgo(14), performedBy: 'System', channel: 'SYSTEM', newValue: 'Rekha CC', leadId: priyaId }, - { activityType: 'WHATSAPP_SENT', summary: 'IVF consultation template sent', occurredAt: daysAgo(13), performedBy: 'Sanjay Marketing', channel: 'WHATSAPP', leadId: priyaId }, - { activityType: 'CALL_RECEIVED', summary: 'Enquired about IVF costs and process', occurredAt: daysAgo(12), performedBy: 'Rekha CC', channel: 'PHONE', leadId: priyaId }, - { activityType: 'STATUS_CHANGE', summary: 'NEW → CONTACTED', occurredAt: daysAgo(12), performedBy: 'System', channel: 'SYSTEM', previousValue: 'NEW', newValue: 'CONTACTED', leadId: priyaId }, - { activityType: 'APPOINTMENT_BOOKED', summary: 'Booked with Dr. Patel — IVF consultation', occurredAt: daysAgo(6), performedBy: 'Rekha CC', channel: 'PHONE', leadId: priyaId }, - { activityType: 'STATUS_CHANGE', summary: 'CONTACTED → APPOINTMENT_SET', occurredAt: daysAgo(6), performedBy: 'System', channel: 'SYSTEM', previousValue: 'CONTACTED', newValue: 'APPOINTMENT_SET', leadId: priyaId }, - { activityType: 'NOTE_ADDED', summary: 'Patient confirmed follow-up attendance', occurredAt: daysAgo(2), performedBy: 'Rekha CC', channel: 'PHONE', leadId: priyaId }, - { activityType: 'STATUS_CHANGE', summary: 'Lead from Google Ad — cervical screening', occurredAt: daysAgo(3), performedBy: 'System', channel: 'SYSTEM', leadId: raviId }, - { activityType: 'ASSIGNED', summary: 'Assigned to Rekha CC', occurredAt: daysAgo(3), performedBy: 'System', channel: 'SYSTEM', leadId: raviId }, - { activityType: 'CALL_RECEIVED', summary: 'Missed call — all agents busy', occurredAt: hoursAgo(18), performedBy: 'System', channel: 'PHONE', leadId: raviId }, - { activityType: 'STATUS_CHANGE', summary: 'Walk-in enquiry created', occurredAt: daysAgo(7), performedBy: 'System', channel: 'IN_PERSON', leadId: deepaId }, - { activityType: 'CALL_RECEIVED', summary: 'IVF package enquiry', occurredAt: daysAgo(7), performedBy: 'Rekha CC', channel: 'PHONE', leadId: deepaId }, - { activityType: 'APPOINTMENT_BOOKED', summary: 'Booked IVF consultation with Dr. Patel', occurredAt: daysAgo(3), performedBy: 'Rekha CC', channel: 'PHONE', leadId: deepaId }, - { activityType: 'CONVERTED', summary: 'Completed first IVF consultation', occurredAt: daysAgo(2), performedBy: 'System', channel: 'SYSTEM', leadId: deepaId }, - { activityType: 'STATUS_CHANGE', summary: 'Referral lead — family doctor', occurredAt: daysAgo(21), performedBy: 'System', channel: 'SYSTEM', leadId: vijayId }, - { activityType: 'APPOINTMENT_BOOKED', summary: 'Cardiology consultation with Dr. Sharma', occurredAt: daysAgo(20), performedBy: 'Rekha CC', channel: 'PHONE', leadId: vijayId }, - { activityType: 'NOTE_ADDED', summary: 'Family history of cardiac issues. Echo ordered.', occurredAt: daysAgo(14), performedBy: 'Rekha CC', channel: 'SYSTEM', leadId: vijayId }, - { activityType: 'NOTE_ADDED', summary: 'Cancelled once — rescheduled', occurredAt: daysAgo(8), performedBy: 'Rekha CC', channel: 'PHONE', leadId: vijayId }, - { activityType: 'STATUS_CHANGE', summary: "New from Women's Day FB campaign", occurredAt: hoursAgo(2), performedBy: 'System', channel: 'SYSTEM', leadId: kavithaId }, + // Deepa: 2 calls + await mk('call', { name: 'Deepa — Walk-in Enquiry', direction: 'INBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: ago(7), endedAt: ago(7), durationSec: 300, disposition: 'INFO_PROVIDED', leadId: deepaLead }); + console.log(' Deepa — inbound IVF enquiry (7d ago)'); + await mk('call', { name: 'Deepa — Appt Booked', direction: 'OUTBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: ago(3), endedAt: ago(3), durationSec: 150, disposition: 'APPOINTMENT_BOOKED', leadId: deepaLead }); + console.log(' Deepa — outbound, booked (3d ago)'); + + // Vijay: 4 calls + await mk('call', { name: 'Vijay — Referral Call', direction: 'INBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: ago(20), endedAt: ago(20), durationSec: 210, disposition: 'APPOINTMENT_BOOKED', leadId: vijayLead }); + console.log(' Vijay — inbound referral (20d ago)'); + await mk('call', { name: 'Vijay — Follow-up Scheduled', direction: 'OUTBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: ago(10), endedAt: ago(10), durationSec: 90, disposition: 'FOLLOW_UP_SCHEDULED', leadId: vijayLead }); + console.log(' Vijay — follow-up call (10d ago)'); + await mk('call', { name: 'Vijay — No Answer', direction: 'OUTBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: ago(5), endedAt: ago(5), durationSec: 0, disposition: 'NO_ANSWER', leadId: vijayLead }); + console.log(' Vijay — no answer (5d ago)'); + await mk('call', { name: 'Vijay — Quarterly Confirmed', direction: 'OUTBOUND', callStatus: 'COMPLETED', agentName: 'Rekha CC', startedAt: ago(3), endedAt: ago(3), durationSec: 180, disposition: 'APPOINTMENT_BOOKED', leadId: vijayLead }); + console.log(' Vijay — quarterly confirmed (3d ago)\n'); + + await auth(); + + // ═══════════════ LEAD ACTIVITIES ═══════════════ + console.log('📋 Activities'); + const acts: any[] = [ + // Priya journey + { name: 'Lead created', activityType: 'STATUS_CHANGE', summary: 'Lead created from Facebook IVF campaign', occurredAt: ago(14), performedBy: 'System', channel: 'SYSTEM', leadId: priyaLead }, + { name: 'Assigned', activityType: 'ASSIGNED', summary: 'Auto-assigned to Rekha CC via round-robin', occurredAt: ago(14), performedBy: 'System', channel: 'SYSTEM', newValue: 'Rekha CC', leadId: priyaLead }, + { name: 'WhatsApp sent', activityType: 'WHATSAPP_SENT', summary: 'IVF consultation template sent via WhatsApp', occurredAt: ago(13), performedBy: 'Sanjay Marketing', channel: 'WHATSAPP', leadId: priyaLead }, + { name: 'Enquiry call', activityType: 'CALL_RECEIVED', summary: 'Inbound call — enquired about IVF costs and process', occurredAt: ago(12), performedBy: 'Rekha CC', channel: 'PHONE', leadId: priyaLead }, + { name: 'Status → CONTACTED', activityType: 'STATUS_CHANGE', summary: 'NEW → CONTACTED', occurredAt: ago(12), performedBy: 'System', channel: 'SYSTEM', previousValue: 'NEW', newValue: 'CONTACTED', leadId: priyaLead }, + { name: 'Appt booked', activityType: 'APPOINTMENT_BOOKED', summary: 'Booked IVF consultation with Dr. Patel', occurredAt: ago(6), performedBy: 'Rekha CC', channel: 'PHONE', leadId: priyaLead }, + { name: 'Status → APPOINTMENT_SET', activityType: 'STATUS_CHANGE', summary: 'CONTACTED → APPOINTMENT_SET', occurredAt: ago(6), performedBy: 'System', channel: 'SYSTEM', previousValue: 'CONTACTED', newValue: 'APPOINTMENT_SET', leadId: priyaLead }, + { name: 'Confirmed', activityType: 'NOTE_ADDED', summary: 'Patient confirmed attendance for follow-up. Interested in premium IVF package.', occurredAt: ago(2), performedBy: 'Rekha CC', channel: 'PHONE', leadId: priyaLead }, + + // Ravi journey + { name: 'Lead created', activityType: 'STATUS_CHANGE', summary: 'Lead created from Google cervical screening campaign', occurredAt: ago(3), performedBy: 'System', channel: 'SYSTEM', leadId: raviLead }, + { name: 'Assigned', activityType: 'ASSIGNED', summary: 'Assigned to Rekha CC', occurredAt: ago(3), performedBy: 'System', channel: 'SYSTEM', newValue: 'Rekha CC', leadId: raviLead }, + { name: 'Missed call', activityType: 'CALL_RECEIVED', summary: 'Missed inbound call — all agents busy', occurredAt: ago(0, 18), performedBy: 'System', channel: 'PHONE', leadId: raviLead }, + + // Deepa journey + { name: 'Walk-in created', activityType: 'STATUS_CHANGE', summary: 'Walk-in enquiry lead created', occurredAt: ago(7), performedBy: 'System', channel: 'IN_PERSON', leadId: deepaLead }, + { name: 'IVF enquiry', activityType: 'CALL_RECEIVED', summary: 'Walk-in enquiry — interested in IVF packages', occurredAt: ago(7), performedBy: 'Rekha CC', channel: 'PHONE', leadId: deepaLead }, + { name: 'Appt booked', activityType: 'APPOINTMENT_BOOKED', summary: 'Booked IVF consultation with Dr. Patel', occurredAt: ago(3), performedBy: 'Rekha CC', channel: 'PHONE', leadId: deepaLead }, + { name: 'Converted', activityType: 'CONVERTED', summary: 'Completed first IVF consultation — converted', occurredAt: ago(2), performedBy: 'System', channel: 'SYSTEM', leadId: deepaLead }, + + // Vijay journey + { name: 'Referral created', activityType: 'STATUS_CHANGE', summary: 'Referral lead — family doctor recommended cardiology check', occurredAt: ago(21), performedBy: 'System', channel: 'SYSTEM', leadId: vijayLead }, + { name: 'Initial booked', activityType: 'APPOINTMENT_BOOKED', summary: 'Cardiology consultation with Dr. Sharma booked', occurredAt: ago(20), performedBy: 'Rekha CC', channel: 'PHONE', leadId: vijayLead }, + { name: 'Clinical note', activityType: 'NOTE_ADDED', summary: 'Family history of cardiac issues. Dr. Sharma ordered echocardiogram.', occurredAt: ago(14), performedBy: 'Rekha CC', channel: 'SYSTEM', leadId: vijayLead }, + { name: 'Follow-up booked', activityType: 'APPOINTMENT_BOOKED', summary: 'Echo review follow-up booked with Dr. Sharma', occurredAt: ago(10), performedBy: 'Rekha CC', channel: 'PHONE', leadId: vijayLead }, + { name: 'Cancellation note', activityType: 'NOTE_ADDED', summary: 'Patient cancelled echo review once — successfully rescheduled', occurredAt: ago(8), performedBy: 'Rekha CC', channel: 'PHONE', leadId: vijayLead }, + { name: 'Quarterly confirmed', activityType: 'APPOINTMENT_BOOKED', summary: 'Quarterly cardiology check-up confirmed', occurredAt: ago(3), performedBy: 'Rekha CC', channel: 'PHONE', leadId: vijayLead }, + + // Kavitha + { name: 'Lead created', activityType: 'STATUS_CHANGE', summary: "New lead from Women's Day Facebook campaign", occurredAt: ago(0, 2), performedBy: 'System', channel: 'SYSTEM', leadId: kavithaLead }, ]; - for (const a of acts) { await create('leadActivity', a); } - console.log(` ✅ ${acts.length} activities\n`); + for (const a of acts) await mk('leadActivity', a); + console.log(` ${acts.length} activities created\n`); - await refreshToken(); + await auth(); - // === FOLLOW-UPS === - console.log('🔔 Follow-ups...'); - await create('followUp', { typeCustom: 'CALLBACK', status: 'OVERDUE', scheduledAt: hoursAgo(6), assignedAgent: 'Rekha CC', priority: 'URGENT' }); - console.log(' ✅ Ravi overdue callback'); - await create('followUp', { typeCustom: 'APPOINTMENT_REMINDER', status: 'PENDING', scheduledAt: daysFromNow(1, 9), assignedAgent: 'Rekha CC', priority: 'HIGH' }); - console.log(' ✅ Vijay appointment reminder\n'); + // ═══════════════ FOLLOW-UPS ═══════════════ + console.log('🔔 Follow-ups'); + await mk('followUp', { name: 'Ravi — Urgent Callback', typeCustom: 'CALLBACK', status: 'OVERDUE', scheduledAt: ago(0, 6), assignedAgent: 'Rekha CC', priority: 'URGENT' }); + console.log(' Ravi — overdue callback (6h ago, URGENT)'); + await mk('followUp', { name: 'Vijay — Appointment Reminder', typeCustom: 'APPOINTMENT_REMINDER', status: 'PENDING', scheduledAt: future(1, 9), assignedAgent: 'Rekha CC', priority: 'HIGH' }); + console.log(' Vijay — appointment reminder (tomorrow 9am)\n'); console.log('🎉 Seed complete!'); - console.log(' 3 campaigns, 5 leads, 6 appointments, 10 calls, 20 activities, 2 follow-ups'); + console.log(' 3 campaigns · 3 patients · 5 leads · 6 appointments · 10 calls · 22 activities · 2 follow-ups'); + console.log(' Demo phones: Priya=9949879837, Ravi=6309248884'); } -main().catch(e => { console.error('❌', e.message); process.exit(1); }); +main().catch(e => { console.error('💥', e.message); process.exit(1); });