2026-04-23 15:33:11 +03:30
|
|
|
// backend/prisma/seed.ts
|
|
|
|
|
import { PrismaClient } from '@prisma/client';
|
2026-06-28 16:46:42 +03:30
|
|
|
import { randomUUID } from 'crypto';
|
2026-04-23 15:33:11 +03:30
|
|
|
import { config } from 'dotenv';
|
|
|
|
|
import path from 'path';
|
|
|
|
|
|
|
|
|
|
// Load environment variables from the correct path
|
|
|
|
|
const envPath = path.join(__dirname, '..', '.env');
|
|
|
|
|
console.log('Loading .env from:', envPath);
|
|
|
|
|
config({ path: envPath });
|
|
|
|
|
|
|
|
|
|
// Verify DATABASE_URL is loaded
|
|
|
|
|
if (!process.env.DATABASE_URL) {
|
|
|
|
|
console.error('❌ DATABASE_URL is not set in environment');
|
|
|
|
|
console.log('Current directory:', process.cwd());
|
|
|
|
|
console.log('.env path:', envPath);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log('✅ DATABASE_URL found:', process.env.DATABASE_URL.substring(0, 30) + '...');
|
|
|
|
|
|
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
|
|
|
|
|
|
async function main() {
|
|
|
|
|
console.log('🌱 Starting seeding...');
|
|
|
|
|
|
|
|
|
|
// Test the connection
|
|
|
|
|
await prisma.$connect();
|
|
|
|
|
console.log('✅ Database connected successfully');
|
|
|
|
|
|
|
|
|
|
// Create organization types
|
2026-04-29 21:55:46 +03:30
|
|
|
await prisma.organizationType.upsert({
|
2026-04-23 15:33:11 +03:30
|
|
|
where: { name: 'CLINIC' },
|
|
|
|
|
update: {},
|
|
|
|
|
create: { name: 'CLINIC' },
|
|
|
|
|
});
|
|
|
|
|
console.log('✅ Created clinic type');
|
|
|
|
|
|
2026-04-29 21:55:46 +03:30
|
|
|
await prisma.organizationType.upsert({
|
2026-04-23 15:33:11 +03:30
|
|
|
where: { name: 'LAB' },
|
|
|
|
|
update: {},
|
|
|
|
|
create: { name: 'LAB' },
|
|
|
|
|
});
|
|
|
|
|
console.log('✅ Created lab type');
|
|
|
|
|
|
|
|
|
|
// Create plans
|
|
|
|
|
const plans = [
|
|
|
|
|
{ name: 'trial', maxUsers: 5, price: 0, features: {} },
|
2026-04-30 00:52:05 +03:30
|
|
|
{ name: 'Small', maxUsers: 5, price: 150, features: {} },
|
|
|
|
|
{ name: 'Medium', maxUsers: 10, price: 250, features: {} },
|
|
|
|
|
{ name: 'Large', maxUsers: 15, price: 400, features: {} },
|
|
|
|
|
{ name: 'Enterprise', maxUsers: 999999, price: 1000, features: {} },
|
2026-04-23 15:33:11 +03:30
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (const plan of plans) {
|
|
|
|
|
await prisma.plan.upsert({
|
|
|
|
|
where: { name: plan.name },
|
|
|
|
|
update: {},
|
|
|
|
|
create: plan,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
console.log('✅ Created plans');
|
|
|
|
|
|
2026-04-29 21:55:46 +03:30
|
|
|
// Minimal permission model (confirmed):
|
|
|
|
|
// - Sidebar tabs use READ/EDIT
|
|
|
|
|
// - EDIT implies READ in app logic
|
|
|
|
|
// - Owners effectively get all permissions
|
2026-04-23 15:33:11 +03:30
|
|
|
const features = [
|
|
|
|
|
{
|
2026-04-29 21:55:46 +03:30
|
|
|
name: 'Today',
|
|
|
|
|
permissions: ['TAB_TODAY_READ', 'TAB_TODAY_EDIT'],
|
2026-04-23 15:33:11 +03:30
|
|
|
},
|
2026-04-30 18:49:23 +03:30
|
|
|
{
|
|
|
|
|
name: 'Staff',
|
|
|
|
|
permissions: ['TAB_STAFF_READ', 'TAB_STAFF_EDIT'],
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-05-05 19:50:07 +03:30
|
|
|
name: 'Organizations',
|
|
|
|
|
permissions: ['TAB_ORGANIZATIONS_READ', 'TAB_ORGANIZATIONS_EDIT'],
|
2026-04-30 18:49:23 +03:30
|
|
|
},
|
2026-04-23 15:33:11 +03:30
|
|
|
{
|
2026-04-29 21:55:46 +03:30
|
|
|
name: 'Patients',
|
|
|
|
|
permissions: ['TAB_PATIENTS_READ', 'TAB_PATIENTS_EDIT'],
|
2026-04-23 15:33:11 +03:30
|
|
|
},
|
|
|
|
|
{
|
2026-04-30 18:49:23 +03:30
|
|
|
name: 'Appointment',
|
2026-04-29 21:55:46 +03:30
|
|
|
permissions: ['TAB_APPOINTMENTS_READ', 'TAB_APPOINTMENTS_EDIT'],
|
2026-04-23 15:33:11 +03:30
|
|
|
},
|
|
|
|
|
{
|
2026-04-30 18:49:23 +03:30
|
|
|
name: 'Treatment',
|
|
|
|
|
permissions: ['TAB_TREATMENT_READ', 'TAB_TREATMENT_EDIT'],
|
2026-04-23 15:33:11 +03:30
|
|
|
},
|
2026-06-28 14:59:06 +03:30
|
|
|
{
|
|
|
|
|
name: 'Cases',
|
|
|
|
|
permissions: ['TAB_CASES_READ', 'TAB_CASES_EDIT'],
|
|
|
|
|
},
|
2026-06-28 22:56:56 +03:30
|
|
|
{
|
|
|
|
|
name: 'Tasks',
|
|
|
|
|
permissions: ['TAB_TASKS_READ', 'TAB_TASKS_EDIT'],
|
|
|
|
|
},
|
2026-04-23 15:33:11 +03:30
|
|
|
{
|
|
|
|
|
name: 'Billing',
|
2026-04-29 21:55:46 +03:30
|
|
|
permissions: ['TAB_BILLING_READ', 'TAB_BILLING_EDIT'],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'Reports',
|
|
|
|
|
permissions: ['TAB_REPORTS_READ', 'TAB_REPORTS_EDIT'],
|
|
|
|
|
},
|
2026-04-23 15:33:11 +03:30
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (const feature of features) {
|
|
|
|
|
const createdFeature = await prisma.feature.upsert({
|
|
|
|
|
where: { name: feature.name },
|
|
|
|
|
update: {},
|
|
|
|
|
create: { name: feature.name },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for (const permissionName of feature.permissions) {
|
|
|
|
|
await prisma.permission.upsert({
|
|
|
|
|
where: { name: permissionName },
|
|
|
|
|
update: {},
|
|
|
|
|
create: {
|
|
|
|
|
name: permissionName,
|
|
|
|
|
featureId: createdFeature.id,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
console.log('✅ Created features and permissions');
|
|
|
|
|
|
2026-06-28 16:46:42 +03:30
|
|
|
const workflowSteps = [
|
|
|
|
|
{ code: 'endo', stepOrder: 1, label: 'Access review' },
|
|
|
|
|
{ code: 'endo', stepOrder: 2, label: 'Fabrication' },
|
|
|
|
|
] as const;
|
|
|
|
|
|
|
|
|
|
const treatmentTypes = [
|
|
|
|
|
{ code: 'consultation', labDependent: false, sortOrder: 1 },
|
|
|
|
|
{ code: 'filling', labDependent: false, sortOrder: 2 },
|
|
|
|
|
{ code: 'endo', labDependent: true, sortOrder: 3 },
|
|
|
|
|
{ code: 'visit', labDependent: false, sortOrder: 4 },
|
|
|
|
|
{ code: 'hygiene', labDependent: false, sortOrder: 5 },
|
|
|
|
|
] as const;
|
|
|
|
|
|
|
|
|
|
for (const type of treatmentTypes) {
|
|
|
|
|
await prisma.treatmentType.upsert({
|
|
|
|
|
where: { code: type.code },
|
|
|
|
|
update: { labDependent: type.labDependent, sortOrder: type.sortOrder },
|
|
|
|
|
create: {
|
|
|
|
|
id: randomUUID(),
|
|
|
|
|
code: type.code,
|
|
|
|
|
labDependent: type.labDependent,
|
|
|
|
|
sortOrder: type.sortOrder,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
console.log('✅ Seeded treatment type catalog');
|
|
|
|
|
|
|
|
|
|
for (const step of workflowSteps) {
|
|
|
|
|
const treatmentType = await prisma.treatmentType.findUniqueOrThrow({
|
|
|
|
|
where: { code: step.code },
|
|
|
|
|
select: { id: true },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await prisma.treatmentWorkflowStep.upsert({
|
|
|
|
|
where: {
|
|
|
|
|
treatmentTypeId_stepOrder: {
|
|
|
|
|
treatmentTypeId: treatmentType.id,
|
|
|
|
|
stepOrder: step.stepOrder,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
update: { label: step.label },
|
|
|
|
|
create: {
|
|
|
|
|
id: randomUUID(),
|
|
|
|
|
treatmentTypeId: treatmentType.id,
|
|
|
|
|
stepOrder: step.stepOrder,
|
|
|
|
|
label: step.label,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
console.log('✅ Seeded lab workflow steps');
|
|
|
|
|
|
2026-04-29 21:55:46 +03:30
|
|
|
console.log('🌱 Seeding completed successfully!');
|
2026-04-23 15:33:11 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
main()
|
|
|
|
|
.catch((e) => {
|
|
|
|
|
console.error('❌ Seeding failed:', e);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
})
|
|
|
|
|
.finally(async () => {
|
|
|
|
|
await prisma.$disconnect();
|
|
|
|
|
});
|