数据模型概览.md 19 KB

数据模型概览

本文档引用的文件

  • schema.prisma
  • index.ts
  • migrate-genstage.ts
  • sync-genstage.ts
  • book-generator.types.ts
  • stage-manager.ts
  • auth.service.ts
  • tts.service.ts
  • member.service.ts
  • book-generator.service.ts
  • seed-test-user.js

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖分析
  7. 性能考虑
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本文件面向AI有声书生成平台,系统性梳理Prisma ORM在该项目中的整体架构设计与数据模型组织方式。重点覆盖以下方面:

  • 数据模型的组织方式与关系映射策略
  • 关键实体(用户、书籍、章节等)的职责划分
  • 版本管理机制、迁移策略与向后兼容性保障
  • 使用Prisma客户端进行数据操作的最佳实践与示例路径

项目结构

本项目的数据层采用Prisma Schema集中定义,配合模块化的业务服务层进行读写操作。核心文件分布如下:

  • Prisma Schema:定义数据模型、关系、索引与约束
  • Prisma 客户端封装:统一初始化与连接管理
  • 迁移与同步脚本:历史数据迁移与状态同步
  • 业务服务:围绕模型进行CRUD与复杂事务处理

    graph TB
    subgraph "数据层"
    PRISMA["Prisma Schema<br/>server/prisma/schema.prisma"]
    MIGRATE["迁移脚本<br/>server/prisma/migrate-genstage.ts"]
    SYNC["同步脚本<br/>server/prisma/sync-genstage.ts"]
    end
    subgraph "应用层"
    MODELS["Prisma 客户端封装<br/>server/src/models/index.ts"]
    AUTH["认证服务<br/>server/src/modules/auth/auth.service.ts"]
    TTS["TTS服务<br/>server/src/modules/tts/tts.service.ts"]
    MEMBER["会员服务<br/>server/src/modules/member/member.service.ts"]
    GEN["书籍生成服务<br/>server/src/modules/book-generator/book-generator.service.ts"]
    STAGE["阶段管理器<br/>server/src/modules/book-generator/stage-manager.ts"]
    end
    PRISMA --> MODELS
    MIGRATE --> PRISMA
    SYNC --> PRISMA
    MODELS --> AUTH
    MODELS --> TTS
    MODELS --> MEMBER
    MODELS --> GEN
    GEN --> STAGE
    

图表来源

  • schema.prisma
  • index.ts
  • migrate-genstage.ts
  • sync-genstage.ts
  • auth.service.ts
  • tts.service.ts
  • member.service.ts
  • book-generator.service.ts
  • stage-manager.ts

章节来源

  • schema.prisma
  • index.ts

核心组件

本节从数据模型视角,介绍关键实体及其职责边界,并说明Prisma的关系映射与约束策略。

  • 用户(User)
    • 职责:平台用户主体,承载会员等级、用量统计、偏好设置等
    • 关系:一对多关联评论、草稿、收藏、订单、播放记录、歌单、签到、订阅、令牌余额与使用记录、偏好设置
    • 约束:手机号与微信OpenID唯一索引;自动维护创建/更新时间
  • 书籍(Book)
    • 职责:书籍主表,记录生成进度、状态、大纲与元数据
    • 关系:一对多章节;可选归属用户;一对多视频项目
    • 约束:复合索引覆盖用户+状态、创建时间
  • 章节(BookChapter)
    • 职责:章节树形结构(支持章/节/小节),记录内容、音频、视频、歌词与生成阶段
    • 关系:多对一所属书籍;一对多评论、播放记录、歌单项、视频项目
    • 约束:唯一索引确保同一层级内章节编号唯一;多维索引覆盖书籍、父子关系与层级
  • 生成阶段(genStage)与状态(status)
    • 设计理念:引入线性阶段字段统一管理生成流程,避免历史遗留的多字段状态分散
    • 书籍与章节分别定义阶段枚举,通过阶段管理器进行安全转移与资源清理
  • 订单(Order)与订阅(Subscription/Plan)
    • 职责:会员体系与消费闭环,包含套餐配置、购买记录与订阅生命周期
    • 关系:多对一用户与套餐;多对一书籍与章节(用于生成配额与令牌)
  • 其他重要实体
    • TokenBalance/TokenUsage:令牌余额与使用流水
    • PlayRecord/Playlist/PlaylistItem:播放记录与歌单
    • AudioRecord:音频生成记录(与书籍章节解耦)
    • Draft/Comment/Feedback/VideoProject/Search/HotSearch:支撑创作、互动与检索生态

