generator client { provider = "prisma-client-js" } datasource db { provider = "mysql" url = env("DATABASE_URL") } /// 用户及个人设置 model User { /// 唯一标识 id String @id @default(uuid()) @db.Char(36) /// 登录用户名,唯一 username String @unique @db.VarChar(64) /// 登录密码的 bcrypt 哈希,不存储明文 passwordHash String @db.VarChar(255) /// 本位币代码 baseCurrency String @default("CNY") @db.Char(3) /// 隐藏菜单标识列表 hiddenMenus String @default("") @db.VarChar(128) /// 登录有效时长,单位小时,范围 1 至 720 sessionHours Int @default(168) /// 查看隐藏项目是否需要再次验证密码 requireHiddenPassword Boolean @default(true) /// 总览显示的卡片键列表,空值表示默认全部显示 overviewCards Json? /// 独立资产是否参与资产总览和净资产轨迹 includeIndependentAssets Boolean @default(true) /// 账户分组显示顺序;空值表示沿用默认顺序 accountGroupOrder Json? /// 是否显示备注 showNotes Boolean @default(true) /// 无操作退出分钟数,0 表示关闭 idleMinutes Int @default(30) /// 记录创建时间,UTC createdAt DateTime @default(now()) /// 记录更新时间,UTC updatedAt DateTime @updatedAt positions Position[] rates ExchangeRate[] metalPrices MetalPrice[] sessions Session[] icons Icon[] transfers Transfer[] schedules Schedule[] agentGrants AgentGrant[] agentOperations AgentOperation[] agentAuthorizations AgentAuthorization[] agentPolicy AgentPolicy? agentCalls AgentCall[] } /// MCP 调用审计,不保存工具参数、令牌、密码或财务内容 model AgentCall { /// 审计记录标识 id String @id @default(uuid()) @db.Char(36) /// 可信认证上下文中的用户标识 userId String @db.Char(36) /// 所属用户;注销后级联清理 user User @relation(fields:[userId],references:[id],onDelete:Cascade) /// 发起调用的连接标识 grantId String @db.Char(36) /// 工具名称 tool String @db.VarChar(100) /// 结果状态 success 或 error status String @db.VarChar(16) /// 调用完成时间,UTC createdAt DateTime @default(now()) @@index([userId,createdAt]) } /// 用户的 Agent 写入策略 model AgentPolicy { /// 所属用户标识,用于数据隔离 userId String @id @db.Char(36) user User @relation(fields:[userId],references:[id],onDelete:Cascade) /// 写入策略:readonly 只读、draft 草稿、direct 普通直接写入 mode String @default("draft") @db.VarChar(16) } /// OAuth 动态注册客户端元数据 model AgentClient { /// 唯一标识 id String @id @db.Char(36) /// 公开客户端注册元数据,不保存用户凭据 metadata Json /// 创建时间,UTC createdAt DateTime @default(now()) } /// 短期 OAuth 授权请求及一次性授权码摘要 model AgentAuthorization { /// 唯一标识 id String @id @default(uuid()) @db.Char(36) /// 所属用户标识,用于数据隔离 userId String? @db.Char(36) user User? @relation(fields:[userId],references:[id],onDelete:Cascade) /// OAuth 客户端标识;个人令牌为空 clientId String @db.Char(36) /// 具体操作参数;禁止保存密码及令牌 parameters Json /// 一次性授权码 SHA-256 摘要 codeDigest String? @unique @db.Char(64) /// 到期时间,UTC expiresAt DateTime /// 当前处理状态 status String @default("pending") @db.VarChar(16) } /// 用户授权连接、令牌摘要及资源权限 model AgentGrant { /// 唯一标识 id String @id @default(uuid()) @db.Char(36) /// 所属用户标识,用于数据隔离 userId String @db.Char(36) user User @relation(fields:[userId],references:[id],onDelete:Cascade) /// OAuth 客户端标识;个人令牌为空 clientId String? @db.Char(36) /// 用户可见连接名称 name String @db.VarChar(100) /// 权限列表:read、draft、write、sensitive scopes Json /// 令牌适用的规范 MCP 资源地址 resource String @db.VarChar(500) /// 访问令牌 SHA-256 摘要;完整值仅颁发时返回 accessDigest String @unique @db.Char(64) /// 刷新令牌 SHA-256 摘要,使用后轮换 refreshDigest String? @unique @db.Char(64) /// 到期时间,UTC expiresAt DateTime /// 刷新授权到期时间,UTC refreshExpiresAt DateTime? /// 撤销时间,UTC;空表示未撤销 revokedAt DateTime? /// 本连接的独立业务授权会话标识,不作为 MCP 凭证 sessionId String @db.Char(64) /// 创建时间,UTC createdAt DateTime @default(now()) @@index([userId,createdAt]) } /// Agent 写入草稿、幂等记录及提交结果 model AgentOperation { /// 唯一标识 id String @id @default(uuid()) @db.Char(36) /// 所属用户标识,用于数据隔离 userId String @db.Char(36) user User @relation(fields:[userId],references:[id],onDelete:Cascade) /// 发起操作的授权连接标识 grantId String @db.Char(36) /// 同用户唯一的客户端幂等键 key String @db.VarChar(128) /// 工具和参数的规范摘要;拒绝同键不同参数 hash String @db.Char(64) /// 业务工具名称 tool String @db.VarChar(100) /// 具体操作参数;禁止保存密码及令牌 parameters Json /// 确认前的账目版本摘要,防止覆盖并发修改 snapshot String @db.Char(64) /// 当前处理状态 status String @default("pending") @db.VarChar(16) /// 到期时间,UTC expiresAt DateTime /// 结构化操作结果或最近提交失败原因 result Json? /// 创建时间,UTC createdAt DateTime @default(now()) /// 完成或取消时间,UTC completedAt DateTime? @@unique([userId,key]) @@index([userId,createdAt]) } /// 登录会话与隐藏项目查看授权 model Session { /// 随机会话令牌的 SHA-256 摘要 id String @id @db.Char(64) /// 所属用户标识,用于数据隔离 userId String @db.Char(36) user User @relation(fields:[userId],references:[id],onDelete:Cascade) /// 会话过期时间,UTC expiresAt DateTime /// 最后有效交互时间,UTC lastActivity DateTime @default(now()) /// 隐藏项目授权截止时间,UTC;空表示未解锁 revealUntil DateTime? /// 已下载备份内容的 SHA-256 摘要 backupDigest String? @db.Char(64) /// 备份清空确认凭据截止时间,UTC backupExpiresAt DateTime? @@index([userId]) } /// 持有项目:账户、独立资产和借入借出债务 model Position { /// 唯一标识 id String @id @default(uuid()) @db.Char(36) /// 备份导入来源项目标识,用于重复导入识别 importedFromId String? @db.Char(36) /// 所属用户标识,用于数据隔离 userId String @db.Char(36) user User @relation(fields:[userId],references:[id],onDelete:Cascade) /// 项目类型:account 账户、asset 独立资产、debt 债务 kind String @db.VarChar(16) /// 统计方向:asset 资产或借出应收、liability 负债或借入应付 side String @db.VarChar(16) /// 显示名称 name String @db.VarChar(100) /// 项目分类代码 category String @db.VarChar(40) /// 自定义账户分组;空字符串表示未分组 groupName String @default("") @db.VarChar(60) /// 原始币种代码 currency String @db.Char(3) /// 用户备注,原文保留 notes String @db.Text /// 是否归档;归档项目仍计入总额 archived Boolean @default(false) /// 是否隐藏;未解锁时不参与可见范围统计 hidden Boolean @default(false) /// 是否参与资产负债总额及净资产轨迹 included Boolean @default(true) /// 贵金属品种:gold 黄金或 silver 白银 metalType String? @db.VarChar(12) /// 贵金属总重量,单位克 metalGrams Decimal? @db.Decimal(24,8) /// 贵金属纯度比例,0 至 1 metalPurity Decimal @default(1) @db.Decimal(12,8) /// 买入时每克实物成本,原币;空值表示不计算盈亏 metalCostPerGram Decimal? @db.Decimal(24,12) /// 是否随每日价格更新自动记录估值 autoValuation Boolean @default(false) /// 记录创建时间,UTC createdAt DateTime @default(now()) /// 记录更新时间,UTC updatedAt DateTime @updatedAt /// 关联账户图标标识 iconId String? @db.Char(36) icon Icon? @relation(fields:[iconId],references:[id],onDelete:SetNull) revisions Revision[] outgoing PositionLink[] @relation("Source") incoming PositionLink[] @relation("Target") transfersOut Transfer[] @relation("TransferSource") transfersIn Transfer[] @relation("TransferTarget") @@index([userId,kind]) @@unique([userId,importedFromId]) } /// 余额历史:金额为变更后的绝对余额 model Revision { /// 唯一标识 id String @id @default(uuid()) @db.Char(36) /// 数据库自增唯一顺序,同业务时间按此排序 sequence Int @unique @default(autoincrement()) /// 所属持有项目标识 positionId String @db.Char(36) position Position @relation(fields:[positionId],references:[id],onDelete:Cascade) /// 变更后的原币绝对余额,不是收支增量,禁止对全部历史求和 /// 负债账户正数为欠款,负数为溢缴存款;前端显示符号相反 amount Decimal @db.Decimal(24,8) /// 北京时间业务时间对应的 UTC,精确到分钟 effectiveDate DateTime @db.DateTime(3) /// 用户备注,原文保留 notes String @db.Text /// 变更原因:初始、余额、估值、转账或借贷配对操作 reason String @db.VarChar(20) /// 记录创建时间,UTC createdAt DateTime @default(now()) /// 记录更新时间,UTC updatedAt DateTime @updatedAt @@index([positionId,effectiveDate,sequence]) @@index([positionId,reason,effectiveDate,sequence]) } /// 项目关联关系,不参与金额求和 model PositionLink { /// 唯一标识 id String @id @default(uuid()) @db.Char(36) /// 关联来源项目标识,通常为债务 sourceId String @db.Char(36) /// 关联目标项目标识,通常为账户或资产 targetId String @db.Char(36) source Position @relation("Source",fields:[sourceId],references:[id],onDelete:Cascade) target Position @relation("Target",fields:[targetId],references:[id],onDelete:Cascade) @@unique([sourceId,targetId]) } /// 用户原币兑本位币的历史汇率 model ExchangeRate { /// 唯一标识 id String @id @default(uuid()) @db.Char(36) /// 所属用户标识,用于数据隔离 userId String @db.Char(36) user User @relation(fields:[userId],references:[id],onDelete:Cascade) /// 原始币种代码 currency String @db.Char(3) /// 本位币代码 baseCurrency String @db.Char(3) /// 汇率业务日期 date DateTime @db.Date /// 每单位原币对应的本位币金额 rate Decimal @db.Decimal(24,12) /// 汇率来源标识,保留已有历史来源 source String @db.VarChar(30) @@unique([userId,currency,baseCurrency,date]) } /// 可复用账户图标 model Icon { /// 唯一标识 id String @id @default(uuid()) @db.Char(36) /// 上传用户标识;空可表示系统图标或原用户已删除 ownerId String? @db.Char(36) owner User? @relation(fields:[ownerId],references:[id],onDelete:SetNull) /// 显示名称 name String @db.VarChar(100) /// 是否公开共享给已登录用户 shared Boolean @default(false) /// 规范化图标内容的 SHA-256 摘要 hash String @db.Char(64) /// 规范化静态 PNG 图片二进制 data Bytes @db.MediumBlob /// 可选公开来源网址 source String? @db.VarChar(500) /// 记录创建时间,UTC createdAt DateTime @default(now()) positions Position[] @@unique([ownerId,hash,shared]) @@index([shared,name]) } /// 资金往来及账户与债务的双边配对记账 model Transfer { /// 唯一标识 id String @id @default(uuid()) @db.Char(36) /// 备份导入来源项目标识,用于重复导入识别 importedFromId String? @db.Char(36) /// 所属用户标识,用于数据隔离 userId String @db.Char(36) user User @relation(fields:[userId],references:[id],onDelete:Cascade) /// 来源资产账户标识 sourceId String @db.Char(36) /// 目标账户或债务标识 targetId String @db.Char(36) source Position @relation("TransferSource",fields:[sourceId],references:[id],onDelete:Cascade) target Position @relation("TransferTarget",fields:[targetId],references:[id],onDelete:Cascade) /// 来源账户配对余额历史标识 sourceRevisionId String @unique @db.Char(36) /// 目标项目配对余额历史标识 targetRevisionId String @unique @db.Char(36) /// 来源账户币种 sourceCurrency String @db.Char(3) /// 目标项目币种 targetCurrency String @db.Char(3) /// 本次来源账户本金金额,不是变更后余额 amount Decimal @db.Decimal(24,8) /// 本次目标到账金额或债务本金金额 received Decimal @db.Decimal(24,8) /// 来源币种手续费;负数表示优惠 fee Decimal @db.Decimal(24,8) /// 北京时间业务时间对应的 UTC,精确到分钟 effectiveDate DateTime @db.DateTime(3) /// 用户备注,原文保留 notes String @db.Text /// 操作类型:transfer 转账、borrow 借入、lend 借出、collect 收款、repay 还款 operation String @default("transfer") @db.VarChar(16) /// 记录创建时间,UTC createdAt DateTime @default(now()) @@unique([userId,importedFromId]) @@index([userId,effectiveDate,id]) } /// 按需执行的定时支出或转账计划 model Schedule { /// 唯一标识 id String @id @default(uuid()) @db.Char(36) /// 所属用户标识,用于数据隔离 userId String @db.Char(36) user User @relation(fields:[userId],references:[id],onDelete:Cascade) /// 备份来源计划标识,用于重复导入识别 importedFromId String? @db.Char(36) /// 计划显示名称 name String @db.VarChar(100) /// 操作类型:expense 支出或 transfer 转账 operation String @db.VarChar(16) /// 支出或转出资产账户标识 sourceId String @db.Char(36) /// 转入账户标识;支出计划为空 targetId String? @db.Char(36) /// 原币支出或转出金额 amount Decimal @db.Decimal(24,8) /// 原币到账金额;支出计划为零 received Decimal @db.Decimal(24,8) /// 下次到期业务时间对应的 UTC nextAt DateTime @db.DateTime(3) /// 重复间隔天数;零表示仅执行一次 intervalDays Int /// 是否启用计划 enabled Boolean @default(true) /// 一次性计划是否已执行完毕 completed Boolean @default(false) /// 用户备注,原文保留 notes String @db.Text @@index([userId,enabled,nextAt]) @@unique([userId,importedFromId]) } /// 用户的贵金属每克参考价历史 model MetalPrice { /// 唯一标识 id String @id @default(uuid()) @db.Char(36) /// 所属用户标识,用于数据隔离 userId String @db.Char(36) user User @relation(fields:[userId],references:[id],onDelete:Cascade) /// 品种:gold 黄金或 silver 白银 metalType String @db.VarChar(12) /// 价格币种 currency String @db.Char(3) /// 纯金属每克价格 price Decimal @db.Decimal(24,12) /// 报价日期,UTC+8 自然日 date DateTime @db.Date /// 价格来源:manual 或 goldapi source String @db.VarChar(20) /// 报价对应时间,UTC quotedAt DateTime @db.DateTime(3) @@unique([userId, metalType, currency, date]) }