// Gruperly - Prisma Schema (PostgreSQL) generator client { provider = "prisma-client" output = "./generated/prisma" } datasource db { provider = "postgresql" } // Auth (Better Auth) - required tables model User { id String @id @default(cuid()) name String email String @unique emailVerified Boolean @default(false) image String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt accounts Account[] sessions Session[] groupsMember Member[] groupsOwner Group[] @relation("OwnerGroups") waitlist WaitlistEntry[] @@map("users") } model Account { id String @id @default(cuid()) userId String providerId String providerAccountId String refreshToken String? accessToken String? accessTokenExpiresAt DateTime? refreshTokenExpiresAt DateTime? scope String? idToken String? password String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([providerId, providerAccountId]) @@map("accounts") } model Session { id String @id @default(cuid()) userId String token String @unique expiresAt DateTime ipAddress String? userAgent String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@map("sessions") } model Verification { id String @id @default(cuid()) identifier String value String expiresAt DateTime createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([identifier, value]) @@map("verifications") } // Domain models model Group { id String @id @default(cuid()) name String description String? createdById String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt owner User @relation("OwnerGroups", fields: [createdById], references: [id], onDelete: Cascade) members Member[] students Student[] payments Payment[] @@map("groups") } model Member { id String @id @default(cuid()) groupId String userId String role Role @default(MEMBER) // OWNER, ADMIN, MEMBER joinedAt DateTime @default(now()) group Group @relation(fields: [groupId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([groupId, userId]) @@map("members") } enum Role { OWNER ADMIN MEMBER } model Student { id String @id @default(cuid()) groupId String fullName String email String? phone String? guardianName String? guardianPhone String? notes String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt group Group @relation(fields: [groupId], references: [id], onDelete: Cascade) payments Payment[] @@index([groupId]) @@map("students") } model Payment { id String @id @default(cuid()) groupId String studentId String amount Decimal @db.Decimal(10, 2) currency String @default("MXN") status PaymentStatus @default(PENDING) // PENDING, PAID, OVERDUE, CANCELLED dueDate DateTime paidAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt group Group @relation(fields: [groupId], references: [id], onDelete: Cascade) student Student @relation(fields: [studentId], references: [id], onDelete: Cascade) @@index([groupId]) @@index([studentId]) @@map("payments") } enum PaymentStatus { PENDING PAID OVERDUE CANCELLED } model WaitlistEntry { id String @id @default(cuid()) email String name String? status WaitlistStatus @default(PENDING) // PENDING, INVITED, JOINED, DECLINED createdAt DateTime @default(now()) updatedAt DateTime @updatedAt userId String? @unique user User? @relation(fields: [userId], references: [id], onDelete: SetNull) @@unique([email]) @@map("waitlist_entries") } enum WaitlistStatus { PENDING INVITED JOINED DECLINED }