// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema // Get a free hosted Postgres database in seconds: `npx create-db` generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } enum UserRole { ADMIN FAMILY } enum GameStatus { OPEN CLOSED } enum PredictionCardType { LEGACY CUSTOM } enum PredictionValueType { NUMBER TEXT SELECT MULTI_TEXT DATE } enum PredictionActivityType { CARD_CREATED CARD_UPDATED CARD_DELETED PREDICTION_CREATED PREDICTION_UPDATED OUTCOME_SET SCORE_SUGGESTED SCORE_VALIDATED GAME_CLOSED GAME_OPENED } enum ParentType { PAPA MAMAN } enum Trimester { T1 T2 T3 DATATION } enum ProjectStatus { DRAFT OPEN CLOSED FINALIZED } model User { id String @id @default(cuid()) username String @unique displayName String? profileImageUrl String? profileBgColor String? passwordHash String refreshTokenHash String? workspaceId String? workspace Workspace? @relation("WorkspaceUsers", fields: [workspaceId], references: [id], onDelete: SetNull) role UserRole @default(FAMILY) createdAt DateTime @default(now()) ownedWorkspace Workspace? @relation("WorkspaceOwner") createdProjects Project[] @relation("ProjectsCreatedBy") projectMembership ProjectMembership? assignedMemberships ProjectMembership[] @relation("ProjectMembershipAssignedBy") predictionCardsCreated PredictionCard[] @relation("PredictionCardsCreatedBy") predictionEntries PredictionEntry[] @relation("PredictionEntriesByUser") predictionHistoryEvents PredictionEntryHistory[] @relation("PredictionHistoryByUser") predictionOutcomesSet PredictionOutcome[] @relation("PredictionOutcomesSetBy") predictionScoresValidated PredictionFieldScore[] @relation("PredictionScoresValidatedBy") predictionActivities PredictionActivity[] @relation("PredictionActivitiesByUser") @@index([workspaceId]) } model Workspace { id String @id @default(cuid()) slug String @unique name String ownerUserId String @unique ownerUser User @relation("WorkspaceOwner", fields: [ownerUserId], references: [id], onDelete: Restrict) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt users User[] @relation("WorkspaceUsers") projects Project[] } model Project { id String @id @default(cuid()) workspaceId String workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade) createdById String createdBy User @relation("ProjectsCreatedBy", fields: [createdById], references: [id], onDelete: Restrict) clonedFromProjectId String? clonedFromProject Project? @relation("ProjectCloneSource", fields: [clonedFromProjectId], references: [id], onDelete: SetNull) clonedProjects Project[] @relation("ProjectCloneSource") name String description String? projectImageUrl String? projectBgColor String? status ProjectStatus @default(DRAFT) babyCount Int @default(1) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt babies ProjectBaby[] memberships ProjectMembership[] games PredictionGame[] cards PredictionCard[] entries PredictionEntry[] outcomes PredictionOutcome[] fieldScores PredictionFieldScore[] activities PredictionActivity[] parentIndices ParentIndices[] babyIndices BabyIndices[] @@index([workspaceId, createdAt]) @@index([createdById, createdAt]) } model ProjectBaby { id String @id @default(cuid()) projectId String project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) babyIndex Int label String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([projectId, babyIndex]) @@index([projectId]) } model ProjectMembership { id String @id @default(cuid()) projectId String project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) userId String @unique user User @relation(fields: [userId], references: [id], onDelete: Cascade) assignedById String? assignedBy User? @relation("ProjectMembershipAssignedBy", fields: [assignedById], references: [id], onDelete: SetNull) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([projectId, userId]) @@index([projectId]) } model PredictionGame { id String @id @default(cuid()) projectId String? project Project? @relation(fields: [projectId], references: [id], onDelete: SetNull) title String @default("Pronostics bebe") status GameStatus @default(OPEN) closedAt DateTime? reopenedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt cards PredictionCard[] entries PredictionEntry[] activities PredictionActivity[] @@index([projectId]) } model PredictionCard { id String @id @default(cuid()) gameId String @default("singleton") game PredictionGame @relation(fields: [gameId], references: [id], onDelete: Cascade) projectId String? project Project? @relation(fields: [projectId], references: [id], onDelete: SetNull) code String? title String description String? type PredictionCardType @default(CUSTOM) valueType PredictionValueType styleId Int @default(0) unit String? isActive Boolean @default(true) isDeletable Boolean @default(true) sortOrder Int @default(0) basePoints Int @default(0) createdById String createdBy User @relation("PredictionCardsCreatedBy", fields: [createdById], references: [id], onDelete: Restrict) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt fields PredictionCardField[] options PredictionCardOption[] entries PredictionEntry[] outcomes PredictionOutcome[] activities PredictionActivity[] @@unique([projectId, code]) @@index([gameId, isActive, sortOrder]) @@index([projectId, isActive, sortOrder]) } model PredictionCardField { id String @id @default(cuid()) cardId String card PredictionCard @relation(fields: [cardId], references: [id], onDelete: Cascade) label String sortOrder Int @default(0) points Int @default(0) isPrimary Boolean @default(false) isRequired Boolean @default(false) minNumber Float? maxNumber Float? stepNumber Float? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt values PredictionEntryValue[] outcomes PredictionOutcome[] scores PredictionFieldScore[] @@unique([cardId, label]) @@index([cardId, sortOrder]) } model PredictionCardOption { id String @id @default(cuid()) cardId String card PredictionCard @relation(fields: [cardId], references: [id], onDelete: Cascade) label String value String sortOrder Int @default(0) @@unique([cardId, value]) @@index([cardId, sortOrder]) } model PredictionEntry { id String @id @default(cuid()) gameId String @default("singleton") game PredictionGame @relation(fields: [gameId], references: [id], onDelete: Cascade) projectId String? project Project? @relation(fields: [projectId], references: [id], onDelete: SetNull) userId String user User @relation("PredictionEntriesByUser", fields: [userId], references: [id], onDelete: Cascade) cardId String card PredictionCard @relation(fields: [cardId], references: [id], onDelete: Cascade) selectedBabyIndex Int? totalPoints Int @default(0) isScored Boolean @default(false) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt values PredictionEntryValue[] history PredictionEntryHistory[] scores PredictionFieldScore[] activities PredictionActivity[] @@unique([userId, cardId, selectedBabyIndex]) @@index([cardId]) @@index([userId]) @@index([projectId, userId]) } model PredictionEntryValue { id String @id @default(cuid()) entryId String entry PredictionEntry @relation(fields: [entryId], references: [id], onDelete: Cascade) fieldId String field PredictionCardField @relation(fields: [fieldId], references: [id], onDelete: Cascade) valueText String? valueNumber Float? valueDate DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([entryId, fieldId]) @@index([fieldId]) } model PredictionEntryHistory { id String @id @default(cuid()) entryId String entry PredictionEntry @relation(fields: [entryId], references: [id], onDelete: Cascade) userId String user User @relation("PredictionHistoryByUser", fields: [userId], references: [id], onDelete: Cascade) snapshot Json message String? createdAt DateTime @default(now()) @@index([entryId, createdAt]) } model PredictionOutcome { id String @id @default(cuid()) cardId String card PredictionCard @relation(fields: [cardId], references: [id], onDelete: Cascade) projectId String? project Project? @relation(fields: [projectId], references: [id], onDelete: SetNull) fieldId String field PredictionCardField @relation(fields: [fieldId], references: [id], onDelete: Cascade) selectedBabyIndex Int? valueText String? valueNumber Float? valueDate DateTime? setById String setBy User @relation("PredictionOutcomesSetBy", fields: [setById], references: [id], onDelete: Restrict) setAt DateTime @default(now()) @@unique([cardId, fieldId, selectedBabyIndex]) @@index([projectId]) @@index([projectId, selectedBabyIndex]) } model PredictionFieldScore { id String @id @default(cuid()) entryId String entry PredictionEntry @relation(fields: [entryId], references: [id], onDelete: Cascade) projectId String? project Project? @relation(fields: [projectId], references: [id], onDelete: SetNull) fieldId String field PredictionCardField @relation(fields: [fieldId], references: [id], onDelete: Cascade) suggestedPoints Int @default(0) awardedPoints Int? isValidated Boolean @default(false) note String? validatedById String? validatedBy User? @relation("PredictionScoresValidatedBy", fields: [validatedById], references: [id], onDelete: SetNull) validatedAt DateTime? updatedAt DateTime @updatedAt @@unique([entryId, fieldId]) @@index([projectId]) } model PredictionActivity { id String @id @default(cuid()) gameId String @default("singleton") game PredictionGame @relation(fields: [gameId], references: [id], onDelete: Cascade) projectId String? project Project? @relation(fields: [projectId], references: [id], onDelete: SetNull) type PredictionActivityType userId String? user User? @relation("PredictionActivitiesByUser", fields: [userId], references: [id], onDelete: SetNull) cardId String? card PredictionCard? @relation(fields: [cardId], references: [id], onDelete: SetNull) entryId String? entry PredictionEntry? @relation(fields: [entryId], references: [id], onDelete: SetNull) message String createdAt DateTime @default(now()) @@index([createdAt]) @@index([projectId, createdAt]) } // ===== INDICES ===== model ParentIndices { id String @id @default(cuid()) projectId String project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) parentType ParentType poids Float? taille Float? perimCranien Float? dateNaissance DateTime? updatedAt DateTime @updatedAt photos ParentIndexPhoto[] @@unique([projectId, parentType]) @@index([projectId]) } model ParentIndexPhoto { id String @id @default(cuid()) parentIndicesId String parentIndices ParentIndices @relation(fields: [parentIndicesId], references: [id], onDelete: Cascade) url String sortOrder Int @default(0) createdAt DateTime @default(now()) @@index([parentIndicesId]) } model BabyIndices { id String @id @default(cuid()) projectId String project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) babyIndex Int dpa DateTime? updatedAt DateTime @updatedAt trimesters BabyTrimesterEntry[] @@unique([projectId, babyIndex]) @@index([projectId]) } model BabyTrimesterEntry { id String @id @default(cuid()) babyIndicesId String babyIndices BabyIndices @relation(fields: [babyIndicesId], references: [id], onDelete: Cascade) trimester Trimester date DateTime? note String? poids Float? taille Float? perimCranien Float? updatedAt DateTime @updatedAt photos BabyTrimesterPhoto[] @@unique([babyIndicesId, trimester]) @@index([babyIndicesId]) } model BabyTrimesterPhoto { id String @id @default(cuid()) trimesterEntryId String trimesterEntry BabyTrimesterEntry @relation(fields: [trimesterEntryId], references: [id], onDelete: Cascade) url String sortOrder Int @default(0) createdAt DateTime @default(now()) @@index([trimesterEntryId]) }