章节来源

  • schema.prisma
  • book-generator.types.ts
  • stage-manager.ts

架构总览

下图展示Prisma数据模型在系统中的交互关系与典型调用链:

erDiagram
USER {
int id PK
string phone UK
string openid UK
string nickname
string avatar
int memberLevel
datetime memberExpireAt
int dailyUsage
string lastUsageDate
datetime createdAt
datetime updatedAt
}
ORDER {
int id PK
int userId FK
string orderNo UK
int planId FK
string productType
decimal amount
string status
string paymentMethod
string paymentId
datetime paidAt
datetime createdAt
datetime updatedAt
}
SUBSCRIPTION_PLAN {
int id PK
string name
int level
decimal priceMonthly
decimal priceYearly
string description
string features
boolean isRecommended
boolean isActive
int sortOrder
int dailyGenerations
int perGenerationLimit
int monthlyTokens
int monthlyMinutes
int yearlyTokens
int voiceOptions
string audioQuality
boolean apiAccess
boolean batchProcessing
boolean teamManagement
boolean overageEnabled
decimal overagePrice
datetime createdAt
datetime updatedAt
}
SUBSCRIPTION {
int id PK
int userId FK
int planId FK
datetime startDate
datetime endDate
string status
boolean autoRenew
datetime createdAt
datetime updatedAt
}
BOOK {
int id PK
int userId FK
string title
string subtitle
text description
string coverUrl
string targetAudience
string style
string bookScale
int totalChapters
int estimatedWords
int progress
boolean isPublished
longtext outlineJson
text foreword
text afterword
text errorMsg
datetime createdAt
datetime updatedAt
varchar failedStage
string genStage
string status
text bookAnalysis
}
BOOK_CHAPTER {
int id PK
int bookId FK
int parentId
int level
int number
string title
text summary
text keyPoints
int estimatedWords
longtext content
int wordCount
text contentError
datetime generatedAt
text audioUrl
int audioDuration
text videoUrl
int videoDuration
boolean isPublic
string genStage
string status
text lrcLyrics
}
PLAYLIST {
int id PK
int userId FK
string name
text description
datetime createdAt
datetime updatedAt
}
PLAYLIST_ITEM {
int id PK
int playlistId FK
int chapterId FK
string audioId
int order
}
PLAY_RECORD {
int id PK
int userId FK
int chapterId FK
float progress
float duration
datetime createdAt
datetime updatedAt
}
AUDIO_RECORD {
int id PK
int userId FK
string audioId UK
string title
longtext text
int wordCount
string voiceId
string voiceParams
text audioUrl
int audioDuration
int audioSize
string status
text errorMsg
datetime createdAt
datetime updatedAt
}
COMMENT {
int id PK
int userId FK
int chapterId FK
text content
int rating
datetime createdAt
}
DRAFT {
int id PK
int userId FK
string type
text title
longtext content
text metadata
datetime autoSavedAt
datetime createdAt
datetime updatedAt
}
TOKEN_BALANCE {
int id PK
int userId UK
int totalTokens
int usedTokens
datetime resetDate
datetime createdAt
datetime updatedAt
}
TOKEN_USAGE {
int id PK
int userId FK
string type
int amount
int contentLength
int orderId FK
text description
datetime createdAt
}
USER_PREFERENCE {
int id PK
int userId UK
float playSpeed
string quality
string theme
string defaultVoiceId
int defaultVolume
boolean autoPlayNext
boolean wifiOnlyDownload
datetime createdAt
datetime updatedAt
}
VIDEO_PROJECT {
int id PK
int userId FK
string title
text description
string coverUrl
longtext configJson
string outputUrl
int duration
int fileSize
int bookId FK
int chapterId FK
string status
int progress
text errorMsg
datetime createdAt
datetime updatedAt
}
USER ||--o{ ORDER : "拥有"
SUBSCRIPTION_PLAN ||--o{ SUBSCRIPTION : "被订阅"
USER ||--o{ SUBSCRIPTION : "订阅"
USER ||--o{ BOOK : "创作"
BOOK ||--o{ BOOK_CHAPTER : "包含"
USER ||--o{ COMMENT : "发表"
BOOK_CHAPTER ||--o{ COMMENT : "被评论"
USER ||--o{ PLAYLIST : "创建"
PLAYLIST ||--o{ PLAYLIST_ITEM : "包含"
USER ||--o{ PLAY_RECORD : "播放"
BOOK_CHAPTER ||--o{ PLAY_RECORD : "被播放"
USER ||--o{ AUDIO_RECORD : "生成"
BOOK ||--o{ VIDEO_PROJECT : "驱动"
BOOK_CHAPTER ||--o{ VIDEO_PROJECT : "驱动"
USER ||--o{ DRAFT : "保存"
USER ||--o{ TOKEN_BALANCE : "持有"
USER ||--o{ TOKEN_USAGE : "产生"
ORDER ||--o{ TOKEN_USAGE : "关联"
USER ||--o{ USER_PREFERENCE : "偏好"

图表来源

  • schema.prisma

详细组件分析

用户模型(User)与相关实体

  • 职责与边界
    • 用户主体,承载会员等级、每日用量、偏好设置与播放记录
    • 与订单、订阅、令牌、播放记录、收藏、草稿、评论、歌单等形成强关联
  • 关系映射
    • 一对一:偏好设置、令牌余额
    • 一对多:订单、订阅、播放记录、收藏、草稿、评论、歌单、签到记录
  • 约束与索引
    • 手机号与OpenID唯一性;常用查询维度建立索引(如用户+创建时间)

章节来源

  • schema.prisma
  • auth.service.ts
  • member.service.ts

书籍模型(Book)与章节模型(BookChapter)

  • 职责与边界
    • 书籍:顶层容器,记录生成进度、状态、大纲与元数据
    • 章节:树形结构,承载内容、音频、视频、歌词与生成阶段
  • 关系映射
    • 书籍与章节:一对多,章节通过bookId关联;章节支持父子关系与层级
    • 章节与播放记录、评论、歌单项、视频项目形成多对多间接关联
  • 约束与索引
    • 章节唯一索引:同一层级下number唯一;多维索引覆盖书籍、父子关系与层级
  • 生成阶段(genStage)与状态(status)

    • 通过阶段管理器进行安全转移,支持前进与回退,自动清理下游资源
    • 书籍与章节分别定义阶段枚举,确保线性演进与一致性

      classDiagram
      class Book {
      +int id
      +int userId
      +string title
      +string status
      +string genStage
      +int progress
      +longtext outlineJson
      +text foreword
      +text afterword
      +datetime createdAt
      +datetime updatedAt
      }
      class BookChapter {
      +int id
      +int bookId
      +int parentId
      +int level
      +int number
      +string title
      +string status
      +string genStage
      +text content
      +text audioUrl
      +text videoUrl
      +text lrcLyrics
      +datetime createdAt
      +datetime updatedAt
      }
      Book "1" --> "0..*" BookChapter : "包含"
      

图表来源

  • schema.prisma
  • stage-manager.ts

章节来源

  • schema.prisma
  • stage-manager.ts
  • book-generator.types.ts

生成阶段与状态同步

  • 阶段定义
    • 书籍与章节分别定义阶段枚举,涵盖大纲、内容、音频、视频等阶段
  • 安全转移
    • 通过转移矩阵与乐观锁,确保并发安全;回退时自动清理下游资源
  • 历史数据迁移

    • 旧字段(status/contentStatus/audioStatus/videoStatus)迁移至genStage
    • 同步脚本基于阶段索引进行安全推进或回退

      flowchart TD
      Start(["开始同步"]) --> LoadChapters["加载章节/书籍"]
      LoadChapters --> InferTarget["根据旧字段推导目标阶段"]
      InferTarget --> Compare["比较当前阶段与目标阶段"]
      Compare --> |相同| Skip["无需更新"]
      Compare --> |目标更大| Advance["前进:safeTransition"]
      Compare --> |目标更小| Regenerate["回退:safeTransition并清理资源"]
      Advance --> Update["更新genStage并清理下游资源"]
      Regenerate --> Update
      Update --> Done(["完成"])
      Skip --> Done
      

图表来源

  • migrate-genstage.ts
  • sync-genstage.ts
  • stage-manager.ts

章节来源

  • migrate-genstage.ts
  • sync-genstage.ts
  • stage-manager.ts

令牌与消费模型(TokenBalance/TokenUsage/Order/Subscription)

  • 令牌余额与使用
    • 令牌余额按用户唯一,记录总量、已用与重置时间
    • 令牌使用记录按用户+时间维度索引,便于审计与配额控制
  • 订单与订阅
    • 套餐计划定义生成配额、音色与质量等权益
    • 订阅记录生命周期与自动续费策略
  • 业务联动
    • 生成服务在创建音频记录时更新令牌使用与余额
    • 会员服务在支付成功后更新用户会员等级与有效期

章节来源

  • schema.prisma
  • tts.service.ts
  • member.service.ts

Prisma 客户端初始化与连接

  • 初始化位置
    • 在应用启动时创建PrismaClient实例并建立连接
  • 连接管理
    • 提供连接状态检查与错误处理,确保数据库可用性

章节来源

  • index.ts

依赖分析

  • 模块耦合
    • 业务服务通过统一的Prisma客户端访问数据,降低耦合度
    • 阶段管理器独立于具体业务,仅依赖Prisma进行状态更新
  • 外部依赖
    • 数据库:MySQL(通过Prisma适配)
    • 第三方服务:TTS提供商、对象存储等(通过服务层抽象)
  • 循环依赖

    • 通过模块拆分与延迟导入避免循环依赖

      graph LR
      MODELS["models/index.ts"] --> AUTH["auth.service.ts"]
      MODELS --> TTS["tts.service.ts"]
      MODELS --> MEMBER["member.service.ts"]
      MODELS --> GEN["book-generator.service.ts"]
      GEN --> STAGE["stage-manager.ts"]
      PRISMA["schema.prisma"] --> MODELS
      

图表来源

  • index.ts
  • auth.service.ts
  • tts.service.ts
  • member.service.ts
  • book-generator.service.ts
  • stage-manager.ts
  • schema.prisma

章节来源

  • index.ts
  • book-generator.service.ts
  • stage-manager.ts

性能考虑

  • 索引策略
    • 为高频查询字段建立复合索引(如用户+状态、书籍+层级、创建时间等)
  • 查询优化
    • 使用select精确投影字段,避免不必要的字段加载
    • 对批量操作使用事务与批量写入减少往返
  • 并发控制
    • 阶段转移采用乐观锁,避免并发冲突导致的数据不一致
  • 缓存与队列
    • 对热点数据(如用户配额、令牌余额)结合内存缓存与队列处理

故障排查指南

  • 连接失败
    • 检查DATABASE_URL环境变量与数据库连通性
    • 查看Prisma客户端连接日志定位问题
  • 状态迁移异常
    • 核对阶段转移矩阵与目标阶段合法性
    • 检查乐观锁条件是否满足,必要时重试
  • 历史数据迁移
    • 使用迁移脚本将旧字段映射到genStage
    • 使用同步脚本进行幂等推进与回退校验
  • 令牌与配额
    • 核对用户会员等级与配额配置
    • 检查令牌使用记录与余额更新是否一致

章节来源

  • index.ts
  • migrate-genstage.ts
  • sync-genstage.ts
  • stage-manager.ts

结论

本项目通过Prisma Schema集中定义数据模型,结合模块化的业务服务与严格的阶段管理机制,实现了有声书生成平台的数据一致性与可扩展性。通过迁移与同步脚本,历史数据得以平滑过渡到新的线性阶段模型;通过统一的Prisma客户端封装,降低了模块间的耦合度。建议在后续迭代中持续完善索引策略、监控与告警体系,并保持阶段模型与业务流程的同步演进。

附录

使用示例与最佳实践

  • 初始化与连接
    • 在应用启动时调用连接函数,确保数据库可用
    • 示例路径:连接函数
  • 用户登录与信息获取
    • 登录/注册:查找或创建用户并生成JWT
    • 获取用户信息:按ID查询用户详情
    • 示例路径:登录与查询
  • 书籍与章节操作
    • 创建默认书籍:若不存在则创建“我的音频”默认书籍
    • 更新章节音频:保存音频URL、时长与歌词
    • 示例路径:默认书籍与章节更新
  • 生成阶段推进
    • 前进:推进到下一阶段(仅允许前进)
    • 回退:清理下游资源并回退到上游阶段
    • 示例路径:阶段推进与回退
  • 会员与订单
    • 创建订单:生成唯一订单号并写入订单记录
    • 支付成功:更新订单状态并提升用户会员等级
    • 示例路径:订单与会员
  • 测试用户创建
    • 脚本化创建测试用户并升级为超级VIP
    • 示例路径:测试用户脚本