/** * Demo Data Insertion Script for ParentFlow * Generates and inserts realistic activity data for demo user's children */ // Simple nano ID generator (alphanumeric, 16 chars) function generateId(prefix = 'act') { const chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; let id = prefix + '_'; for (let i = 0; i < 12; i++) { id += chars[Math.floor(Math.random() * chars.length)]; } return id; } // Child data from database const ALICE = { id: 'chd_xr7ymrde3vf0', name: 'Alice', birthDate: new Date('2020-07-09'), gender: 'female', ageMonths: Math.floor((new Date() - new Date('2020-07-09')) / (1000 * 60 * 60 * 24 * 30)), }; const ROBERT = { id: 'chd_8b58nlkopebg', name: 'Robert', birthDate: new Date('2025-02-04'), gender: 'male', ageMonths: Math.floor((new Date() - new Date('2025-02-04')) / (1000 * 60 * 60 * 24 * 30)), }; const FAMILY_ID = 'fam_vpusjt4fhsxu'; const USER_ID = 'usr_p40br2mryafh'; // Demo user ID // Helper functions const random = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min; const choice = (arr) => arr[random(0, arr.length - 1)]; const addDays = (date, days) => { const result = new Date(date); result.setDate(result.getDate() + days); return result; }; const addHours = (date, hours) => { const result = new Date(date); result.setHours(result.getHours() + hours); return result; }; const addMinutes = (date, minutes) => { const result = new Date(date); result.setMinutes(result.getMinutes() + minutes); return result; }; // Generate feeding activities function generateFeedingActivities(childId, birthDate, ageMonths) { 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)); let feedingsPerDay = 8; // Newborn if (currentAgeMonths >= 3) feedingsPerDay = 6; if (currentAgeMonths >= 6) feedingsPerDay = 5; if (currentAgeMonths >= 12) feedingsPerDay = 4; if (currentAgeMonths >= 24) feedingsPerDay = 4; for (let i = 0; i < feedingsPerDay; i++) { const hour = currentAgeMonths < 6 ? random(0, 23) : [7, 10, 13, 17, 19][i] || random(8, 18); 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) { type = choice(['breast', 'bottle']); if (type === 'breast') { duration = random(15, 40); } else { amount = random(60, 180); } } else if (currentAgeMonths < 12) { 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 { 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: generateId('act'), child_id: childId, type: 'feeding', started_at: timestamp, ended_at: type === 'breast' && duration ? addMinutes(timestamp, duration) : timestamp, logged_by: USER_ID, notes: notes, metadata: { feedingType: type, amount, duration, side: type === 'breast' ? choice(['left', 'right', 'both']) : null, }, created_at: timestamp, updated_at: timestamp, }); } currentDate = addDays(currentDate, 1); } return activities; } // Generate sleep activities function generateSleepActivities(childId, birthDate, ageMonths) { 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)); 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: generateId('act'), child_id: childId, type: 'sleep', started_at: bedtime, ended_at: wakeTime, logged_by: USER_ID, notes: '', metadata: { duration: Math.floor((wakeTime.getTime() - bedtime.getTime()) / (1000 * 60)), sleepType: 'night', quality: choice(['excellent', 'good', 'good', 'fair']), }, 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) : currentAgeMonths < 18 ? random(60, 120) : random(60, 90); const napEnd = addMinutes(napStart, napDuration); activities.push({ id: generateId('act'), child_id: childId, type: 'sleep', started_at: napStart, ended_at: napEnd, logged_by: USER_ID, notes: '', metadata: { duration: napDuration, sleepType: 'nap', quality: choice(['excellent', 'good', 'good', 'fair']), }, created_at: napStart, updated_at: napEnd, }); } currentDate = addDays(currentDate, 1); } return activities; } // Generate diaper activities function generateDiaperActivities(childId, birthDate, ageMonths) { 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 at 30 months (potty trained) if (currentAgeMonths >= 30) { currentDate = addDays(currentDate, 1); continue; } let changesPerDay = 8; 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; const poopOnly = random(1, 10) <= 1; const both = !wetOnly && !poopOnly; activities.push({ id: generateId('act'), child_id: childId, type: 'diaper', started_at: timestamp, ended_at: timestamp, logged_by: USER_ID, notes: '', metadata: { isWet: wetOnly || both, isPoopy: poopOnly || both, rash: random(1, 100) <= 5, }, created_at: timestamp, updated_at: timestamp, }); } currentDate = addDays(currentDate, 1); } return activities; } // Generate growth measurements function generateGrowthMeasurements(childId, birthDate, ageMonths, gender) { console.log(`Generating growth measurements for ${childId}...`); const measurements = []; const getExpectedWeight = (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) => { 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) => { 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); }; const schedule = [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 schedule) { if (month > ageMonths) break; const measurementDate = addDays(birthDate, month * 30); measurements.push({ id: generateId('act'), child_id: childId, type: 'growth', started_at: measurementDate, ended_at: measurementDate, logged_by: USER_ID, notes: month === 0 ? 'Birth measurements' : `${month} month checkup`, metadata: { weight: getExpectedWeight(month), height: getExpectedHeight(month), headCircumference: month <= 24 ? getExpectedHeadCircumference(month) : null, }, created_at: measurementDate, updated_at: measurementDate, }); } return measurements; } // Generate medicine/vaccination records function generateMedicineActivities(childId, birthDate, ageMonths) { console.log(`Generating medicine/vaccination activities for ${childId}...`); const activities = []; 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: generateId('act'), child_id: childId, type: 'medicine', started_at: vaccDate, ended_at: vaccDate, logged_by: USER_ID, notes: 'Well-child visit', metadata: { medicationType: vacc.type, name: vacc.name, dosage: '', }, created_at: vaccDate, updated_at: vaccDate, }); } // Occasional fever medication 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: generateId('act'), child_id: childId, type: 'medicine', started_at: medicineDate, ended_at: medicineDate, logged_by: USER_ID, notes: 'Fever reducer', metadata: { medicationType: 'medication', name: choice(['Infant Tylenol', 'Infant Ibuprofen']), dosage: '2.5ml', }, created_at: medicineDate, updated_at: medicineDate, }); } return activities; } // Generate SQL INSERT statements function generateSQLInserts(activities) { const sqlStatements = []; for (const activity of activities) { const startedAt = activity.started_at.toISOString(); const endedAt = activity.ended_at ? activity.ended_at.toISOString() : startedAt; const createdAt = activity.created_at.toISOString(); const updatedAt = activity.updated_at.toISOString(); const metadataJson = JSON.stringify(activity.metadata).replace(/'/g, "''"); const notes = (activity.notes || '').replace(/'/g, "''"); const sql = `INSERT INTO activities (id, child_id, type, started_at, ended_at, logged_by, notes, metadata, created_at, updated_at) VALUES ('${activity.id}', '${activity.child_id}', '${activity.type}', '${startedAt}', '${endedAt}', '${activity.logged_by}', '${notes}', '${metadataJson}', '${createdAt}', '${updatedAt}');`; sqlStatements.push(sql); } return sqlStatements; } // Main execution async function main() { 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 = generateFeedingActivities(ALICE.id, ALICE.birthDate, ALICE.ageMonths); const aliceSleep = generateSleepActivities(ALICE.id, ALICE.birthDate, ALICE.ageMonths); const aliceDiaper = generateDiaperActivities(ALICE.id, ALICE.birthDate, ALICE.ageMonths); const aliceGrowth = generateGrowthMeasurements(ALICE.id, ALICE.birthDate, ALICE.ageMonths, ALICE.gender); const aliceMedicine = 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 = generateFeedingActivities(ROBERT.id, ROBERT.birthDate, ROBERT.ageMonths); const robertSleep = generateSleepActivities(ROBERT.id, ROBERT.birthDate, ROBERT.ageMonths); const robertDiaper = generateDiaperActivities(ROBERT.id, ROBERT.birthDate, ROBERT.ageMonths); const robertGrowth = generateGrowthMeasurements(ROBERT.id, ROBERT.birthDate, ROBERT.ageMonths, ROBERT.gender); const robertMedicine = 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`); // Generate SQL const sqlStatements = generateSQLInserts(allActivities); // Save to file const fs = require('fs'); const sqlFile = '/root/maternal-app/scripts/demo-data.sql'; fs.writeFileSync(sqlFile, '-- Demo data for ParentFlow\n'); fs.writeFileSync(sqlFile, '-- Generated: ' + new Date().toISOString() + '\n\n', { flag: 'a' }); fs.writeFileSync(sqlFile, 'BEGIN;\n\n', { flag: 'a' }); for (const sql of sqlStatements) { fs.writeFileSync(sqlFile, sql + '\n', { flag: 'a' }); } fs.writeFileSync(sqlFile, '\nCOMMIT;\n', { flag: 'a' }); console.log(`SQL file saved to ${sqlFile}`); console.log(`\nTo import: docker exec maternal-postgres psql -U maternal_user -d maternal_app -f /demo-data.sql`); } main().catch(console.error);