generator client { provider = "prisma-client" output = "../src/generated/prisma" } datasource db { provider = "postgresql" } model Organization { id String @id @default(cuid()) name String slug String @unique orgType String @default("charity") // charity | fundraiser country String @default("UK") timezone String @default("Europe/London") bankName String? bankSortCode String? bankAccountNo String? bankAccountName String? refPrefix String @default("PNPL") logo String? primaryColor String @default("#1e40af") gcAccessToken String? gcEnvironment String @default("sandbox") whatsappConnected Boolean @default(false) zakatEnabled Boolean @default(false) // enables Zakat / Sadaqah / Lillah fund type picker createdAt DateTime @default(now()) updatedAt DateTime @updatedAt users User[] events Event[] pledges Pledge[] imports Import[] @@index([slug]) } model User { id String @id @default(cuid()) email String @unique name String? hashedPassword String? role String @default("staff") // super_admin, org_admin, staff, volunteer organizationId String organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([organizationId]) } model Event { id String @id @default(cuid()) name String slug String description String? eventDate DateTime? location String? goalAmount Int? // in pence currency String @default("GBP") status String @default("active") // draft, active, closed, archived paymentMode String @default("self") // self = we show bank details, external = redirect to URL externalUrl String? // e.g. https://launchgood.com/my-campaign externalPlatform String? // launchgood, enthuse, justgiving, gofundme, other fundAllocation String? // e.g. "Mosque Building Fund" — tracks which fund this event raises for organizationId String organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt qrSources QrSource[] pledges Pledge[] @@unique([organizationId, slug]) @@index([organizationId, status]) } model QrSource { id String @id @default(cuid()) label String // "Table 5", "Volunteer: Ahmed" code String @unique // short token for URL volunteerName String? tableName String? eventId String event Event @relation(fields: [eventId], references: [id], onDelete: Cascade) scanCount Int @default(0) createdAt DateTime @default(now()) pledges Pledge[] @@index([eventId]) @@index([code]) } model Pledge { id String @id @default(cuid()) reference String @unique // human-safe bank ref e.g. "PNPL-7K4P-50" amountPence Int currency String @default("GBP") rail String // bank, gocardless, card status String @default("new") // new, initiated, paid, overdue, cancelled donorName String? donorEmail String? donorPhone String? giftAid Boolean @default(false) fundType String? // null=general, zakat, sadaqah, lillah, fitrana iPaidClickedAt DateTime? notes String? // Payment scheduling — the core of "pledge now, pay later" dueDate DateTime? // null = pay now, set = promise to pay on this date planId String? // groups installments together installmentNumber Int? // e.g. 1 (of 4) installmentTotal Int? // e.g. 4 reminderSentForDueDate Boolean @default(false) eventId String event Event @relation(fields: [eventId], references: [id]) qrSourceId String? qrSource QrSource? @relation(fields: [qrSourceId], references: [id]) organizationId String organization Organization @relation(fields: [organizationId], references: [id]) paymentInstruction PaymentInstruction? payments Payment[] reminders Reminder[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt paidAt DateTime? cancelledAt DateTime? @@index([organizationId, status]) @@index([reference]) @@index([eventId, status]) @@index([donorEmail]) @@index([donorPhone]) @@index([dueDate, status]) @@index([planId]) } model PaymentInstruction { id String @id @default(cuid()) pledgeId String @unique pledge Pledge @relation(fields: [pledgeId], references: [id], onDelete: Cascade) bankReference String // the unique ref to use bankDetails Json // {sortCode, accountNo, accountName, bankName} gcMandateId String? gcMandateUrl String? sentAt DateTime? createdAt DateTime @default(now()) @@index([bankReference]) } model Payment { id String @id @default(cuid()) pledgeId String pledge Pledge @relation(fields: [pledgeId], references: [id], onDelete: Cascade) provider String // bank, gocardless, stripe providerRef String? // external ID amountPence Int status String @default("pending") // pending, confirmed, failed matchedBy String? // auto, manual receivedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt importId String? import Import? @relation(fields: [importId], references: [id]) @@index([pledgeId]) @@index([providerRef]) } model Reminder { id String @id @default(cuid()) pledgeId String pledge Pledge @relation(fields: [pledgeId], references: [id], onDelete: Cascade) step Int // 0=instructions, 1=nudge, 2=urgency, 3=final channel String @default("email") // email, sms, whatsapp scheduledAt DateTime sentAt DateTime? status String @default("pending") // pending, sent, skipped, failed payload Json? createdAt DateTime @default(now()) @@index([pledgeId]) @@index([scheduledAt, status]) } model Import { id String @id @default(cuid()) organizationId String organization Organization @relation(fields: [organizationId], references: [id]) kind String // bank_statement, gocardless_export, crm_export fileName String? rowCount Int @default(0) matchedCount Int @default(0) unmatchedCount Int @default(0) mappingConfig Json? stats Json? status String @default("pending") // pending, processing, completed, failed uploadedAt DateTime @default(now()) payments Payment[] @@index([organizationId]) } model AnalyticsEvent { id String @id @default(cuid()) eventType String // pledge_start, amount_selected, rail_selected, identity_submitted, pledge_completed, instruction_copy_clicked, i_paid_clicked, payment_matched pledgeId String? eventId String? qrSourceId String? metadata Json? createdAt DateTime @default(now()) @@index([eventType]) @@index([pledgeId]) @@index([eventId]) @@index([createdAt]) }