// Kokorone 資料模型 // R-2 會將 provider 由 sqlite 切換為 postgresql,並為 MemoryRetriever 加上 pgvector 語意檢索。 generator client { provider = "prisma-client" output = "../packages/db/generated" } datasource db { provider = "sqlite" } enum CharacterSource { ORIGINAL // 原創 EXISTING_WORK // 既有作品 } enum CharacterBuildStatus { CANDIDATE // 候補 BUILT // 已建置 } enum MemorySource { INTERACTION // 互動 OFFLINE_GENERATED // 離線生成 SOURCE_EXTRACTION // 原作萃取 } // 情緒標籤類型:對應情緒子系統六種狀態(見 D 群組) enum EmotionTag { CALM // 平靜 JOY // 愉悅 SAD // 低落 ALERT // 警戒 SHY // 害羞 GRUMPY // 彆扭 } enum RelationshipStage { STRANGER // 陌生 0-19 ACQUAINTANCE // 認識 20-39 FRIEND // 朋友 40-59 CLOSE_AMBIGUOUS // 摯友-曖昧 60-79 BONDED // 羈絆 80-100 } // I-1 週期表:平日/週末/假期各一份時段表 enum ScheduleDayType { WEEKDAY // 平日 WEEKEND // 週末 HOLIDAY // 假期/特殊日 } enum ScheduleSlotStatus { SLEEP // 睡眠 BUSY // 忙碌 SEMI_BUSY // 半忙碌 FREE // 空閒 } // J-1 委託類型 enum TaskType { ONE_TIME // 單次提醒 RECURRING // 週期提醒 CONDITIONAL // 條件提醒 QUERY_ORGANIZE // 查詢整理 TODO_TRACKING // 代辦追蹤 } enum TaskStatus { PENDING // 尚未觸發 TRIGGERED // 已觸發,等候使用者回應 COMPLETED // 已完成 FAILED // 執行失敗 CANCELLED // 已取消 } model User { id String @id @default(cuid()) name String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt relationships Relationship[] relatedMemories EpisodicMemory[] tasks Task[] @@map("users") } model Work { id String @id @default(cuid()) title String volumeProgress String? // 卷數進度 worldview String? // 世界觀 progressAnchor String? // 作品進度錨定點(M-9/N 群組使用;描述作品實際描寫過的時期) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt characters Character[] @@map("works") } model Character { id String @id @default(cuid()) workId String? work Work? @relation(fields: [workId], references: [id], onDelete: SetNull) source CharacterSource buildStatus CharacterBuildStatus @default(CANDIDATE) // 角色設定表七欄位 basicInfo String // 基本資料:名字、年齡、外型、出身 backgroundStory String // 背景故事:成長經歷、重大事件 personalityArchetype String // 性格原型:傲嬌/冷淡/天然呆/元氣/大小姐/三無 likesDislikes String // 喜好/厭惡 goalsObsessions String // 目標/執念 speechStyle String // 說話方式:口癖、語尾詞、第一/第二人稱 initialRelationValue String? // 人際初始值:對誰親近、對誰有心結 createdAt DateTime @default(now()) updatedAt DateTime @updatedAt aliases CharacterAlias[] episodicMemories EpisodicMemory[] semanticMemories SemanticMemory[] proceduralRules ProceduralRule[] emotionState EmotionState? relationships Relationship[] contrastTriggerLogs ContrastTriggerLog[] scheduleSlots ScheduleSlot[] specialDays SpecialDay[] scheduleExceptions ScheduleExceptionLog[] tasks Task[] proactiveCareLogs ProactiveCareLog[] relationshipsToOthers CharacterRelationship[] @relation("RelationshipFrom") relationshipsFromOthers CharacterRelationship[] @relation("RelationshipTo") @@map("characters") } // K-2/K-4 角色間關係:群聊中「角色間關係上場」與發言權分配的「與發言者的關係」都吃這張表。 // 有向邊(characterId 對 otherCharacterId 的觀感),故同作品兩角色互相的觀感可以不對稱。 model CharacterRelationship { id String @id @default(cuid()) characterId String character Character @relation("RelationshipFrom", fields: [characterId], references: [id], onDelete: Cascade) otherCharacterId String otherCharacter Character @relation("RelationshipTo", fields: [otherCharacterId], references: [id], onDelete: Cascade) affinity Int @default(50) // 0~100,越高越要好;50 為中性 dynamic String? // 互動基調描述性標籤,例如 loyal-friend/rival/protective/crush createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([characterId, otherCharacterId]) @@map("character_relationships") } // G-4 反差萌稀有度控制:記錄每次反差行為觸發的時間,供冷卻期判定。 model ContrastTriggerLog { id String @id @default(cuid()) characterId String character Character @relation(fields: [characterId], references: [id], onDelete: Cascade) triggeredAt DateTime @default(now()) @@map("contrast_trigger_logs") } // I-1 作息表:平日/週末/假期各一份時段表,每個時段一列。 model ScheduleSlot { id String @id @default(cuid()) characterId String character Character @relation(fields: [characterId], references: [id], onDelete: Cascade) dayType ScheduleDayType startMinute Int // 當天 00:00 起算的分鐘數(0~1440),跨午夜的時段請拆成兩列 endMinute Int status ScheduleSlotStatus label String? // 固定行程名稱,例如「社團活動」 @@map("schedule_slots") } // I-1 特殊日:考試週、生日、原作紀念日——當天整天視為 HOLIDAY 作息。 model SpecialDay { id String @id @default(cuid()) characterId String character Character @relation(fields: [characterId], references: [id], onDelete: Cascade) date DateTime // 只使用日期部分(比對年/月/日) label String @@map("special_days") } // I-4 破例規則:記錄每種破例最後一次觸發的時間,供稀有度冷卻判定。 model ScheduleExceptionLog { id String @id @default(cuid()) characterId String character Character @relation(fields: [characterId], references: [id], onDelete: Cascade) exceptionType String // LATE_NIGHT_CHAT/SNEAK_REPLY_IN_CLASS/ADJUST_SCHEDULE triggeredAt DateTime @default(now()) @@map("schedule_exception_logs") } model CharacterAlias { id String @id @default(cuid()) characterId String character Character @relation(fields: [characterId], references: [id], onDelete: Cascade) formalName String // 正式名 nickname String? // 暱稱 calledByOthers String? // 他人稱呼(作品中其他角色如何稱呼) createdAt DateTime @default(now()) @@map("character_aliases") } model EpisodicMemory { id String @id @default(cuid()) characterId String character Character @relation(fields: [characterId], references: [id], onDelete: Cascade) content String occurredAt DateTime // 發生時間 emotionTag EmotionTag emotionIntensity Float // 情緒強度 retrievalCount Int @default(0) // 提取次數 lastRetrievedAt DateTime? source MemorySource weight Float @default(1) // 權重(供遺忘/檢索排序使用) relatedUserId String? // 這段記憶與哪位使用者相關(E-5 關係加權檢索用) relatedUser User? @relation(fields: [relatedUserId], references: [id], onDelete: SetNull) isPrivate Boolean @default(false) // K-3 隱私邊界:一對一聊過的私密內容,群聊中不主動洩漏(口風不緊原型除外) createdAt DateTime @default(now()) @@map("episodic_memories") } model SemanticMemory { id String @id @default(cuid()) characterId String character Character @relation(fields: [characterId], references: [id], onDelete: Cascade) fact String // 去情境化事實 about String // 對象(關於誰/什麼) createdAt DateTime @default(now()) @@map("semantic_memories") } model ProceduralRule { id String @id @default(cuid()) characterId String character Character @relation(fields: [characterId], references: [id], onDelete: Cascade) situation String // 情境 responsePattern String // 回應模式 weight Float @default(1) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@map("procedural_rules") } model EmotionState { id String @id @default(cuid()) characterId String @unique character Character @relation(fields: [characterId], references: [id], onDelete: Cascade) calm Float @default(100) // 平靜 joy Float @default(0) // 愉悅 sad Float @default(0) // 低落 alert Float @default(0) // 警戒 shy Float @default(0) // 害羞 grumpy Float @default(0) // 彆扭 updatedAt DateTime @updatedAt @@map("emotion_states") } model Relationship { id String @id @default(cuid()) characterId String character Character @relation(fields: [characterId], references: [id], onDelete: Cascade) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) intimacy Int @default(0) // 親密度 0~100 trust Int @default(0) // 信任度 0~100 firstMet DateTime? lastInteraction DateTime? interactionCount Int @default(0) stage RelationshipStage @default(STRANGER) ledgerEntries SentimentLedgerEntry[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([characterId, userId]) @@map("relationships") } model SentimentLedgerEntry { id String @id @default(cuid()) relationshipId String relationship Relationship @relation(fields: [relationshipId], references: [id], onDelete: Cascade) date DateTime event String weight Float // 允許正負:正向事件為正值,負向事件為負值 createdAt DateTime @default(now()) @@map("sentiment_ledger_entries") } // J-1 委託:使用者請角色做的事。執行(觸發準時度)是引擎責任,演出(接案/觸發/追擊的台詞)是角色責任。 model Task { id String @id @default(cuid()) characterId String character Character @relation(fields: [characterId], references: [id], onDelete: Cascade) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) type TaskType content String // 委託內容(去除時間片語後的純委託描述,例如「開會」) rawText String // 使用者原始輸入,供回顧/記憶引用 triggerAt DateTime? // 單次提醒的觸發時間;週期提醒改用 cronExpression cronExpression String? // 週期提醒(node-cron 表達式) condition String? // 條件提醒的條件描述(MVP 為文字紀錄,不做真實環境條件監測) status TaskStatus @default(PENDING) triggeredAt DateTime? // 最近一次實際觸發的時間 triggerMessage String? // 最近一次觸發演出的訊息內容(供前端/測試輪詢) overdueNudgeCount Int @default(0) // J-4 逾期追擊次數 lastNudgeAt DateTime? completedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@map("tasks") } // J-6 主動關照:記錄每次主動關心的觸發時間與內容,供稀有度節流與「不重複台詞」判定。 model ProactiveCareLog { id String @id @default(cuid()) characterId String character Character @relation(fields: [characterId], references: [id], onDelete: Cascade) userId String message String triggeredAt DateTime @default(now()) @@map("proactive_care_logs") }