initial project setup
Fastify + Prisma backend, React + Vite frontend, Docker deployment. Multi-board feedback platform with anonymous cookie auth, passkey upgrade path, ALTCHA spam protection, plugin system, and full privacy-first architecture.
This commit is contained in:
213
packages/api/prisma/schema.prisma
Normal file
213
packages/api/prisma/schema.prisma
Normal file
@@ -0,0 +1,213 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
enum AuthMethod {
|
||||
COOKIE
|
||||
PASSKEY
|
||||
}
|
||||
|
||||
enum PostType {
|
||||
FEATURE_REQUEST
|
||||
BUG_REPORT
|
||||
}
|
||||
|
||||
enum PostStatus {
|
||||
OPEN
|
||||
UNDER_REVIEW
|
||||
PLANNED
|
||||
IN_PROGRESS
|
||||
DONE
|
||||
DECLINED
|
||||
}
|
||||
|
||||
model Board {
|
||||
id String @id @default(cuid())
|
||||
slug String @unique
|
||||
name String
|
||||
description String?
|
||||
externalUrl String?
|
||||
isArchived Boolean @default(false)
|
||||
voteBudget Int @default(10)
|
||||
voteBudgetReset String @default("monthly")
|
||||
lastBudgetReset DateTime?
|
||||
allowMultiVote Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
posts Post[]
|
||||
activityEvents ActivityEvent[]
|
||||
pushSubscriptions PushSubscription[]
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
authMethod AuthMethod @default(COOKIE)
|
||||
tokenHash String? @unique
|
||||
username String?
|
||||
usernameIdx String? @unique
|
||||
displayName String?
|
||||
darkMode String @default("system")
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
passkeys Passkey[]
|
||||
posts Post[]
|
||||
comments Comment[]
|
||||
reactions Reaction[]
|
||||
votes Vote[]
|
||||
pushSubscriptions PushSubscription[]
|
||||
}
|
||||
|
||||
model Passkey {
|
||||
id String @id @default(cuid())
|
||||
credentialId String
|
||||
credentialIdIdx String @unique
|
||||
credentialPublicKey Bytes
|
||||
counter BigInt
|
||||
credentialDeviceType String
|
||||
credentialBackedUp Boolean
|
||||
transports String?
|
||||
userId String
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
model Post {
|
||||
id String @id @default(cuid())
|
||||
type PostType
|
||||
title String
|
||||
description Json
|
||||
status PostStatus @default(OPEN)
|
||||
category String?
|
||||
voteCount Int @default(0)
|
||||
isPinned Boolean @default(false)
|
||||
boardId String
|
||||
authorId String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
board Board @relation(fields: [boardId], references: [id], onDelete: Cascade)
|
||||
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
|
||||
statusChanges StatusChange[]
|
||||
comments Comment[]
|
||||
votes Vote[]
|
||||
adminResponses AdminResponse[]
|
||||
activityEvents ActivityEvent[]
|
||||
pushSubscriptions PushSubscription[]
|
||||
}
|
||||
|
||||
model StatusChange {
|
||||
id String @id @default(cuid())
|
||||
postId String
|
||||
fromStatus PostStatus
|
||||
toStatus PostStatus
|
||||
changedBy String
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
model Comment {
|
||||
id String @id @default(cuid())
|
||||
body String
|
||||
postId String
|
||||
authorId String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
|
||||
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
|
||||
reactions Reaction[]
|
||||
}
|
||||
|
||||
model Reaction {
|
||||
id String @id @default(cuid())
|
||||
emoji String
|
||||
commentId String
|
||||
userId String
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
comment Comment @relation(fields: [commentId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([commentId, userId, emoji])
|
||||
}
|
||||
|
||||
model Vote {
|
||||
id String @id @default(cuid())
|
||||
weight Int @default(1)
|
||||
postId String
|
||||
voterId String
|
||||
budgetPeriod String
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
|
||||
voter User @relation(fields: [voterId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([postId, voterId])
|
||||
}
|
||||
|
||||
model AdminUser {
|
||||
id String @id @default(cuid())
|
||||
email String @unique
|
||||
passwordHash String
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
responses AdminResponse[]
|
||||
}
|
||||
|
||||
model AdminResponse {
|
||||
id String @id @default(cuid())
|
||||
body String
|
||||
postId String
|
||||
adminId String
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
|
||||
admin AdminUser @relation(fields: [adminId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
model ActivityEvent {
|
||||
id String @id @default(cuid())
|
||||
type String
|
||||
boardId String
|
||||
postId String?
|
||||
metadata Json
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
board Board @relation(fields: [boardId], references: [id], onDelete: Cascade)
|
||||
post Post? @relation(fields: [postId], references: [id], onDelete: SetNull)
|
||||
|
||||
@@index([boardId, createdAt])
|
||||
@@index([createdAt])
|
||||
}
|
||||
|
||||
model PushSubscription {
|
||||
id String @id @default(cuid())
|
||||
endpoint String
|
||||
endpointIdx String @unique
|
||||
keysP256dh String
|
||||
keysAuth String
|
||||
userId String
|
||||
boardId String?
|
||||
postId String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
board Board? @relation(fields: [boardId], references: [id], onDelete: Cascade)
|
||||
post Post? @relation(fields: [postId], references: [id], onDelete: SetNull)
|
||||
}
|
||||
|
||||
model Category {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
slug String @unique
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
Reference in New Issue
Block a user