Organize/prisma/schema.prisma

117 lines
3.3 KiB
Plaintext

// Prisma schema for the organizer app.
// Learn more: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client"
output = "../lib/generated/prisma"
}
datasource db {
provider = "postgresql"
}
enum Role {
ADMIN
USER
PENDING
}
// How the site handles new sign-ups. See SiteSettings.signupMode.
enum SignupMode {
// Anyone can sign up and is immediately a USER. Today's behavior.
OPEN
// Anyone can sign up, but starts PENDING until an admin approves them
// (moves them to USER or ADMIN) on the Admin page.
APPROVED
// Anyone can sign up, but starts PENDING until they confirm their email.
// Not implemented yet -- the Admin page exposes this option greyed out.
CONFIRMED
// Sign-ups are turned off entirely: no form, no working sign-up action.
CLOSED
}
model User {
id String @id @default(cuid())
email String @unique
passwordHash String
name String?
// The very first person to sign up becomes ADMIN regardless of
// signupMode (the site needs at least one admin to bootstrap). Everyone
// after that gets USER (signupMode OPEN) or PENDING (APPROVED/CONFIRMED),
// per SiteSettings.signupMode.
role Role @default(USER)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
categories Category[]
}
// Single-row table of site-wide settings. Always has exactly one row, at
// the fixed id below -- read with `findFirst` (falling back to defaults
// when the row doesn't exist yet) and written with `upsert`.
model SiteSettings {
id String @id @default("singleton")
signupMode SignupMode @default(OPEN)
updatedAt DateTime @updatedAt
}
model Category {
id String @id @default(cuid())
name String
order Int
userId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
groups Group[]
@@index([userId, order])
}
model Group {
id String @id @default(cuid())
// Short display title, enforced at <=20 chars in app-level validation too.
title String @db.VarChar(20)
// Palette key (see lib/colors.ts) rather than a raw hex value, so the
// curated palette can be retinted centrally without a data migration.
color String
// Position within its Category lane.
order Int
// Single evolving markdown document for the group. Not a separate model:
// it's a 1:1, always-exists field with no independent lifecycle.
noteContent String @default("") @db.Text
// Set once a group is archived; archived groups are kept (not deleted)
// but excluded from the Home board query. Null = active.
archivedAt DateTime?
categoryId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)
todos Todo[]
@@index([categoryId, order])
}
model Todo {
id String @id @default(cuid())
title String @db.VarChar(20)
details String? @db.Text
completed Boolean @default(false)
// Position within its Group's to-do list.
order Int
groupId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
group Group @relation(fields: [groupId], references: [id], onDelete: Cascade)
@@index([groupId, order])
}