Files
TodoList/apps/api/prisma/schema.prisma
T

404 lines
11 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.
// Prisma 数据模型定义(TodoList
generator client {
provider = "prisma-client"
output = "../generated/prisma"
}
datasource db {
provider = "postgresql"
}
enum UserStatus {
ACTIVE
DISABLED
BANNED
}
enum AuthProvider {
EMAIL
GITHUB
QQ
WECHAT
}
enum TaskPriority {
LOW
MEDIUM
HIGH
URGENT
}
enum TaskStatus {
TODO
IN_PROGRESS
DONE
ARCHIVED
}
enum AttachmentType {
IMAGE
VIDEO
FILE
LINK
}
enum AiChannel {
USER_KEY
ASTRBOT
PUBLIC_POOL
}
enum NotificationChannel {
EMAIL
WEB_PUSH
}
enum NotificationStatus {
PENDING
SENT
FAILED
CANCELED
}
model User {
id String @id @default(cuid())
email String @unique
nickname String?
avatarUrl String?
status UserStatus @default(ACTIVE)
defaultStorageQuotaMb Int @default(100)
usedStorageBytes BigInt @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
identities AuthIdentity[]
refreshTokens RefreshToken[]
security UserSecurity?
tasks Task[]
tags Tag[]
attachments Attachment[]
taskActivityLogs TaskActivityLog[]
syncOperations SyncOperation[]
syncCursors SyncCursor[]
taskTombstones TaskTombstone[]
aiProviderBindings AiProviderBinding[]
aiUsageLogs AiUsageLog[]
notificationRules NotificationRule[]
notificationJobs NotificationJob[]
createdAdminTokens AdminToken[]
auditLogs AuditLog[]
@@map("users")
}
model AuthIdentity {
id String @id @default(cuid())
userId String
provider AuthProvider
providerUserId String
email String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerUserId])
@@index([userId])
@@map("auth_identities")
}
model UserSecurity {
id String @id @default(cuid())
userId String @unique
twoFactorEnabled Boolean @default(false)
twoFactorSecret String?
recoveryCodes String[] @default([])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("user_security")
}
model RefreshToken {
id String @id @default(cuid())
userId String
tokenHash String @unique
deviceId String?
expiresAt DateTime
revokedAt DateTime?
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, expiresAt])
@@map("refresh_tokens")
}
model Task {
id String @id @default(cuid())
userId String
title String
contentJson Json?
contentText String?
priority TaskPriority @default(MEDIUM)
status TaskStatus @default(TODO)
ddl DateTime?
completedAt DateTime?
version Int @default(1)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
taskTags TaskTag[]
attachments Attachment[]
activityLogs TaskActivityLog[]
notificationJobs NotificationJob[]
notificationRules NotificationRule[]
@@index([userId, status])
@@index([userId, ddl])
@@map("tasks")
}
model Tag {
id String @id @default(cuid())
userId String
name String
color String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
taskTags TaskTag[]
@@unique([userId, name])
@@index([userId])
@@map("tags")
}
model TaskTag {
taskId String
tagId String
createdAt DateTime @default(now())
task Task @relation(fields: [taskId], references: [id], onDelete: Cascade)
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
@@id([taskId, tagId])
@@index([tagId])
@@map("task_tags")
}
model Attachment {
id String @id @default(cuid())
userId String
taskId String?
type AttachmentType
url String
mimeType String?
fileName String?
fileSize Int
width Int?
height Int?
durationMs Int?
checksum String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
task Task? @relation(fields: [taskId], references: [id], onDelete: SetNull)
@@index([userId])
@@index([taskId])
@@map("attachments")
}
model TaskActivityLog {
id String @id @default(cuid())
userId String
taskId String
action String
payload Json?
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
task Task @relation(fields: [taskId], references: [id], onDelete: Cascade)
@@index([taskId, createdAt])
@@index([userId, createdAt])
@@map("task_activity_logs")
}
model SyncOperation {
id String @id @default(cuid())
opId String @unique
userId String
deviceId String
entityType String
entityId String
action String
payload Json?
clientTs DateTime
serverTs DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, deviceId, serverTs])
@@index([userId, entityType, entityId])
@@map("sync_operations")
}
model SyncCursor {
id String @id @default(cuid())
userId String
deviceId String
lastPulledAt DateTime?
lastOperationServerTs DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([userId, deviceId])
@@map("sync_cursors")
}
model TaskTombstone {
id String @id @default(cuid())
taskId String @unique
userId String
deletedAt DateTime @default(now())
deleteOpId String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, deletedAt])
@@map("task_tombstones")
}
model AiProviderBinding {
id String @id @default(cuid())
userId String
channel AiChannel
providerName String
model String?
encryptedApiKey String?
endpoint String?
isDefault Boolean @default(false)
isEnabled Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, isEnabled])
@@map("ai_provider_bindings")
}
model AiPublicPoolConfig {
id String @id @default(cuid())
enabled Boolean @default(false)
providerName String?
model String?
encryptedApiKey String?
endpoint String?
rpmLimit Int @default(60)
dailyTokenLimit Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("ai_public_pool_config")
}
model AiUsageLog {
id String @id @default(cuid())
userId String?
channel AiChannel
providerName String?
model String?
promptTokens Int @default(0)
completionTokens Int @default(0)
totalTokens Int @default(0)
latencyMs Int?
success Boolean @default(true)
errorCode String?
createdAt DateTime @default(now())
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
@@index([userId, createdAt])
@@index([channel, createdAt])
@@map("ai_usage_logs")
}
model NotificationRule {
id String @id @default(cuid())
userId String
taskId String?
channel NotificationChannel @default(EMAIL)
advanceMinutes Int @default(60)
enabled Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
task Task? @relation(fields: [taskId], references: [id], onDelete: SetNull)
jobs NotificationJob[]
@@index([userId, enabled])
@@index([taskId])
@@map("notification_rules")
}
model NotificationJob {
id String @id @default(cuid())
userId String
taskId String?
ruleId String?
channel NotificationChannel
scheduledAt DateTime
sentAt DateTime?
status NotificationStatus @default(PENDING)
retryCount Int @default(0)
errorMessage String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
task Task? @relation(fields: [taskId], references: [id], onDelete: SetNull)
rule NotificationRule? @relation(fields: [ruleId], references: [id], onDelete: SetNull)
@@index([status, scheduledAt])
@@index([userId, createdAt])
@@map("notification_jobs")
}
model SystemSetting {
id String @id @default(cuid())
key String @unique
value Json
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("system_settings")
}
model AdminToken {
id String @id @default(cuid())
tokenHash String @unique
name String
expiresAt DateTime
lastUsedAt DateTime?
revokedAt DateTime?
createdAt DateTime @default(now())
createdByUserId String?
createdByUser User? @relation(fields: [createdByUserId], references: [id], onDelete: SetNull)
@@index([expiresAt])
@@map("admin_tokens")
}
model AuditLog {
id String @id @default(cuid())
actorUserId String?
action String
targetType String
targetId String?
meta Json?
ip String?
userAgent String?
createdAt DateTime @default(now())
actorUser User? @relation(fields: [actorUserId], references: [id], onDelete: SetNull)
@@index([action, createdAt])
@@index([actorUserId, createdAt])
@@map("audit_logs")
}