// backend/prisma/schema.prisma generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model User { id String @id @default(uuid()) email String @unique passwordHash String? googleId String? @unique facebookId String? @unique name String trialUsedAt DateTime? memberships Membership[] ownedOrganizations Organization[] @relation("OrganizationOwner") sessions Session[] // 👈 ADD THIS - opposite relation for Session sentStaffInvites StaffInvitation[] sentOrganizationInvitations OrganizationInvitation[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@map("users") } model OrganizationType { id String @id @default(uuid()) name String @unique // "CLINIC" or "LAB" organizations Organization[] features Feature[] // 👈 ADD THIS - opposite relation for Feature @@map("organization_types") } model Organization { id String @id @default(uuid()) name String email String @unique phone String? address String? typeId String type OrganizationType @relation(fields: [typeId], references: [id]) ownerId String owner User @relation("OrganizationOwner", fields: [ownerId], references: [id]) memberships Membership[] planId String? plan Plan? @relation(fields: [planId], references: [id]) sharedWithMe OrganizationLink[] @relation("OrganizationB") sharedWithOthers OrganizationLink[] @relation("OrganizationA") sentOrganizationInvitations OrganizationInvitation[] @relation("OrganizationInvitationInviter") patients Patient[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@map("organizations") } model Patient { id String @id @default(uuid()) organizationId String firstName String lastName String phone String? email String? dateOfBirth DateTime? notes String? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt organization Organization @relation(fields: [organizationId], references: [id]) treatments PatientTreatmentHistory[] @@index([organizationId, createdAt]) @@index([organizationId, lastName, firstName]) @@map("patients") } model PatientTreatmentHistory { id String @id @default(uuid()) patientId String title String status String treatmentAt DateTime tooth String? notes String? totalCost Float? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt patient Patient @relation(fields: [patientId], references: [id], onDelete: Cascade) @@index([patientId, treatmentAt]) @@map("patient_treatment_histories") } model Plan { id String @id @default(uuid()) name String @unique // "Solo", "Small", "Medium", "Large", "Enterprise" maxUsers Int // 1, 5, 10, 15, 999999 for unlimited price Float features Json // Store feature flags as JSON organizations Organization[] @@map("plans") } model Membership { id String @id @default(uuid()) userId String organizationId String isOwner Boolean @default(false) isActive Boolean @default(true) user User @relation(fields: [userId], references: [id]) organization Organization @relation(fields: [organizationId], references: [id]) permissions MembershipPermission[] invitations StaffInvitation[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([userId, organizationId]) @@map("memberships") } model StaffInvitation { id String @id @default(uuid()) membershipId String invitedById String tokenHash String @unique expiresAt DateTime acceptedAt DateTime? revokedAt DateTime? membership Membership @relation(fields: [membershipId], references: [id], onDelete: Cascade) invitedBy User @relation(fields: [invitedById], references: [id], onDelete: Cascade) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([membershipId, createdAt]) @@map("staff_invitations") } model Permission { id String @id @default(uuid()) name String @unique description String? memberships MembershipPermission[] featureId String? feature Feature? @relation(fields: [featureId], references: [id]) @@map("permissions") } model MembershipPermission { membershipId String permissionId String membership Membership @relation(fields: [membershipId], references: [id]) permission Permission @relation(fields: [permissionId], references: [id]) @@id([membershipId, permissionId]) @@map("membership_permissions") } model Feature { id String @id @default(uuid()) name String @unique description String? permissions Permission[] organizationTypeId String? organizationType OrganizationType? @relation(fields: [organizationTypeId], references: [id]) @@map("features") } model OrganizationLink { id String @id @default(uuid()) organizationAId String organizationBId String status LinkStatus @default(PENDING) sharedDataTypes Json organizationA Organization @relation("OrganizationA", fields: [organizationAId], references: [id]) organizationB Organization @relation("OrganizationB", fields: [organizationBId], references: [id]) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([organizationAId, organizationBId]) @@map("organization_links") } model OrganizationInvitation { id String @id @default(uuid()) inviterOrganizationId String inviterUserId String invitedOrganizationId String? invitedOrganizationName String invitedOwnerEmail String invitedOrganizationType String tokenHash String @unique expiresAt DateTime acceptedAt DateTime? revokedAt DateTime? inviterOrganization Organization @relation("OrganizationInvitationInviter", fields: [inviterOrganizationId], references: [id], onDelete: Cascade) inviterUser User @relation(fields: [inviterUserId], references: [id], onDelete: Cascade) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([inviterOrganizationId, createdAt]) @@index([invitedOwnerEmail, createdAt]) @@map("organization_invitations") } model Session { id String @id @default(uuid()) userId String token String @unique refreshToken String? @unique expiresAt DateTime userAgent String? ipAddress String? user User @relation(fields: [userId], references: [id]) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@map("sessions") } enum LinkStatus { PENDING ACTIVE REJECTED BLOCKED }