/** * Demo Data Generator for ParentFlow * Generates realistic activity data for demo user's children from birth to present */ import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); // Child data from database const ALICE = { id: 'chd_xr7ymrde3vf0', name: 'Alice', birthDate: new Date('2020-07-09'), gender: 'female', ageMonths: 64, // ~5 years 4 months }; const ROBERT = { id: 'chd_8b58nlkopebg', name: 'Robert', birthDate: new Date('2025-02-04'), gender: 'male', ageMonths: 8, }; const FAMILY_ID = 'fam_vpusjt4fhsxu'; // Helper: Random between min and max const random = (min: number, max: number) => Math.floor(Math.random() * (max - min + 1)) + min; // Helper: Random choice from array const choice = (arr: T[]): T => arr[random(0, arr.length - 1)]; // Helper: Add days to date const addDays = (date: Date, days: number) => { const result = new Date(date); result.setDate(result.getDate() + days); return result; }; // Helper: Add hours to date const addHours = (date: Date, hours: number) => { const result = new Date(date); result.setHours(result.getHours() + hours); return result; }; // Helper: Add minutes to date const addMinutes = (date: Date, minutes: number) => { const result = new Date(date); result.setMinutes(result.getMinutes() + minutes); return result; }; // Generate feeding activities async function generateFeedingActivities(childId: string, birthDate: Date, ageMonths: number) { console.log(`Generating feeding activities for ${childId}...`); const activities = []; const today = new Date(); let currentDate = new Date(birthDate); while (currentDate < today) { const currentAgeMonths = Math.floor((currentDate.getTime() - birthDate.getTime()) / (1000 * 60 * 60 * 24 * 30)); // Feeding frequency changes with age let feedingsPerDay = 8; // Newborn if (currentAgeMonths >= 3) feedingsPerDay = 6; if (currentAgeMonths >= 6) feedingsPerDay = 5; if (currentAgeMonths >= 12) feedingsPerDay = 4; // 3 meals + 1 snack if (currentAgeMonths >= 24) feedingsPerDay = 4; // 3 meals + 1 snack for (let i = 0; i < feedingsPerDay; i++) { const hour = currentAgeMonths < 6 ? random(0, 23) // Newborns eat around the clock : [7, 10, 13, 17, 19][i] || random(8, 18); // Older kids have schedule const timestamp = new Date(currentDate); timestamp.setHours(hour, random(0, 59), 0, 0); let type = 'breast'; let amount = null; let duration = null; let notes = ''; if (currentAgeMonths < 6) { // 0-6 months: mainly breast/bottle type = choice(['breast', 'bottle']); if (type === 'breast') { duration = random(15, 40); // minutes } else { amount = random(60, 180); // ml } } else if (currentAgeMonths < 12) { // 6-12 months: introducing solids type = choice(['breast', 'bottle', 'solid', 'solid']); if (type === 'breast') { duration = random(10, 25); } else if (type === 'bottle') { amount = random(120, 240); } else { notes = choice(['Puréed vegetables', 'Banana mash', 'Rice cereal', 'Oatmeal', 'Puréed chicken', 'Sweet potato']); } } else { // 12+ months: mostly solids type = 'solid'; const meals = [ 'Scrambled eggs and toast', 'Oatmeal with berries', 'Yogurt and fruit', 'Mac and cheese', 'Chicken nuggets and veggies', 'Pasta with tomato sauce', 'Grilled cheese sandwich', 'Rice and beans', 'Fish sticks and peas', 'Pancakes', 'Quesadilla', 'Soup and crackers', ]; notes = choice(meals); } activities.push({ id: `act_feed_${childId}_${timestamp.getTime()}`, child_id: childId, family_id: FAMILY_ID, type: 'feeding', timestamp, data: { feedingType: type, amount, duration, side: type === 'breast' ? choice(['left', 'right', 'both']) : null, notes, }, created_at: timestamp, updated_at: timestamp, }); } currentDate = addDays(currentDate, 1); } return activities; } // Generate sleep activities async function generateSleepActivities(childId: string, birthDate: Date, ageMonths: number) { console.log(`Generating sleep activities for ${childId}...`); const activities = []; const today = new Date(); let currentDate = new Date(birthDate); while (currentDate < today) { const currentAgeMonths = Math.floor((currentDate.getTime() - birthDate.getTime()) / (1000 * 60 * 60 * 24 * 30)); // Sleep patterns change with age let napsPerDay = 4; // Newborn let nightSleepHours = 8; if (currentAgeMonths >= 3) { napsPerDay = 3; nightSleepHours = 10; } if (currentAgeMonths >= 6) { napsPerDay = 2; nightSleepHours = 11; } if (currentAgeMonths >= 12) { napsPerDay = 1; nightSleepHours = 11; } if (currentAgeMonths >= 18) { napsPerDay = 1; nightSleepHours = 11; } if (currentAgeMonths >= 36) { napsPerDay = 0; nightSleepHours = 10; } // Night sleep const bedtime = new Date(currentDate); bedtime.setHours(currentAgeMonths < 12 ? random(19, 21) : random(20, 22), random(0, 59), 0, 0); const wakeTime = addHours(bedtime, nightSleepHours + random(-1, 1)); activities.push({ id: `act_sleep_night_${childId}_${bedtime.getTime()}`, child_id: childId, family_id: FAMILY_ID, type: 'sleep', timestamp: bedtime, data: { startedAt: bedtime.toISOString(), endedAt: wakeTime.toISOString(), duration: Math.floor((wakeTime.getTime() - bedtime.getTime()) / (1000 * 60)), sleepType: 'night', quality: choice(['excellent', 'good', 'good', 'fair']), notes: '', }, created_at: bedtime, updated_at: wakeTime, }); // Naps for (let i = 0; i < napsPerDay; i++) { const napHour = currentAgeMonths < 6 ? random(9, 16) : [9, 13, 16][i] || 13; const napStart = new Date(currentDate); napStart.setHours(napHour, random(0, 59), 0, 0); const napDuration = currentAgeMonths < 6 ? random(30, 120) // Newborns: 30min-2h : currentAgeMonths < 18 ? random(60, 120) // Babies: 1-2h : random(60, 90); // Toddlers: 1-1.5h const napEnd = addMinutes(napStart, napDuration); activities.push({ id: `act_sleep_nap_${childId}_${napStart.getTime()}`, child_id: childId, family_id: FAMILY_ID, type: 'sleep', timestamp: napStart, data: { startedAt: napStart.toISOString(), endedAt: napEnd.toISOString(), duration: napDuration, sleepType: 'nap', quality: choice(['excellent', 'good', 'good', 'fair']), notes: '', }, created_at: napStart, updated_at: napEnd, }); } currentDate = addDays(currentDate, 1); } return activities; } // Generate diaper activities async function generateDiaperActivities(childId: string, birthDate: Date, ageMonths: number) { console.log(`Generating diaper activities for ${childId}...`); const activities = []; const today = new Date(); let currentDate = new Date(birthDate); while (currentDate < today) { const currentAgeMonths = Math.floor((currentDate.getTime() - birthDate.getTime()) / (1000 * 60 * 60 * 24 * 30)); // Stop generating diapers after 30 months (potty trained) if (currentAgeMonths >= 30) { currentDate = addDays(currentDate, 1); continue; } // Diaper frequency changes with age let changesPerDay = 8; // Newborn if (currentAgeMonths >= 3) changesPerDay = 6; if (currentAgeMonths >= 6) changesPerDay = 5; if (currentAgeMonths >= 12) changesPerDay = 4; if (currentAgeMonths >= 24) changesPerDay = 3; for (let i = 0; i < changesPerDay; i++) { const hour = random(6, 20); const timestamp = new Date(currentDate); timestamp.setHours(hour, random(0, 59), 0, 0); const wetOnly = random(1, 10) <= 6; // 60% wet only const poopOnly = random(1, 10) <= 1; // 10% poop only const both = !wetOnly && !poopOnly; // 30% both activities.push({ id: `act_diaper_${childId}_${timestamp.getTime()}`, child_id: childId, family_id: FAMILY_ID, type: 'diaper', timestamp, data: { isWet: wetOnly || both, isPoopy: poopOnly || both, rash: random(1, 100) <= 5, // 5% chance of rash notes: '', }, created_at: timestamp, updated_at: timestamp, }); } currentDate = addDays(currentDate, 1); } return activities; } // Generate growth measurements async function generateGrowthMeasurements(childId: string, birthDate: Date, ageMonths: number, gender: string) { console.log(`Generating growth measurements for ${childId}...`); const measurements = []; // WHO growth standards (approximate) const getExpectedWeight = (months: number, gender: string) => { // Birth weight ~3.5kg, doubles by 5 months, triples by 12 months if (months === 0) return 3.5 + random(-5, 5) / 10; if (months <= 6) return 3.5 + (months * 0.7) + random(-3, 3) / 10; if (months <= 12) return 7 + (months - 6) * 0.3 + random(-3, 3) / 10; if (months <= 24) return 10 + (months - 12) * 0.2 + random(-3, 3) / 10; return 12.5 + (months - 24) * 0.15 + random(-5, 5) / 10; }; const getExpectedHeight = (months: number) => { // Birth ~50cm, ~75cm at 12 months, ~86cm at 24 months if (months === 0) return 50 + random(-2, 2); if (months <= 12) return 50 + (months * 2.1) + random(-2, 2); if (months <= 24) return 75 + (months - 12) * 0.9 + random(-2, 2); return 86 + (months - 24) * 0.4 + random(-2, 2); }; const getExpectedHeadCircumference = (months: number) => { // Birth ~35cm, increases rapidly first year if (months === 0) return 35 + random(-1, 1); if (months <= 12) return 35 + (months * 1.2) + random(-1, 1); if (months <= 24) return 47 + (months - 12) * 0.3 + random(-1, 1); return 50 + (months - 24) * 0.1 + random(-1, 1); }; // Measurements at birth, 2 weeks, 1 month, then monthly for first year, then every 3 months const measurementSchedule = [0, 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63]; for (const month of measurementSchedule) { if (month > ageMonths) break; const measurementDate = addDays(birthDate, month * 30); measurements.push({ id: `act_growth_${childId}_${measurementDate.getTime()}`, child_id: childId, family_id: FAMILY_ID, type: 'growth', timestamp: measurementDate, data: { weight: getExpectedWeight(month, gender), height: getExpectedHeight(month), headCircumference: month <= 24 ? getExpectedHeadCircumference(month) : null, notes: month === 0 ? 'Birth measurements' : `${month} month checkup`, }, created_at: measurementDate, updated_at: measurementDate, }); } return measurements; } // Generate medicine/vaccination records async function generateMedicineActivities(childId: string, birthDate: Date, ageMonths: number) { console.log(`Generating medicine/vaccination activities for ${childId}...`); const activities = []; // CDC vaccination schedule const vaccinations = [ { ageMonths: 0, name: 'Hepatitis B (1st dose)', type: 'vaccine' }, { ageMonths: 1, name: 'Hepatitis B (2nd dose)', type: 'vaccine' }, { ageMonths: 2, name: 'DTaP, IPV, Hib, PCV13, Rotavirus (1st doses)', type: 'vaccine' }, { ageMonths: 4, name: 'DTaP, IPV, Hib, PCV13, Rotavirus (2nd doses)', type: 'vaccine' }, { ageMonths: 6, name: 'DTaP, IPV, Hib, PCV13, Rotavirus (3rd doses)', type: 'vaccine' }, { ageMonths: 6, name: 'Influenza (annual)', type: 'vaccine' }, { ageMonths: 12, name: 'MMR, Varicella, Hepatitis A (1st doses)', type: 'vaccine' }, { ageMonths: 15, name: 'DTaP (4th dose)', type: 'vaccine' }, { ageMonths: 18, name: 'Hepatitis A (2nd dose)', type: 'vaccine' }, { ageMonths: 18, name: 'Influenza (annual)', type: 'vaccine' }, { ageMonths: 30, name: 'Influenza (annual)', type: 'vaccine' }, { ageMonths: 42, name: 'Influenza (annual)', type: 'vaccine' }, { ageMonths: 54, name: 'Influenza (annual)', type: 'vaccine' }, ]; for (const vacc of vaccinations) { if (vacc.ageMonths > ageMonths) continue; const vaccDate = addDays(birthDate, vacc.ageMonths * 30); activities.push({ id: `act_medicine_${childId}_${vaccDate.getTime()}`, child_id: childId, family_id: FAMILY_ID, type: 'medicine', timestamp: vaccDate, data: { medicationType: vacc.type, name: vacc.name, dosage: '', notes: 'Well-child visit', }, created_at: vaccDate, updated_at: vaccDate, }); } // Occasional fever medication (1-2 times per year after 6 months) const feverMedicineMonths = []; for (let month = 6; month <= ageMonths; month += random(4, 8)) { feverMedicineMonths.push(month); } for (const month of feverMedicineMonths) { const medicineDate = addDays(birthDate, month * 30 + random(0, 29)); activities.push({ id: `act_medicine_fever_${childId}_${medicineDate.getTime()}`, child_id: childId, family_id: FAMILY_ID, type: 'medicine', timestamp: medicineDate, data: { medicationType: 'medication', name: choice(['Infant Tylenol', 'Infant Ibuprofen']), dosage: '2.5ml', notes: 'Fever reducer', }, created_at: medicineDate, updated_at: medicineDate, }); } return activities; } // Main execution async function main() { try { console.log('Starting demo data generation for ParentFlow...\n'); // Generate data for Alice (5 years old) console.log('=== Generating data for Alice (5 years old) ==='); const aliceFeeding = await generateFeedingActivities(ALICE.id, ALICE.birthDate, ALICE.ageMonths); const aliceSleep = await generateSleepActivities(ALICE.id, ALICE.birthDate, ALICE.ageMonths); const aliceDiaper = await generateDiaperActivities(ALICE.id, ALICE.birthDate, ALICE.ageMonths); const aliceGrowth = await generateGrowthMeasurements(ALICE.id, ALICE.birthDate, ALICE.ageMonths, ALICE.gender); const aliceMedicine = await generateMedicineActivities(ALICE.id, ALICE.birthDate, ALICE.ageMonths); console.log(`\nAlice activities generated: - Feeding: ${aliceFeeding.length} - Sleep: ${aliceSleep.length} - Diaper: ${aliceDiaper.length} - Growth: ${aliceGrowth.length} - Medicine: ${aliceMedicine.length} - Total: ${aliceFeeding.length + aliceSleep.length + aliceDiaper.length + aliceGrowth.length + aliceMedicine.length} `); // Generate data for Robert (8 months old) console.log('\n=== Generating data for Robert (8 months old) ==='); const robertFeeding = await generateFeedingActivities(ROBERT.id, ROBERT.birthDate, ROBERT.ageMonths); const robertSleep = await generateSleepActivities(ROBERT.id, ROBERT.birthDate, ROBERT.ageMonths); const robertDiaper = await generateDiaperActivities(ROBERT.id, ROBERT.birthDate, ROBERT.ageMonths); const robertGrowth = await generateGrowthMeasurements(ROBERT.id, ROBERT.birthDate, ROBERT.ageMonths, ROBERT.gender); const robertMedicine = await generateMedicineActivities(ROBERT.id, ROBERT.birthDate, ROBERT.ageMonths); console.log(`\nRobert activities generated: - Feeding: ${robertFeeding.length} - Sleep: ${robertSleep.length} - Diaper: ${robertDiaper.length} - Growth: ${robertGrowth.length} - Medicine: ${robertMedicine.length} - Total: ${robertFeeding.length + robertSleep.length + robertDiaper.length + robertGrowth.length + robertMedicine.length} `); // Combine all activities const allActivities = [ ...aliceFeeding, ...aliceSleep, ...aliceDiaper, ...aliceGrowth, ...aliceMedicine, ...robertFeeding, ...robertSleep, ...robertDiaper, ...robertGrowth, ...robertMedicine, ]; console.log(`\n=== Total activities to insert: ${allActivities.length} ===\n`); // Save to JSON file for SQL import const fs = require('fs'); fs.writeFileSync( '/root/maternal-app/scripts/demo-data.json', JSON.stringify(allActivities, null, 2) ); console.log('Demo data saved to /root/maternal-app/scripts/demo-data.json'); console.log('\nRun the SQL import script to insert this data into the database.'); } catch (error) { console.error('Error generating demo data:', error); process.exit(1); } finally { await prisma.$disconnect(); } } main();