mirror_match/prisma/schema.prisma

238 lines
5.7 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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) // 110 (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])
}