haixunMaster/prisma/schema.prisma

344 lines
11 KiB
Plaintext
Raw Permalink 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.

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
email String @unique
passwordHash String
name String?
activeAccountId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accounts Account[]
sessions Session[]
settings Setting?
}
model Session {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
token String @unique
expiresAt DateTime
createdAt DateTime @default(now())
}
model Account {
id String @id @default(cuid())
userId String?
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
username String?
displayName String?
persona String?
styleProfile String?
styleBenchmark String?
brief String?
productBrief String?
targetAudience String?
goals String?
storageState String @default("")
valid Boolean @default(true)
threadsAccessToken String?
threadsUserId String?
threadsTokenExpiresAt DateTime?
automationEnabled Boolean @default(false)
searchViaApi Boolean @default(false)
/// mixed | threads | brave | crawler | threads_brave | threads_crawler | brave_crawler
searchSourceMode String @default("mixed")
publishViaApi Boolean @default(false)
devMode Boolean @default(true)
scrapeReplies Boolean @default(true)
repliesPerPost Int @default(10)
publishHeaded Boolean @default(false)
playwrightDebug Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
automationRules AutomationRule[]
}
/// 每帳號 × 每任務的自動化規則mode=manual 先審核mode=auto 自動執行(受 dailyCap 與排程限制)
model AutomationRule {
id String @id @default(cuid())
accountId String
account Account @relation(fields: [accountId], references: [id], onDelete: Cascade)
taskType String // scan | generate | outreach | engagement | publish
mode String @default("manual") // manual | auto
dailyCap Int @default(20)
schedule String @default("0 9 * * *")
enabled Boolean @default(false)
lastRunAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([accountId, taskType])
}
/// 自動化動作稽核紀錄,供成效回溯與「殺停」後檢視
model ActionLog {
id String @id @default(cuid())
accountId String?
taskType String // scan | generate | outreach | engagement | publish
action String // publish-post | reply-outreach | reply-inbound | scan | generate
mode String @default("auto") // auto | manual
status String @default("success") // success | failed | skipped
targetId String?
externalId String?
permalink String?
detail String?
error String?
createdAt DateTime @default(now())
}
model BrandProfile {
id String @id @default(cuid())
accountId String?
name String
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
products ProductProfile[]
topics Topic[]
}
model ProductProfile {
id String @id @default(cuid())
accountId String?
brandId String?
brand BrandProfile? @relation(fields: [brandId], references: [id], onDelete: Cascade)
label String
context String @default("")
matchTags String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
topics Topic[]
}
model Topic {
id String @id @default(cuid())
accountId String?
label String
query String
brief String?
productContext String?
brandProfileId String?
brandProfile BrandProfile? @relation(fields: [brandProfileId], references: [id], onDelete: SetNull)
productProfileId String?
productProfile ProductProfile? @relation(fields: [productProfileId], references: [id], onDelete: SetNull)
topicGoal String @default("viral")
researchMap String?
selectedTags String?
active Boolean @default(true)
createdAt DateTime @default(now())
scans Scan[]
}
model Scan {
id String @id @default(cuid())
accountId String?
topicId String
topic Topic @relation(fields: [topicId], references: [id], onDelete: Cascade)
scanMode String @default("single")
scanGoal String @default("viral")
scanTags String?
searchSource String? // api | browser | web | hybrid這次海巡實際用哪種方式找到貼文
repliesFetched Boolean @default(false) // 是否有抓到別人貼文的留言(需瀏覽器)
repliesCount Int @default(0) // 抓到的留言則數
createdAt DateTime @default(now())
items ScanItem[]
}
model ScanItem {
id String @id @default(cuid())
scanId String
scan Scan @relation(fields: [scanId], references: [id], onDelete: Cascade)
externalId String?
text String
permalink String?
authorName String?
postedAt DateTime?
likeCount Int?
replyCount Int?
score Float
searchTag String?
relevanceScore Float?
placementScore Float?
placementReason String?
qualityTier String?
qualityReason String?
combinedScore Float?
mediaUrls String?
mediaType String?
viralAnalysis String?
replies Reply[]
outreachTargets OutreachTarget[]
}
model Reply {
id String @id @default(cuid())
scanItemId String
scanItem ScanItem @relation(fields: [scanItemId], references: [id], onDelete: Cascade)
text String
authorName String?
likeCount Int?
postedAt DateTime?
}
model Draft {
id String @id @default(cuid())
accountId String?
topicId String?
text String
angle String?
rationale String?
hook String?
referenceNotes String?
searchTag String?
sortOrder Int?
sources String?
draftType String?
imageBrief String?
imagePath String?
imagePaths String?
scanItemId String?
status String @default("PENDING")
factCheckResult String?
createdAt DateTime @default(now())
}
model Published {
id String @id @default(cuid())
accountId String?
topicId String?
externalId String?
text String
angle String?
hook String?
rationale String?
draftType String?
permalink String?
publishedAt DateTime @default(now())
views Int?
likes Int?
replies Int?
reposts Int?
quotes Int?
snapshots PerformanceSnapshot[]
inboundReplies InboundReply[]
}
model PerformanceSnapshot {
id String @id @default(cuid())
publishedId String?
published Published? @relation(fields: [publishedId], references: [id], onDelete: Cascade)
profileId String?
views Int?
likes Int?
replies Int?
reposts Int?
quotes Int?
followers Int?
source String @default("threads-api")
capturedAt DateTime @default(now())
}
model InboundReply {
id String @id @default(cuid())
publishedId String?
published Published? @relation(fields: [publishedId], references: [id], onDelete: Cascade)
externalId String? @unique
parentId String?
text String
authorName String?
permalink String?
postedAt DateTime?
likeCount Int?
sentiment String?
intent String?
status String @default("NEW")
createdAt DateTime @default(now())
replyDrafts ReplyDraft[]
}
model ReplyDraft {
id String @id @default(cuid())
inboundReplyId String
inboundReply InboundReply @relation(fields: [inboundReplyId], references: [id], onDelete: Cascade)
text String
rationale String?
status String @default("PENDING")
createdAt DateTime @default(now())
publishedAt DateTime?
}
model OutreachTarget {
id String @id @default(cuid())
scanItemId String
scanItem ScanItem @relation(fields: [scanItemId], references: [id], onDelete: Cascade)
status String @default("NEW")
relevance Float?
reason String?
createdAt DateTime @default(now())
drafts OutreachDraft[]
}
model OutreachDraft {
id String @id @default(cuid())
outreachTargetId String
outreachTarget OutreachTarget @relation(fields: [outreachTargetId], references: [id], onDelete: Cascade)
text String
angle String?
rationale String?
status String @default("PENDING")
createdAt DateTime @default(now())
publishedAt DateTime?
}
model BackgroundJob {
id String @id @default(cuid())
accountId String?
type String
status String @default("pending")
topicId String?
label String?
payload String?
result String?
error String?
progress String?
progressDetail String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
completedAt DateTime?
}
model Setting {
id String @id @default(cuid())
userId String? @unique
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
persona String?
aiProvider String @default("xai")
aiModel String @default("grok-3")
researchAiProvider String?
researchAiModel String?
draftsPerScan Int @default(4)
matrixRows Int @default(7)
scanCron String @default("0 9 * * *")
scrapeReplies Boolean @default(true)
repliesPerPost Int @default(10)
playwrightDebug Boolean @default(false)
providerApiKeys String?
threadsAppId String?
threadsAppSecret String?
appUrl String?
publishViaApi Boolean @default(true)
searchViaApi Boolean @default(true)
publishHeaded Boolean @default(true)
devMode Boolean @default(false)
connectionMigrated Boolean @default(false)
}