// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema // Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" } enum GroupRole { ADMIN MEMBER } enum SetStatus { DRAFT OPEN LOCKED REVEALED } enum RevealMode { MANUAL AUTO_WHEN_ALL_GUESSED } model User { id String @id @default(cuid()) name String? email String? @unique emailVerified DateTime? image String? accounts Account[] sessions Session[] memberships GroupMember[] groupsCreated Group[] @relation("groupsCreated") setsCreated Set[] @relation("setsCreated") photosUploaded Photo[] guesses Guess[] invitesCreated Invite[] @relation("invitesCreated") invitesUsed Invite[] @relation("invitesUsed") createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } // Auth.js / NextAuth Prisma Adapter models model Account { id String @id @default(cuid()) userId String type String provider String providerAccountId String refresh_token String? access_token String? expires_at Int? token_type String? scope String? id_token String? session_state String? user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([provider, providerAccountId]) } model Session { id String @id @default(cuid()) sessionToken String @unique userId String expires DateTime user User @relation(fields: [userId], references: [id], onDelete: Cascade) } model VerificationToken { identifier String token String @unique expires DateTime @@unique([identifier, token]) } // MirrorMatch domain models model Group { id String @id @default(cuid()) name String slug String @unique createdById String createdBy User @relation("groupsCreated", fields: [createdById], references: [id], onDelete: Restrict) members GroupMember[] sets Set[] invites Invite[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model GroupMember { id String @id @default(cuid()) groupId String userId String role GroupRole @default(MEMBER) group Group @relation(fields: [groupId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) joinedAt DateTime @default(now()) @@unique([groupId, userId]) } model Set { id String @id @default(cuid()) groupId String createdById String title String? instructions String? // Config constraints minPhotos Int @default(2) maxPhotos Int @default(10) minOptions Int @default(2) maxOptions Int @default(4) status SetStatus @default(DRAFT) revealMode RevealMode @default(MANUAL) // If revealMode == AUTO_WHEN_ALL_GUESSED, app may auto-reveal once every active member has guessed every photo. allowManualReveal Boolean @default(true) group Group @relation(fields: [groupId], references: [id], onDelete: Cascade) createdBy User @relation("setsCreated", fields: [createdById], references: [id], onDelete: Restrict) options Option[] photos Photo[] revealedAt DateTime? revealedById String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([groupId, status]) } model Option { id String @id @default(cuid()) setId String label String order Int set Set @relation(fields: [setId], references: [id], onDelete: Cascade) photosCorrect Photo[] @relation("correctOption") guessesChosen Guess[] @relation("chosenOption") @@unique([setId, label]) @@index([setId, order]) } model Photo { id String @id @default(cuid()) setId String uploaderId String // Object storage pointer (MinIO / S3) storageKey String mimeType String? order Int points Int @default(1) // 1–10 (enforced by app) correctOptionId String set Set @relation(fields: [setId], references: [id], onDelete: Cascade) uploader User @relation(fields: [uploaderId], references: [id], onDelete: Restrict) correctOption Option @relation("correctOption", fields: [correctOptionId], references: [id], onDelete: Restrict) guesses Guess[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([setId, order]) } model Guess { id String @id @default(cuid()) photoId String userId String chosenOptionId String photo Photo @relation(fields: [photoId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) chosenOption Option @relation("chosenOption", fields: [chosenOptionId], references: [id], onDelete: Restrict) createdAt DateTime @default(now()) @@unique([photoId, userId]) @@index([userId, createdAt]) } model Invite { id String @id @default(cuid()) groupId String email String role GroupRole @default(MEMBER) // Store only a hash of the token in DB. tokenHash String @unique createdById String createdBy User @relation("invitesCreated", fields: [createdById], references: [id], onDelete: Restrict) usedAt DateTime? usedById String? usedBy User? @relation("invitesUsed", fields: [usedById], references: [id], onDelete: SetNull) expiresAt DateTime group Group @relation(fields: [groupId], references: [id], onDelete: Cascade) createdAt DateTime @default(now()) @@index([groupId, expiresAt]) @@index([email, expiresAt]) }