import { PrismaPg } from '@prisma/adapter-pg'; import { randomBytes, scrypt } from 'node:crypto'; import { promisify } from 'node:util'; import { PrismaClient } from '../src/generated/prisma/client.js'; import { UserRole } from '../src/generated/prisma/enums.js'; const scryptAsync = promisify(scrypt); const TEST_PASSWORD = 'Test123456'; const HOSPITAL_CODE = 'DEMO_HOSP_001'; const HOSPITAL_NAME = 'Demo Hospital'; const DEPARTMENT_NAME = 'Cardiology'; const MEDICAL_GROUP_NAME = 'Group A'; interface SeedUserInput { phone: string; name: string; role: UserRole; hospitalId: number | null; departmentId: number | null; medicalGroupId: number | null; managerId: number | null; } interface PatientInput { name: string; hospitalId: number; departmentId: number | null; medicalGroupId: number | null; doctorId: number; } function requireDatabaseUrl(): string { const url = process.env.DATABASE_URL; if (!url) { throw new Error('DATABASE_URL is required. Run with `node --env-file=.env ...`.'); } return url; } async function hashPassword(password: string): Promise { const salt = randomBytes(16).toString('hex'); const derivedKey = (await scryptAsync(password, salt, 64)) as Buffer; return `${salt}:${derivedKey.toString('hex')}`; } async function upsertUser( prisma: PrismaClient, user: SeedUserInput, passwordHash: string, ) { return prisma.user.upsert({ where: { phone: user.phone }, create: { phone: user.phone, passwordHash, name: user.name, role: user.role, hospitalId: user.hospitalId, departmentId: user.departmentId, medicalGroupId: user.medicalGroupId, managerId: user.managerId, isActive: true, }, update: { passwordHash, name: user.name, role: user.role, hospitalId: user.hospitalId, departmentId: user.departmentId, medicalGroupId: user.medicalGroupId, managerId: user.managerId, isActive: true, }, select: { id: true, role: true, phone: true, name: true, }, }); } async function upsertPatientByNaturalKey( prisma: PrismaClient, patient: PatientInput, ) { const existing = await prisma.patient.findFirst({ where: { name: patient.name, hospitalId: patient.hospitalId, doctorId: patient.doctorId, }, select: { id: true }, }); if (existing) { return prisma.patient.update({ where: { id: existing.id }, data: { departmentId: patient.departmentId, medicalGroupId: patient.medicalGroupId, }, select: { id: true, name: true }, }); } return prisma.patient.create({ data: patient, select: { id: true, name: true }, }); } async function main() { const adapter = new PrismaPg({ connectionString: requireDatabaseUrl() }); const prisma = new PrismaClient({ adapter }); try { const passwordHash = await hashPassword(TEST_PASSWORD); const hospital = await prisma.hospital.upsert({ where: { code: HOSPITAL_CODE }, create: { code: HOSPITAL_CODE, name: HOSPITAL_NAME, }, update: { name: HOSPITAL_NAME, }, select: { id: true, name: true, code: true }, }); const department = await prisma.department.upsert({ where: { hospitalId_name: { hospitalId: hospital.id, name: DEPARTMENT_NAME, }, }, create: { name: DEPARTMENT_NAME, hospitalId: hospital.id, }, update: {}, select: { id: true, name: true }, }); const medicalGroup = await prisma.medicalGroup.upsert({ where: { departmentId_name: { departmentId: department.id, name: MEDICAL_GROUP_NAME, }, }, create: { name: MEDICAL_GROUP_NAME, departmentId: department.id, }, update: {}, select: { id: true, name: true }, }); const systemAdmin = await upsertUser( prisma, { phone: '+8613800000001', name: 'System Admin', role: UserRole.SYSTEM_ADMIN, hospitalId: null, departmentId: null, medicalGroupId: null, managerId: null, }, passwordHash, ); const hospitalAdmin = await upsertUser( prisma, { phone: '+8613800000002', name: 'Hospital Admin', role: UserRole.HOSPITAL_ADMIN, hospitalId: hospital.id, departmentId: null, medicalGroupId: null, managerId: null, }, passwordHash, ); const director = await upsertUser( prisma, { phone: '+8613800000003', name: 'Director', role: UserRole.DIRECTOR, hospitalId: hospital.id, departmentId: department.id, medicalGroupId: null, managerId: hospitalAdmin.id, }, passwordHash, ); const teamLead = await upsertUser( prisma, { phone: '+8613800000004', name: 'Team Lead', role: UserRole.TEAM_LEAD, hospitalId: hospital.id, departmentId: department.id, medicalGroupId: medicalGroup.id, managerId: director.id, }, passwordHash, ); const doctor = await upsertUser( prisma, { phone: '+8613800000005', name: 'Doctor', role: UserRole.DOCTOR, hospitalId: hospital.id, departmentId: department.id, medicalGroupId: medicalGroup.id, managerId: teamLead.id, }, passwordHash, ); const engineer = await upsertUser( prisma, { phone: '+8613800000006', name: 'Engineer', role: UserRole.ENGINEER, hospitalId: hospital.id, departmentId: null, medicalGroupId: null, managerId: hospitalAdmin.id, }, passwordHash, ); await upsertPatientByNaturalKey(prisma, { name: 'Patient Alpha', hospitalId: hospital.id, departmentId: department.id, medicalGroupId: medicalGroup.id, doctorId: doctor.id, }); await upsertPatientByNaturalKey(prisma, { name: 'Patient Beta', hospitalId: hospital.id, departmentId: department.id, medicalGroupId: medicalGroup.id, doctorId: doctor.id, }); await prisma.engineerHospitalAssignment.upsert({ where: { hospitalId_engineerId: { hospitalId: hospital.id, engineerId: engineer.id, }, }, create: { hospitalId: hospital.id, engineerId: engineer.id, assignedById: systemAdmin.id, }, update: { assignedById: systemAdmin.id, }, select: { id: true }, }); console.log(`Seed completed for hospital ${hospital.code} (${hospital.name}).`); console.log('Test password for all seeded users:', TEST_PASSWORD); console.table( [systemAdmin, hospitalAdmin, director, teamLead, doctor, engineer].map( (user) => ({ role: user.role, phone: user.phone, name: user.name ?? '', password: TEST_PASSWORD, }), ), ); console.log('No mini-program or official-account openId was pre-seeded.'); } finally { await prisma.$disconnect(); } } main().catch((error) => { console.error('Seed failed:', error); process.exit(1); });