# 后端-04:统一数据库 Schema(结构定义)-v1 - 版本:v7 - 更新日期:2026-05-13 - 目标读者:后端/架构/前端/数据库维护者 - 阅读时间:35–55 分钟 - 边界说明:本文件只定义持久化模型、表结构职责、关系、约束与索引策略;流程与状态跳转细节统一引用 `架构-04-状态机与约束清单.md`,接口输入输出统一引用 `后端-05-统一API契约-v1.md`。本文描述目标 Schema(结构定义),不代表当前代码或 migration 都已实现。 ## 1. 目标 这份 Schema(结构定义) 只做一件事:把 Muse 的双轨模型落成不会自相矛盾的数据结构。 本版直接固化以下设计决策: - `Block.content` 使用结构化 `jsonb`,不再退回纯文本。 - `Work` 直接持有导入/解析状态,不另建工作流状态总表。 - Shadow(待审层) 只存待审对象;历史进入 Archive(归档层)/Audit。 - 异步作业状态与审核状态分离:作业进 `*_jobs`,待审对象进 `suggestions` / `proposals`。 - 保留 `work_id` 冗余字段,但必须用复合唯一键与复合外键保证一致性,禁止只靠应用层“记得写对”。 - 所有业务主键和外键统一使用自定义字符串 ID,不再使用 UUID 或自增整数作为目标态业务 ID。 - 知识 Canonical(规范数据) 使用 `jsonb` 快照,但必须补属性级变更日志,不能把来源链路弄丢。 - `meta_schemas` 采用三维分类:`domain`(content/world/narrative)+ `scope`(work/chapter/entity/relation/event)+ `target_type`。 - Narrative State(叙事状态) 的运行态值不能只靠 `meta_schemas`;`work` / `chapter` / `entity` 三个 scope 必须有真实持久化载体。 - PG 是唯一事实源;RAGFlow 和 Graph Query Provider 都是 PG 的投影,通过 `projection_outbox` 异步同步。Neo4j 只是不满足 GraphRAG 能力时的条件交付 provider。 - Proposal 携带 source snapshot(source_kind/ref_id/revision/content_hash),用于 stale draft 检测。 - 管理员(Admin)配置能力进入 Admin BC,不混入普通用户作品工作台。 - Sa-Token 作为认证授权基座,负责登录认证、RBAC、接口鉴权、会话与 Token 生命周期、当前用户上下文和基础审计上下文。 - 全局知识库(Global Knowledge Base)与局域知识库(Local Knowledge Base)分层;全局知识库授权不自动写入作品事实。 - 元数据可见性至少表达 `ui_visible`、`ai_context`、`user_editable`、`user_searchable`、`exportable`。 - New-API 继续负责模型供应商、路由、用户分组限流、Token 成本策略和消耗日志;Muse 只同步用户、分组、配额、套餐和绑定状态。 ## 2. 总体原则 ### 2.1 持久化对象分类 系统内持久化对象按事实层级分类,不能把配置、事实、待审对象、任务和投影混成一张万能表。 | 类别 | 说明 | 代表表 | |---|---|---| | Canonical(规范数据) | 用户确认后的事实数据 | `works` / `chapters` / `blocks` / `knowledge_entities` / `knowledge_relations` / `knowledge_events` / `narrative_states` | | Shadow(待审层) Active(活跃层) | 仍待审核的建议/提案 | `suggestions` / `proposals` | | Job | 异步生成、解析、批处理状态 | `generation_jobs` / `extraction_jobs` | | Configuration(系统配置) | 管理员配置、版本、启停和授权策略 | `roles` / `permissions` / `user_roles` / `role_permissions` / `system_service_identities` / `meta_schemas` / `meta_fields` / `prompt_versions` / `agent_configs` / `global_knowledge_bases` / `global_knowledge_access_policies` / `newapi_user_bindings` / `newapi_plan_mappings` / `evaluation_datasets` | | History / Audit | 已完成审核、审计或评测记录 | `suggestion_archive` / `proposal_archive` / `audit_logs` / `knowledge_attribute_changes` / `evaluation_runs` | | Projection | 投影基础设施(PG → 外部存储的异步同步) | `projection_outbox` / `projection_watermarks` / `ragflow_id_mappings` | | Infrastructure(基础设施) | 非业务实体的系统支撑表 | `id_sequence_segments` | ### 2.2 通用列约定 - 主键和业务外键默认使用 `varchar(96)`,由应用层 ID 生成器生成,不使用数据库自增或 UUID 默认值。长度放宽到 96 是为了容纳表名大写对象码,例如 `GLOBAL_KNOWLEDGE_ACCESS_POLICIES`。 - 时间统一使用 `timestamptz`。 - 状态字段统一使用 `text + CHECK`,不使用 PostgreSQL 原生 enum,避免以后迁移把自己卡死。 - 计数字段统一为非负整数,写入端负责维护,读端允许按需回算校验。 - 所有跨表 ownership 约束优先使用复合唯一键 + 复合外键;只有表达不了的“写一次后不可改”规则才考虑触发器。 ### 2.3 自定义字符串 ID 规则 目标态业务 ID 统一格式: `` ID 不带额外分隔符,示例:`WORKS20260512000001A1B2C3153045`。如果表名本身包含下划线,下划线属于对象码本身,不作为 ID 片段分隔符。 组成说明: | 片段 | 规则 | |---|---| | `OBJECT_CODE` | 默认采用所属表名大写,例如 `USERS`、`WORKS`、`CHAPTERS`、`BLOCKS`、`KNOWLEDGE_ENTITIES`;确需例外时必须在 S0-ID spec 中登记 | | `YYYYMMDD` | 生成日期,固定使用 `Asia/Shanghai` | | `SEQ6` | 按 `OBJECT_CODE + YYYYMMDD` 独立递增的 6 位取号器,左侧补 0 | | `RAND6` | 6 位大写 Base36 随机片段;应用层使用 Java `SecureRandom` 生成,不要再称为 UUID | | `HHMMSS` | 生成时间,补充可读性和粗粒度排序信息 | 取号器由数据库号段表管理,服务每次按对象码和日期领取 1000 个号段,并立即把数据库起始值推进到下一个未分配号段;服务进程只在内存中消费已领取号段。服务重启后未消费号段直接作废,重新领取下一个未分配号段,避免重复取号。 取号器超过 999999 时必须失败并告警,不能静默扩位破坏 ID 格式。API 契约对外只暴露字符串 ID,不再暴露迁移前的数字 ID 或 UUID。 迁移范围包含 `users.id`,以及作品、章节、Block、任务、建议、提案、知识、配置、审计、投影等所有业务和配置对象。对象码采用“表名大写 + 文档登记 + 代码常量”双维护:本文件和 S0-ID spec 是对象码的设计证据,代码实现必须用 enum 或常量集中定义;不引入数据库元数据表动态管理对象码。 S0-ID 采用停机清库/重建,不做双写过渡。基于“当前无重要数据,可以全部清理”的已确认前提,迁移方式改为清库/重建/重置式迁移:删除现有 schema,重建 schema,重新执行 migration,重新生成最小 smoke 数据,并一次性改表、改代码、改前端类型后跑全量回归。 该口径默认允许用于本地、隔离测试库和当前远程开发库。执行清理前必须记录环境标识、数据库连接摘要、操作者和清理范围;不要求快照或备份。若进入有价值数据或生产数据环境,必须停止执行该口径,重新评审是否需要数据保留和映射迁移方案。 最小 smoke 数据只覆盖验证主链路所需对象:管理员用户、普通用户、角色、权限、示例作品、章节、Block、基础 Prompt/Agent/MetaSchema/New-API 绑定配置,以及一组可触发建议、提案、知识确认和用量反馈的测试样本。不在 S0-ID 阶段重建完整演示小说样本。 ### 2.4 冗余 `work_id` 的约束策略 既然决定保留冗余 `work_id`,那就别装作没成本。 必须满足: - `chapters` 提供唯一键 `(work_id, id)`。 - `blocks` 提供唯一键 `(work_id, id)`,并通过 `(work_id, chapter_id)` 复合外键绑定到 `chapters`。 - `knowledge_entities` 提供唯一键 `(work_id, id)`。 - `suggestions`、`proposals`、`knowledge_relations` 只要同时保存 `work_id` 和下游对象 ID,就必须走复合外键校验同属一个 `work`。 ### 2.5 新产品形态表结构处理矩阵 本节只定义目标处理方式,不表示所有对象都已落地为当前 migration。 | 分类 | 对象 | 处理原则 | |---|---|---| | 优先复用 | `meta_schemas`、`narrative_states`、`knowledge_entities`、`knowledge_relations`、`generation_jobs`、`extraction_jobs`、`audit_logs` | 作品规划台、叙事状态、知识确认和任务记录优先复用这些目标模型;不要为每个 UI 面板新增孤立表 | | 扩展字段 | 元数据可见性字段、知识库访问策略字段、任务来源和审计字段 | 在已有模型能承载时优先扩展字段;必须保留版本、来源、操作者和权限上下文 | | 倾向新增 | `roles`、`permissions`、`user_roles`、`role_permissions`、`system_service_identities`、`prompt_versions`、`agent_configs`、`newapi_user_bindings`、`newapi_plan_mappings`、`global_knowledge_bases`、`global_knowledge_access_policies`、`evaluation_datasets`、`evaluation_runs` | 这些属于认证授权、系统级配置、授权或评测能力,适合独立建模;具体聚合职责见 `后端-01` | | 明确不新增 | `local_knowledge_bases` 独立表 | 局域知识库由 `work_id + knowledge_entities / knowledge_relations / knowledge_events / narrative_states` 隐式表达,不单独建容器表 | | 明确不新增 | `usage_logs` 本地明细表或本地汇总表 | New-API 是成本账本权威;Muse 只在任务记录、审计和个人中心响应中保留 New-API 引用、同步状态和任务级 usage 摘要 | 作品规划台(Planning Desk)的数据结构优先复用 MetaSchema、narrative_states、knowledge_entities、knowledge_relations、Work、Chapter 和 Block。产品可写“情节节拍 / 场景推进”,但本版不新增小说场景(Scene)独立一级表。 ## 3. 表结构 ### 3.1 Auth / User #### `users` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 用户 ID | | email | text | NOT NULL, UNIQUE | 登录邮箱,应用层统一 lower-case | | display_name | text | NOT NULL | 显示名称 | | password_hash | text | NOT NULL | Argon2id 哈希 | | status | text | NOT NULL, default `'active'`, CHECK IN (`'active'`, `'pending_deletion'`) | 用户状态 | | deletion_requested_at | timestamptz | nullable | 进入删除缓冲期的时间 | | deleted_at | timestamptz | nullable | 物理删除前的最终标记时间 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 补充约束: - `status = 'pending_deletion'` 时,`deletion_requested_at` 必须非空。 - `status = 'active'` 时,`deleted_at` 必须为空。 #### `roles` > Sa-Token 使用的最小角色表。角色表达接口和后台能力,不表达某个作品的正文或知识确认权。 | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 角色 ID | | role_key | text | NOT NULL, UNIQUE | 角色标识,例如 `admin`、`user` | | role_name | text | NOT NULL | 角色名称 | | description | text | nullable | 说明 | | builtin | boolean | NOT NULL, default false | 是否内置角色 | | status | text | NOT NULL, default `'active'`, CHECK IN (`'active'`, `'disabled'`) | 状态 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 内置角色至少包含: - `admin`:管理员控制台(Admin Console)能力。 - `user`:普通用户(User Workspace / Personal Center)能力。 #### `permissions` > Sa-Token 使用的最小权限点表。权限点用于接口鉴权、菜单展示和审计解释,不替代业务用例内的作品级校验。 | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 权限 ID | | permission_key | text | NOT NULL, UNIQUE | 权限标识,例如 `admin:prompts:write`、`workspace:works:read` | | permission_name | text | NOT NULL | 权限名称 | | resource_type | text | NOT NULL | 资源类型,如 `admin_api`、`workspace_api`、`personal_api`、`system_job` | | action | text | NOT NULL | 动作,如 `read`、`write`、`execute` | | description | text | nullable | 说明 | | builtin | boolean | NOT NULL, default false | 是否内置权限 | | status | text | NOT NULL, default `'active'`, CHECK IN (`'active'`, `'disabled'`) | 状态 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | #### `user_roles` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | user_id | varchar(96) | NOT NULL, FK → `users.id` ON DELETE CASCADE | 用户 | | role_id | varchar(96) | NOT NULL, FK → `roles.id` ON DELETE CASCADE | 角色 | | assigned_by | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 分配人 | | assigned_at | timestamptz | NOT NULL, default `now()` | 分配时间 | 约束: - PK (`user_id`, `role_id`)。 #### `role_permissions` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | role_id | varchar(96) | NOT NULL, FK → `roles.id` ON DELETE CASCADE | 角色 | | permission_id | varchar(96) | NOT NULL, FK → `permissions.id` ON DELETE CASCADE | 权限 | | assigned_by | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 分配人 | | assigned_at | timestamptz | NOT NULL, default `now()` | 分配时间 | 约束: - PK (`role_id`, `permission_id`)。 #### `system_service_identities` > 系统任务(System Job)服务身份表。服务身份用于投影消费、索引重建、同步重试、评测执行和清理任务,不允许伪装成普通用户做作品事实确认。 | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 服务身份 ID | | service_key | text | NOT NULL, UNIQUE | 服务身份标识,例如 `projection-worker` | | service_name | text | NOT NULL | 展示名称 | | permission_scope | jsonb | NOT NULL, default `'{}'::jsonb` | 允许执行的系统任务范围 | | status | text | NOT NULL, default `'active'`, CHECK IN (`'active'`, `'disabled'`) | 状态 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - 服务身份只能进入明确的后台任务入口。 - 服务身份写入审计时必须标记 `actor_type='system_job'` 或等价语义。 - 服务身份不得调用确认正文、确认知识草稿、接受 AI 候选等普通用户决策接口。 #### `id_sequence_segments` > 自定义字符串 ID 的数据库号段表。它不是业务实体,只负责保证同一 `OBJECT_CODE + YYYYMMDD` 下不会重复分配取号器区间。 | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | object_code | text | NOT NULL | 对象码,如 `USERS`、`WORKS`、`CHAPTERS`、`BLOCKS` | | yyyymmdd | char(8) | NOT NULL | 生成日期 | | next_value | int | NOT NULL, CHECK `next_value BETWEEN 1 AND 1000000` | 下一个未分配取号器起始值 | | segment_size | int | NOT NULL, default `1000`, CHECK `segment_size > 0` | 每次领取号段大小 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - PK (`object_code`, `yyyymmdd`)。 - 服务领取号段时必须在同一事务内锁定当前行,并把 `next_value` 推进到 `next_value + 1000`。 - 已领取但未消费的内存号段在服务重启后直接作废,不允许回收复用。 ### 3.2 Content BC(内容上下文) #### `works` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 作品 ID | | user_id | varchar(96) | NOT NULL, FK → `users.id` ON DELETE RESTRICT | 所属用户 | | title | text | NOT NULL | 标题 | | genre | text | NOT NULL | 题材 | | summary | text | nullable | 简介 | | work_schema_id | varchar(96) | nullable, FK → `meta_schemas.id` ON DELETE SET NULL | 绑定的作品级 Schema(结构定义),要求 `scope='work'` | | status | text | NOT NULL, default `'writing'`, CHECK IN (`'writing'`, `'completed'`, `'archived'`) | 作品状态 | | word_count | int | NOT NULL, default `0`, CHECK `word_count >= 0` | 总字数 | | chapter_count | int | NOT NULL, default `0`, CHECK `chapter_count >= 0` | 章节数 | | imported_at | timestamptz | nullable | 导入完成时间;只能从 null 写一次 | | import_error | text | nullable | 导入失败原因 | | parse_status | text | NOT NULL, default `'not_parsed'`, CHECK IN (`'not_parsed'`, `'parsing'`, `'parsed'`, `'parse_failed'`) | 解析状态 | | parse_progress | int | nullable, CHECK `parse_progress BETWEEN 0 AND 100` | 解析进度百分比 | | parse_error | text | nullable | 解析失败原因 | | parsed_at | timestamptz | nullable | 解析成功完成时间 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 补充约束: - `parsed_at` 只能在 `parse_status = 'parsed'` 时非空。 - `parse_status = 'not_parsed'` 时,`parsed_at` 必须为空。 - `imported_at` 是 write-once 字段,应用层和触发器都要拒绝二次写入。 #### `chapters` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 章节 ID | | work_id | varchar(96) | NOT NULL, FK → `works.id` ON DELETE CASCADE | 所属作品 | | title | text | NOT NULL | 章节标题 | | order_index | int | NOT NULL | 作品内顺序 | | summary | text | nullable | 章节摘要 | | block_count | int | NOT NULL, default `0`, CHECK `block_count >= 0` | Block(文本块) 数 | | word_count | int | NOT NULL, default `0`, CHECK `word_count >= 0` | 章节字数 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - UNIQUE (`work_id`, `order_index`) - UNIQUE (`work_id`, `id`) #### `blocks` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | Block(文本块) ID | | work_id | varchar(96) | NOT NULL | 冗余所有权,用于复合约束与热路径过滤 | | chapter_id | varchar(96) | NOT NULL | 所属章节 | | order_index | int | NOT NULL | 章节内顺序 | | content | jsonb | NOT NULL | Tiptap(富文本编辑器)/结构化文档内容 | | revision | int | NOT NULL, default `1`, CHECK `revision > 0` | 乐观锁版本 | | word_count | int | NOT NULL, default `0`, CHECK `word_count >= 0` | 当前 Block(文本块) 字数 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - FK (`work_id`, `chapter_id`) → `chapters(work_id, id)` ON DELETE CASCADE - UNIQUE (`chapter_id`, `order_index`) - UNIQUE (`work_id`, `id`) 说明: - `content` 是唯一 Canonical(规范数据) 正文载体;不再额外存 `status='canonical'` 这种废话字段。 - `revision` 是写入锚点,任何正文写操作都必须基于它。 ### 3.3 AI BC(人工智能上下文):Job #### `generation_jobs` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 生成任务 ID | | work_id | varchar(96) | NOT NULL, FK → `works.id` ON DELETE CASCADE | 所属作品 | | requested_by | varchar(96) | NOT NULL, FK → `users.id` ON DELETE RESTRICT | 触发用户 | | target_block_id | varchar(96) | nullable | 目标 Block(文本块) | | suggestion_type | text | NOT NULL, CHECK IN (`'continuation'`, `'rewrite'`, `'expand'`, `'planning'`, `'check'`) | 建议类型;覆盖写作台与作品规划台 AI 辅助 | | context_block_ids | jsonb | NOT NULL, default `'[]'::jsonb` | 上下文 Block(文本块) ID 列表 | | request_source | text | NOT NULL, default `'writing_desk'`, CHECK IN (`'writing_desk'`, `'planning_desk'`, `'knowledge_check'`, `'import_parse'`, `'admin_evaluation'`) | 任务来源,用于区分写作、规划、检查、解析或评测触发 | | config_snapshot | jsonb | NOT NULL, default `'{}'::jsonb` | PromptVersion、AgentConfig、上下文策略、New-API 绑定和全局知识授权快照摘要 | | audit_context | jsonb | NOT NULL, default `'{}'::jsonb` | 请求 ID、入口、用户意图、来源解释等审计上下文;禁止写正文全文 | | status | text | NOT NULL, default `'queued'`, CHECK IN (`'queued'`, `'running'`, `'succeeded'`, `'failed'`, `'canceled'`) | 作业状态 | | pipeline_step | text | nullable, CHECK IN (`'generating'`, `'extracting'`, `'validating'`, `'risk_routing'`, `'regenerating'`) | Generation Pipeline 内部步骤追踪;只在 `status=running` 时有意义;外部 API(GenerationJobSummary)不暴露此字段(v4 修正:新增字段,支持 Pipeline 内部多步追踪) | | error_code | text | nullable | 失败代码 | | error_message | text | nullable | 失败信息 | | started_at | timestamptz | nullable | 开始时间 | | finished_at | timestamptz | nullable | 完成时间 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - FK (`work_id`, `target_block_id`) → `blocks(work_id, id)` ON DELETE SET NULL #### `extraction_jobs` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 提取任务 ID | | work_id | varchar(96) | NOT NULL, FK → `works.id` ON DELETE CASCADE | 所属作品 | | requested_by | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 发起用户;导入批处理可为空 | | trigger_type | text | NOT NULL, CHECK IN (`'accept_suggestion'`, `'import_parse'`, `'manual_extract'`, `'block_save'`, `'planning_confirm'`) | 触发来源 | | scope_type | text | NOT NULL, CHECK IN (`'block'`, `'work'`) | 提取范围 | | source_block_id | varchar(96) | nullable | 来源 Block(文本块) | | source_suggestion_archive_id | varchar(96) | nullable | 来源建议归档 ID | | request_source | text | NOT NULL, default `'writing_desk'`, CHECK IN (`'writing_desk'`, `'planning_desk'`, `'knowledge_check'`, `'import_parse'`, `'admin_evaluation'`) | 任务来源 | | config_snapshot | jsonb | NOT NULL, default `'{}'::jsonb` | 提取、校验、风险路由使用的配置快照摘要 | | audit_context | jsonb | NOT NULL, default `'{}'::jsonb` | 来源、请求和审计上下文;禁止写正文全文 | | status | text | NOT NULL, default `'queued'`, CHECK IN (`'queued'`, `'running'`, `'succeeded'`, `'failed'`, `'canceled'`) | 作业状态 | | error_code | text | nullable | 失败代码 | | error_message | text | nullable | 失败信息 | | started_at | timestamptz | nullable | 开始时间 | | finished_at | timestamptz | nullable | 完成时间 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - FK (`work_id`, `source_block_id`) → `blocks(work_id, id)` ON DELETE SET NULL - FK (`source_suggestion_archive_id`) → `suggestion_archive(id)` ON DELETE SET NULL ### 3.4 AI BC(人工智能上下文):Shadow(待审层) Active(活跃层) #### `suggestions` > Active(活跃层) 表只存待审对象。行存在,就意味着 `pending_review`;接受、拒绝、过期后必须迁出到 `suggestion_archive`。 | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | Suggestion(建议) ID | | work_id | varchar(96) | NOT NULL, FK → `works.id` ON DELETE CASCADE | 所属作品 | | generation_job_id | varchar(96) | NOT NULL, UNIQUE, FK → `generation_jobs.id` ON DELETE CASCADE | 来源生成任务 | | target_block_id | varchar(96) | nullable | 目标 Block(文本块) | | suggestion_type | text | NOT NULL, CHECK IN (`'continuation'`, `'rewrite'`, `'expand'`) | 建议类型 | | anchor_type | text | NOT NULL, CHECK IN (`'replace_block'`, `'insert_after_block'`, `'replace_range'`) | 锚点类型 | | anchor_payload | jsonb | NOT NULL | 锚点细节:位置、范围、上下文摘要 | | base_block_revision | int | NOT NULL, CHECK `base_block_revision > 0` | 生成时绑定的 Block(文本块) revision | | content | jsonb | NOT NULL | 建议内容,结构与 `blocks.content` 同型 | | source_context | jsonb | nullable | 生成上下文摘要 | | conflict_warning | jsonb | nullable | 预检测冲突说明 | | expires_at | timestamptz | NOT NULL | 过期时间 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - FK (`work_id`, `target_block_id`) → `blocks(work_id, id)` ON DELETE SET NULL - `expires_at > created_at` #### `proposals` > Active(活跃层) 表只存待审提案。终态进入 `proposal_archive`。 | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | Proposal(提案) ID | | work_id | varchar(96) | NOT NULL, FK → `works.id` ON DELETE CASCADE | 所属作品 | | extraction_job_id | varchar(96) | NOT NULL, FK → `extraction_jobs.id` ON DELETE CASCADE | 来源提取任务 | | parse_job_id | varchar(96) | nullable, FK → `extraction_jobs.id` ON DELETE CASCADE | 全书解析批次 ID;仅 `trigger_type='import_parse'` 时使用,通常等于该行的 `extraction_job_id` | | chapter_id | varchar(96) | nullable | 关联章节;全书解析场景下必填,表示当前 Proposal 属于哪个章节批次 | | suggestion_id | varchar(96) | nullable, FK → `suggestions.id` ON DELETE SET NULL | 关联的 Suggestion(建议);生成链路中 Proposal 通过此字段关联到 Suggestion,实现 Knowledge Draft 数据合同 | | entity_id | varchar(96) | nullable | 关联实体;创建新实体时为空 | | proposal_type | text | NOT NULL, CHECK IN (`'create_entity'`, `'update_attribute'`, `'add_relation'`) | 提案类型 | | stage | text | NOT NULL, default `'raw'`, CHECK IN (`'raw'`, `'validated'`) | 内部校验阶段 | | risk_level | text | nullable, CHECK IN (`'low'`, `'medium'`, `'high'`, `'critical'`) | 风险级别(v7 修正:新增 critical) | | dedupe_group | text | nullable | 去重分组 ID | | conflict_summary | jsonb | nullable | 冲突摘要 | | proposed_data | jsonb | NOT NULL | 提议写入的数据 | | current_data | jsonb | nullable | 当前 Canonical(规范数据) 快照 | | source_block_id | varchar(96) | nullable | 来源 Block(文本块) | | source_kind | text | nullable | 来源类型:block / suggestion / parse_job(v7 新增,Source Snapshot 合同) | | source_ref_id | varchar(96) | nullable | 来源引用 ID(v7 新增) | | source_block_revision | int | nullable | 来源 Block revision(v7 新增) | | source_content_hash | text | nullable | 来源内容 hash,用于 stale draft 检测(v7 新增) | | expires_at | timestamptz | NOT NULL | 过期时间 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - FK (`work_id`, `entity_id`) → `knowledge_entities(work_id, id)` ON DELETE SET NULL - FK (`work_id`, `chapter_id`) → `chapters(work_id, id)` ON DELETE SET NULL - FK (`work_id`, `source_block_id`) → `blocks(work_id, id)` ON DELETE SET NULL - `expires_at > created_at` - `parse_job_id` 与 `chapter_id` 只在全书解析场景使用:`parse_job_id IS NOT NULL` 时,`chapter_id` 必须非空 - `source_kind='parse_job'` 时,`parse_job_id`、`chapter_id`、`source_content_hash` 必须非空 - 缺少 `source_kind`、`source_ref_id`、`source_block_revision` 或 `source_content_hash` 的历史 Proposal 在新链路下全部视为 stale draft,必须重新提取;不得 best-effort 补 snapshot 后继续确认 - 同一章节批量确认边界由 `parse_job_id + chapter_id` 决定;Schema 允许同一边界下存在多条 Proposal,但确认提交必须由状态机按章节事务循环保证 all-or-nothing,不能实现成跨章节大事务 ### 3.5 AI BC(人工智能上下文):Archive(归档层) #### `suggestion_archive` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK | 沿用原 Suggestion(建议) ID | | work_id | varchar(96) | NOT NULL | 所属作品 | | generation_job_id | varchar(96) | NOT NULL | 来源任务 | | target_block_id | varchar(96) | nullable | 原目标 Block(文本块) | | suggestion_type | text | NOT NULL | 建议类型 | | anchor_type | text | NOT NULL | 锚点类型 | | anchor_payload | jsonb | NOT NULL | 锚点快照 | | base_block_revision | int | NOT NULL | 生成时 revision | | original_content | jsonb | NOT NULL | 原建议内容 | | final_content | jsonb | nullable | 用户修改 Block 后合并时写入正文的最终内容快照(仅用于归档/审计) | | disposition | text | NOT NULL, CHECK IN (`'accepted'`, `'rejected'`, `'expired'`) | 终态 | | disposition_reason | text | nullable | 拒绝说明/过期原因 | | archived_by | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 审核人;系统过期时为空 | | archived_at | timestamptz | NOT NULL | 归档时间 | | merged_block_id | varchar(96) | nullable | 接受后写入的 Block(文本块) | | merged_block_revision | int | nullable | 接受后 Block(文本块) 的 revision | | source_context | jsonb | nullable | 生成上下文 | | conflict_warning | jsonb | nullable | 冲突警告 | | created_at | timestamptz | NOT NULL | 原始创建时间 | #### `proposal_archive` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK | 沿用原 Proposal(提案) ID | | work_id | varchar(96) | NOT NULL | 所属作品 | | extraction_job_id | varchar(96) | NOT NULL | 来源任务 | | parse_job_id | varchar(96) | nullable | 全书解析批次 ID 快照 | | chapter_id | varchar(96) | nullable | 章节批次快照 | | entity_id | varchar(96) | nullable | 原实体 | | proposal_type | text | NOT NULL | 提案类型 | | stage | text | NOT NULL | 归档前阶段 | | risk_level | text | nullable | 风险级别 | | dedupe_group | text | nullable | 去重分组 | | conflict_summary | jsonb | nullable | 冲突摘要 | | proposed_data | jsonb | NOT NULL | 提议数据 | | current_data | jsonb | nullable | 原快照 | | source_block_id | varchar(96) | nullable | 来源 Block(文本块) | | source_kind | text | nullable | 来源类型快照 | | source_ref_id | varchar(96) | nullable | 来源引用 ID 快照 | | source_block_revision | int | nullable | 来源 Block revision 快照 | | source_content_hash | text | nullable | 来源内容 hash 快照;用于 stale 检测留痕 | | disposition | text | NOT NULL, CHECK IN (`'accepted'`, `'rejected'`, `'expired'`) | 终态 | | disposition_reason | text | nullable | 拒绝/过期原因 | | archived_by | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 审核人;系统过期时为空 | | archived_at | timestamptz | NOT NULL | 归档时间 | | applied_entity_id | varchar(96) | nullable | 接受后最终作用到的实体 | | applied_snapshot | jsonb | nullable | 接受后的实体快照 | | created_at | timestamptz | NOT NULL | 原始创建时间 | ### 3.6 Knowledge BC(知识上下文) #### `knowledge_entities` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 实体 ID | | work_id | varchar(96) | NOT NULL, FK → `works.id` ON DELETE CASCADE | 所属作品 | | name | text | NOT NULL | 实体名 | | entity_type | text | NOT NULL | 实体类型,如 `character` / `location` / `item`,由 MetaSchema(domain=world, scope=entity) 定义 | | entity_schema_id | varchar(96) | nullable, FK → `meta_schemas.id` ON DELETE SET NULL | 绑定的实体 Schema(结构定义),要求 `scope='entity'` | | attributes | jsonb | NOT NULL, default `'{}'::jsonb` | 当前 Canonical(规范数据) 属性快照 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - UNIQUE (`work_id`, `name`, `entity_type`) - UNIQUE (`work_id`, `id`) #### `knowledge_relations` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 关系 ID | | work_id | varchar(96) | NOT NULL, FK → `works.id` ON DELETE CASCADE | 所属作品 | | source_entity_id | varchar(96) | NOT NULL | 起点实体 | | target_entity_id | varchar(96) | NOT NULL | 终点实体 | | relation_type | text | NOT NULL | 关系类型,由 MetaSchema(domain=world, scope=relation) 定义 | | description | text | nullable | 关系描述 | | properties | jsonb | nullable | 关系属性(JSONB),字段结构由 MetaSchema 约束 | | since_chapter | int | nullable | 关系生效起始章节序号 | | until_chapter | int | nullable | 关系失效章节序号,NULL 表示仍然有效 | | source_block_id | varchar(96) | nullable | 来源 Block(文本块) | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - FK (`work_id`, `source_entity_id`) → `knowledge_entities(work_id, id)` ON DELETE CASCADE - FK (`work_id`, `target_entity_id`) → `knowledge_entities(work_id, id)` ON DELETE CASCADE - FK (`work_id`, `source_block_id`) → `blocks(work_id, id)` ON DELETE SET NULL - CHECK (`source_entity_id <> target_entity_id`) - UNIQUE (`work_id`, `source_entity_id`, `target_entity_id`, `relation_type`) #### `knowledge_events` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 事件 ID | | work_id | varchar(96) | NOT NULL, FK → `works.id` ON DELETE CASCADE | 所属作品 | | event_type | text | NOT NULL | 事件类型,如 突破、相遇、冲突、转折,由 MetaSchema(domain=world, scope=event) 定义 | | description | text | NOT NULL | 事件描述 | | chapter_order | int | NOT NULL | 事件发生的章节序号 | | source_block_id | varchar(96) | nullable | 来源 Block | | properties | jsonb | NOT NULL, default `'{}'::jsonb` | 事件属性(JSONB),包含 involves(参与实体列表)和 causes(因果效果列表),字段结构由 MetaSchema 约束 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | | deleted | boolean | NOT NULL, default `false` | 软删除标记 | #### `knowledge_attribute_changes` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 变更记录 ID | | work_id | varchar(96) | NOT NULL, FK → `works.id` ON DELETE CASCADE | 所属作品 | | entity_id | varchar(96) | NOT NULL | 目标实体 | | attribute_key | text | NOT NULL | 属性键 | | change_type | text | NOT NULL, CHECK IN (`'set'`, `'unset'`, `'merge'`) | 变更类型 | | old_value | jsonb | nullable | 旧值 | | new_value | jsonb | nullable | 新值 | | source_type | text | NOT NULL, CHECK IN (`'proposal_accept'`, `'manual_edit'`, `'import'`) | 来源类型 | | source_proposal_archive_id | varchar(96) | nullable | 来源归档提案 | | source_block_id | varchar(96) | nullable | 来源 Block(文本块) | | changed_by | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 操作者 | | created_at | timestamptz | NOT NULL, default `now()` | 变更时间 | 约束: - FK (`work_id`, `entity_id`) → `knowledge_entities(work_id, id)` ON DELETE CASCADE - FK (`work_id`, `source_block_id`) → `blocks(work_id, id)` ON DELETE SET NULL - FK (`source_proposal_archive_id`) → `proposal_archive(id)` ON DELETE SET NULL #### `narrative_states` > Narrative State(叙事状态) 的运行态值载体。`meta_schemas(domain=narrative)` 只定义字段形状,真正的运行态值必须落在这里,而不是挂在 Schema 定义本身。 | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 叙事状态记录 ID | | work_id | varchar(96) | NOT NULL, FK → `works.id` ON DELETE CASCADE | 所属作品 | | scope | text | NOT NULL, CHECK IN (`'work'`, `'chapter'`, `'entity'`) | 运行态作用域;只允许三个可写 scope | | chapter_id | varchar(96) | nullable | `scope='chapter'` 时必填 | | entity_id | varchar(96) | nullable | `scope='entity'` 时必填 | | schema_id | varchar(96) | nullable, FK → `meta_schemas.id` ON DELETE SET NULL | 对应的 narrative Schema(结构定义) | | state_payload | jsonb | NOT NULL, default `'{}'::jsonb` | 当前叙事状态值,如弧线进度、章节意图、角色目标/动机 | | source_type | text | NOT NULL, CHECK IN (`'manual_edit'`, `'proposal_accept'`, `'batch_confirm'`) | 最近一次写入来源 | | source_proposal_archive_id | varchar(96) | nullable, FK → `proposal_archive.id` ON DELETE SET NULL | 由提案确认写入时记录来源 | | invalidated_at | timestamptz | nullable | 失效时间;内容改写导致需要重提取时写入 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - FK (`work_id`, `chapter_id`) → `chapters(work_id, id)` ON DELETE CASCADE - FK (`work_id`, `entity_id`) → `knowledge_entities(work_id, id)` ON DELETE CASCADE - `scope='work'` 时,`chapter_id` 与 `entity_id` 必须为空 - `scope='chapter'` 时,`chapter_id` 必须非空,`entity_id` 必须为空 - `scope='entity'` 时,`entity_id` 必须非空,`chapter_id` 必须为空 唯一性: - work scope:UNIQUE (`work_id`, `scope`) WHERE `scope='work'` - chapter scope:UNIQUE (`work_id`, `scope`, `chapter_id`) WHERE `scope='chapter'` - entity scope:UNIQUE (`work_id`, `scope`, `entity_id`) WHERE `scope='entity'` ### 3.7 Admin BC(管理上下文) #### `meta_schemas` > `meta_schemas` 只定义字段、校验规则和继承关系。对于 `domain='narrative'`,它不是运行态存储;运行态值统一进入 `narrative_states`。 | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | Schema(结构定义) ID | | schema_key | text | NOT NULL, UNIQUE | 稳定标识,如 `xuanhuan_work` / `character_base` | | name | text | NOT NULL | 展示名称 | | description | text | nullable | 描述 | | scope | text | NOT NULL, CHECK IN (`'work'`, `'chapter'`, `'entity'`, `'relation'`, `'event'`) | Schema(结构定义) 作用域 | | target_type | text | NOT NULL | `work` 作用域时表示作品类型;`entity` 作用域时表示实体类型;`relation`/`event` 作用域时表示关系/事件类型 | | domain | text | NOT NULL, DEFAULT `'world'`, CHECK IN (`'content'`, `'world'`, `'narrative'`) | 领域分类:content(创作容器) / world(世界模型) / narrative(叙事模型)(v7 新增) | | parent_schema_id | varchar(96) | nullable, FK → `meta_schemas.id` ON DELETE SET NULL | 父 Schema(结构定义) | | is_builtin | bool | NOT NULL, default `false` | 是否内置 | | version | int | NOT NULL, default `1`, CHECK `version > 0` | 配置版本;变更时创建新版本或保留可追溯变更记录 | | status | text | NOT NULL, default `'active'`, CHECK IN (`'draft'`, `'active'`, `'disabled'`, `'archived'`) | 配置状态 | | ui_visible | bool | NOT NULL, default `true` | 该 Schema(结构定义)对应对象是否允许在普通用户 UI 展示 | | ai_context | bool | NOT NULL, default `false` | 该 Schema 对象是否默认允许进入 AI 上下文 | | user_editable | bool | NOT NULL, default `false` | 普通用户是否默认可编辑该 Schema 对象 | | user_searchable | bool | NOT NULL, default `true` | 普通用户是否默认可检索该 Schema 对象 | | exportable | bool | NOT NULL, default `true` | 是否默认允许随作品导出 | | created_by | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 创建者 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - UNIQUE (`scope`, `target_type`, `name`) - UNIQUE (`domain`, `scope`, `target_type`, `name`)(v7 修正:三维分类唯一约束) #### `meta_fields` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 字段 ID | | schema_id | varchar(96) | NOT NULL, FK → `meta_schemas.id` ON DELETE CASCADE | 所属 Schema(结构定义) | | field_key | text | NOT NULL | 字段键 | | field_label | text | NOT NULL | 字段显示名 | | field_type | text | NOT NULL, CHECK IN (`'text'`, `'number'`, `'enum'`, `'boolean'`, `'array'`, `'reference'`) | 字段类型 | | is_required | bool | NOT NULL, default `false` | 是否必填 | | default_value | jsonb | nullable | 默认值 | | enum_options | jsonb | nullable | 枚举选项 | | reference_target_type | text | nullable | 引用类型:仅 `reference` 时有效 | | validation_rules | jsonb | NOT NULL, default `'{}'::jsonb` | 范围、正则、数组长度等规则 | | order_index | int | NOT NULL | 字段顺序 | | ui_visible | bool | NOT NULL, default `true` | 字段是否在普通用户 UI 展示 | | ai_context | bool | NOT NULL, default `false` | 字段是否允许进入 AI 上下文 | | user_editable | bool | NOT NULL, default `false` | 普通用户是否可编辑该字段 | | user_searchable | bool | NOT NULL, default `true` | 普通用户是否可检索该字段 | | exportable | bool | NOT NULL, default `true` | 字段是否允许随作品导出 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - UNIQUE (`schema_id`, `field_key`) - UNIQUE (`schema_id`, `order_index`) - 字段级可见性优先于 Schema 默认值;`ui_visible=false` 不代表 `ai_context=false`。 - 可见性变更必须写入审计,并触发用户可见投影重建或失效标记。 #### `prompt_versions` > 指令模板(Prompt)版本表。Prompt 是系统级配置,普通用户不能通过作品工作台读取或修改原始 Prompt。 | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | Prompt 版本 ID | | prompt_key | text | NOT NULL | 稳定标识,如 `generation.default` / `planning.chapter` | | prompt_type | text | NOT NULL, CHECK IN (`'system'`, `'task'`, `'genre'`, `'style'`, `'planning'`, `'validation'`) | Prompt 类型 | | version | int | NOT NULL, CHECK `version > 0` | 版本号,同 `prompt_key` 下递增 | | status | text | NOT NULL, default `'draft'`, CHECK IN (`'draft'`, `'active'`, `'disabled'`, `'archived'`) | 生命周期状态 | | content | text | NOT NULL | Prompt 正文 | | variables_schema | jsonb | NOT NULL, default `'{}'::jsonb` | 变量结构与必填规则 | | rollout_policy | jsonb | NOT NULL, default `'{}'::jsonb` | 灰度、回滚、适用范围 | | change_summary | text | nullable | 变更摘要 | | activated_by | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 激活人 | | activated_at | timestamptz | nullable | 激活时间 | | created_by | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 创建人 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - UNIQUE (`prompt_key`, `version`) - 同一 `prompt_key` 同一时间最多一个 active 版本。 - 已激活版本不得原地静默修改;需要变更时创建新版本或显式回滚。 #### `agent_configs` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | Agent 配置 ID | | agent_key | text | NOT NULL | 稳定标识,如 `generation.default` / `extraction.block` | | agent_type | text | NOT NULL, CHECK IN (`'generation'`, `'extraction'`, `'validation'`, `'planning'`, `'retrieval'`) | Agent 类型 | | version | int | NOT NULL, CHECK `version > 0` | 版本号 | | status | text | NOT NULL, default `'draft'`, CHECK IN (`'draft'`, `'active'`, `'disabled'`, `'archived'`) | 生命周期状态 | | config_payload | jsonb | NOT NULL, default `'{}'::jsonb` | Muse 侧编排配置,不保存模型供应商路由权威数据 | | timeout_ms | int | NOT NULL, default `60000`, CHECK `timeout_ms > 0` | 超时配置 | | retry_policy | jsonb | NOT NULL, default `'{}'::jsonb` | 重试策略 | | fallback_policy | jsonb | NOT NULL, default `'{}'::jsonb` | 降级策略 | | activated_by | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 激活人 | | activated_at | timestamptz | nullable | 激活时间 | | created_by | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 创建人 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - UNIQUE (`agent_key`, `version`) - 同一 `agent_key` 同一时间最多一个 active 版本。 - `agent_configs` 不承载模型供应商、模型路由、用户分组限流、Token 成本策略和 New-API 消耗日志。 #### `global_knowledge_bases` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 全局知识库 ID | | kb_key | text | NOT NULL | 稳定标识 | | name | text | NOT NULL | 名称 | | description | text | nullable | 描述 | | version | int | NOT NULL, default `1`, CHECK `version > 0` | 内容版本 | | status | text | NOT NULL, default `'preparing'`, CHECK IN (`'preparing'`, `'active'`, `'disabled'`, `'archived'`) | 生命周期状态 | | source_type | text | NOT NULL, CHECK IN (`'upload'`, `'ragflow_dataset'`, `'manual'`, `'external'`) | 来源类型 | | source_ref | text | nullable | 外部来源引用,如 RAGFlow dataset ID | | index_status | text | NOT NULL, default `'not_indexed'`, CHECK IN (`'not_indexed'`, `'indexing'`, `'indexed'`, `'index_failed'`) | 索引状态 | | metadata | jsonb | NOT NULL, default `'{}'::jsonb` | 体裁、平台、标签等元信息 | | created_by | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 创建人 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - UNIQUE (`kb_key`, `version`) - 停用后不得进入新的检索或生成上下文。 - 全局知识库不会自动写入任何作品的局域知识库(Local Knowledge Base)。 - 全局知识库是独立逻辑资料集;即使多个全局知识库共用同一个物理数据库、向量索引或 RAGFlow dataset,也必须保留可过滤的 `global_kb_id` 或等价资料集标识。 #### `global_knowledge_access_policies` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 访问策略 ID | | global_kb_id | varchar(96) | NOT NULL, FK → `global_knowledge_bases.id` ON DELETE CASCADE | 全局知识库 | | version | int | NOT NULL, default `1`, CHECK `version > 0` | 策略版本 | | status | text | NOT NULL, default `'draft'`, CHECK IN (`'draft'`, `'active'`, `'disabled'`, `'archived'`) | 策略状态 | | subject_type | text | NOT NULL, CHECK IN (`'user'`, `'user_group'`, `'plan'`, `'all_users'`) | 授权对象类型 | | subject_id | text | nullable | 授权对象 ID;`all_users` 可为空 | | default_bound | bool | NOT NULL, default `false` | 是否默认绑定 | | ui_visible | bool | NOT NULL, default `false` | 普通用户是否可见 | | user_searchable | bool | NOT NULL, default `false` | 普通用户是否可主动检索 | | ai_context | bool | NOT NULL, default `false` | 是否允许进入 AI 生成上下文 | | user_bindable | bool | NOT NULL, default `false` | 用户是否可主动绑定 | | user_unbindable | bool | NOT NULL, default `false` | 用户是否可主动解绑 | | readonly | bool | NOT NULL, default `true` | 普通用户是否只读使用 | | active_from | timestamptz | nullable | 生效时间 | | active_until | timestamptz | nullable | 失效时间 | | created_by | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 创建人 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - 没有 active 策略时,全局知识库不得展示、检索或进入生成上下文。 - 策略变更不得改写任何作品的局域知识库事实。 - 全局知识库版本和访问策略版本可独立回滚。 - 授权撤销后的权限边界是请求时计算允许使用的 `global_kb_id` 列表;被撤销资料集不得进入检索请求和上下文组装。 - 如果授权对象共用同一个物理索引或数据库,检索条件必须包含 `global_kb_id IN allowedIds` 或等价过滤条件;异步索引失效、重建或清理只作为性能和数据清理手段,不能作为权限边界。 #### `newapi_user_bindings` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 绑定 ID | | user_id | varchar(96) | NOT NULL, UNIQUE, FK → `users.id` ON DELETE CASCADE | Muse 用户 | | newapi_user_id | text | NOT NULL | New-API 侧用户 ID | | newapi_group_key | text | nullable | New-API 分组 | | plan_key | text | nullable | Muse 套餐标识 | | quota_snapshot | jsonb | NOT NULL, default `'{}'::jsonb` | 最近一次同步得到的配额/套餐摘要 | | status | text | NOT NULL, default `'syncing'`, CHECK IN (`'syncing'`, `'active'`, `'error'`, `'disabled'`) | 同步状态 | | last_synced_at | timestamptz | nullable | 最后同步时间 | | last_sync_error | text | nullable | 最后同步失败原因 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - UNIQUE (`newapi_user_id`) - 同步必须幂等;失败保留原因和重试入口。 - 不保存 New-API 模型供应商、模型路由或消耗日志权威数据。 #### `newapi_plan_mappings` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 套餐映射 ID | | muse_plan_key | text | NOT NULL | Muse 套餐标识 | | newapi_group_key | text | NOT NULL | New-API 分组标识 | | version | int | NOT NULL, default `1`, CHECK `version > 0` | 映射版本 | | status | text | NOT NULL, default `'draft'`, CHECK IN (`'draft'`, `'active'`, `'disabled'`, `'archived'`) | 状态 | | quota_policy | jsonb | NOT NULL, default `'{}'::jsonb` | 配额策略摘要 | | package_payload | jsonb | NOT NULL, default `'{}'::jsonb` | 套餐同步所需参数 | | created_by | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 创建人 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - UNIQUE (`muse_plan_key`, `version`) - active 映射变更只影响后续 New-API 同步任务,不改写已完成任务记录。 #### `evaluation_datasets` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 评测集 ID | | dataset_key | text | NOT NULL | 稳定标识 | | version | int | NOT NULL, CHECK `version > 0` | 版本号 | | status | text | NOT NULL, default `'draft'`, CHECK IN (`'draft'`, `'active'`, `'locked'`, `'archived'`) | 生命周期状态 | | scenario | text | NOT NULL | 评测场景,如续写、改写、描写、作品规划、实体一致性、角色一致性、角色弧光、世界事实、大纲一致性、细纲一致性、叙事手法、伏笔与回收、张力曲线、节奏与信息释放、主题表达、文风匹配、全书解析、长程连载 | | scoring_rubric | jsonb | NOT NULL | 固定评分标准 | | dataset_payload | jsonb | NOT NULL | 固定输入、参考输出或样本集 | | locked_at | timestamptz | nullable | 首次正式使用后的锁定时间 | | created_by | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 创建人 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - UNIQUE (`dataset_key`, `version`) - `locked` 后不得原地修改样本和评分标准。 #### `evaluation_runs` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 评测运行 ID | | dataset_id | varchar(96) | NOT NULL, FK → `evaluation_datasets.id` ON DELETE RESTRICT | 使用的评测集 | | run_status | text | NOT NULL, default `'queued'`, CHECK IN (`'queued'`, `'running'`, `'succeeded'`, `'failed'`, `'canceled'`) | 运行状态 | | tested_config_snapshot | jsonb | NOT NULL, default `'{}'::jsonb` | 被测 Prompt、Agent、上下文策略快照 | | judge_model_set | jsonb | NOT NULL, default `'[]'::jsonb` | 多模型评审集合 | | result_summary | jsonb | nullable | 算法汇总评分、置信度和指标 | | risk_summary | jsonb | nullable | 风险结论 | | started_at | timestamptz | nullable | 开始时间 | | finished_at | timestamptz | nullable | 完成时间 | | created_by | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 发起人 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | updated_at | timestamptz | NOT NULL, default `now()` | 更新时间 | 约束: - 评测运行只影响系统改进判断,不替代普通用户对正文、规划和作品知识的确认。 ### 3.8 Audit & Projection(审计与投影) #### `audit_logs` | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 审计日志 ID | | work_id | varchar(96) | nullable, FK → `works.id` ON DELETE CASCADE | 所属作品;全局认证行为可为空 | | user_id | varchar(96) | nullable, FK → `users.id` ON DELETE SET NULL | 用户操作者;系统任务可为空 | | service_identity_id | varchar(96) | nullable, FK → `system_service_identities.id` ON DELETE SET NULL | 系统任务服务身份 | | actor_role | text | nullable, CHECK IN (`'admin'`, `'user'`, `'system_job'`) | 操作角色 | | action | text | NOT NULL | 动作名 | | target_type | text | NOT NULL | 目标类型 | | target_id | varchar(96) | nullable | 目标 ID | | source_surface | text | nullable, CHECK IN (`'admin_console'`, `'user_workspace'`, `'personal_center'`, `'system_job'`) | 来源入口 | | request_id | text | nullable | 请求追踪 ID | | metadata | jsonb | NOT NULL, default `'{}'::jsonb` | 结构化上下文;禁止写正文全文 | | created_at | timestamptz | NOT NULL, default `now()` | 发生时间 | #### `projection_outbox` > PG 事务内写业务数据 + outbox,保证原子性。投影消费者从 outbox 幂等消费,用 PG 稳定业务 ID 做幂等键。 > 只有 Canonical(规范数据) 正文与已确认知识会写入正式投影;`suggestions` / `proposals` 里的 Shadow draft 永不直接进入正式检索。 | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | id | varchar(96) | PK, 应用层生成 | 消息 ID | | work_id | varchar(96) | NOT NULL | 所属作品 | | event_type | text | NOT NULL | 事件类型,如 `entity_created`、`attribute_changed`、`relation_added`、`event_recorded` | | payload | jsonb | NOT NULL | 事件载荷 | | projection_target | text | NOT NULL | 投影目标:`ragflow` / `graph_provider`;若 Graph Query Provider 选型为 Neo4j,则由 `graph_provider` 消费者写入 Neo4j | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | | consumed_at | timestamptz | nullable | 消费时间,NULL 表示未消费 | #### `projection_watermarks` > 每个投影目标独立 watermark。Context Assembly 组装时读 watermark 判断投影是否追平,未追平时用 PG overlay 补齐。 | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | work_id | varchar(96) | PK (composite) | 所属作品 | | projection_target | text | PK (composite) | 投影目标:`ragflow` / `graph_provider` | | last_synced_revision | bigint | NOT NULL | 最后同步的 revision | | last_synced_at | timestamptz | NOT NULL | 最后同步时间 | ### 3.9 Integration(外部集成) #### `ragflow_id_mappings` > 维护 PG 业务 ID ↔ RAGFlow document ID 的映射。Graph Query Provider 若落到 Neo4j,不需要单独映射表——图节点直接使用 PG 稳定业务 ID。 | 字段 | 类型 | 约束 | 说明 | |---|---|---|---| | pg_id | varchar(96) | PK (composite) | PG 侧业务 ID(entity ID 或 block ID) | | pg_type | text | PK (composite) | PG 侧类型:`entity` / `block` | | ragflow_doc_id | text | NOT NULL | RAGFlow 侧文档 ID | | work_id | varchar(96) | NOT NULL | 所属作品 | | created_at | timestamptz | NOT NULL, default `now()` | 创建时间 | ## 4. 外键与删除策略 ### 4.1 Canonical(规范数据) - `users → works`:`RESTRICT`。用户删除必须走缓冲期和应用层编排,不能裸删。 - `works → chapters → blocks`:`CASCADE`。作品删除时正文整体删除。 - `works → knowledge_entities / knowledge_relations / knowledge_attribute_changes / narrative_states`:`CASCADE`。 ### 4.2 Shadow(待审层) Active(活跃层) - `works → generation_jobs / extraction_jobs / suggestions / proposals`:`CASCADE`。 - `blocks → suggestions.target_block_id`:`SET NULL`,保留待审对象直到过期或归档。 - `knowledge_entities → proposals.entity_id`:`SET NULL`,保留提案上下文。 ### 4.3 Archive(归档层) / Audit - Archive(归档层) 表不反向依赖 Active(活跃层) 表。 - Archive(归档层) 中保留原始业务 ID 与快照,允许下游对象被删除后仍保留审核证据。 - `audit_logs.user_id` 使用 `SET NULL`,避免因用户删除破坏审计链。 ## 5. 索引策略 ### 5.1 热路径 | 索引 | 类型 | 用途 | |---|---|---| | `works(user_id, updated_at DESC)` | B-tree | 用户作品列表 | | `chapters(work_id, order_index)` | B-tree, UNIQUE | 章节树 | | `blocks(work_id, chapter_id, order_index)` | B-tree | 章节 Block(文本块) 有序分页 | | `suggestions(work_id, target_block_id, created_at DESC)` | B-tree | Block(文本块) 待审建议 | | `proposals(work_id, created_at DESC)` | B-tree | 提案列表 | | `proposals(parse_job_id, chapter_id, created_at DESC)` | B-tree | 全书解析章节批量确认边界查询 | | `generation_jobs(work_id, status, created_at DESC)` | B-tree | 生成作业查询 | | `extraction_jobs(work_id, status, created_at DESC)` | B-tree | 提取作业查询 | | `knowledge_entities(work_id, entity_type, name)` | B-tree | 实体列表/筛选 | | `knowledge_relations(work_id, source_entity_id)` | B-tree | 关系展开 | | `narrative_states(work_id, scope)` | B-tree, partial UNIQUE | work scope Narrative State 读取 | | `narrative_states(work_id, scope, chapter_id)` | B-tree, partial UNIQUE | chapter scope Narrative State 读取 | | `narrative_states(work_id, scope, entity_id)` | B-tree, partial UNIQUE | entity scope Narrative State 读取 | | `prompt_versions(prompt_key, version)` | B-tree, UNIQUE | Prompt 版本追溯 | | `prompt_versions(prompt_key) WHERE status='active'` | B-tree, partial UNIQUE | 每个 Prompt 当前 active 版本 | | `agent_configs(agent_key, version)` | B-tree, UNIQUE | Agent 配置版本追溯 | | `agent_configs(agent_key) WHERE status='active'` | B-tree, partial UNIQUE | 每个 Agent 当前 active 版本 | | `global_knowledge_bases(kb_key, version)` | B-tree, UNIQUE | 全局知识库版本 | | `global_knowledge_access_policies(global_kb_id, subject_type, subject_id, status)` | B-tree | 授权判断 | | `newapi_user_bindings(user_id)` | B-tree, UNIQUE | 用户绑定读取 | | `newapi_plan_mappings(muse_plan_key, version)` | B-tree, UNIQUE | 套餐映射版本 | | `evaluation_datasets(dataset_key, version)` | B-tree, UNIQUE | 评测集版本 | | `evaluation_runs(dataset_id, created_at DESC)` | B-tree | 评测运行历史 | | `audit_logs(source_surface, created_at DESC)` | B-tree | 管理员/用户入口审计筛选 | ### 5.2 JSONB(二进制JSON) | 索引 | 类型 | 用途 | |---|---|---| | `knowledge_entities(attributes)` | GIN | 按属性路径查询 | | `suggestions(anchor_payload)` | GIN | 锚点范围查询 | | `meta_fields(validation_rules)` | GIN | 规则检索/调试 | (v4 修正:移除 `knowledge_entities(embedding)` HNSW/IVFFlat 向量索引,向量检索改为 RAGFlow) 说明: - 语义检索由 RAGFlow 提供,不再依赖 PostgreSQL 向量索引。 ## 6. 迁移建议 ### 6.1 必须一次定死的东西 - `blocks.content` 的结构化 JSON(结构化文本) 形态 - `works` 的导入/解析状态字段 - Shadow(待审层) Active(活跃层) 与 Archive(归档层) 分层 - `meta_schemas.scope + target_type` - 元数据可见性字段:`ui_visible`、`ai_context`、`user_editable`、`user_searchable`、`exportable` - `knowledge_attribute_changes` - `narrative_states` 作为 Narrative State 真实运行态载体 - `proposals.parse_job_id + chapter_id` 作为 Full Parse(全书解析) 章节批量确认边界 - 管理员配置对象的版本与启停语义:`prompt_versions`、`agent_configs`、`global_knowledge_bases`、`global_knowledge_access_policies`、`evaluation_datasets` ### 6.2 可以后补的东西 - 更细粒度的 `anchor_type` - Archive(归档层) 查询 API(接口) - 不建 `local_knowledge_bases` 显式表;局域知识库由 `work_id + knowledge_* / narrative_states` 表达 - 不建 `usage_logs` 显式表或本地 usage 汇总表;用户可见用量由 New-API 汇总和 Muse 任务级 usage 摘要生成 ### 6.3 与完整建表 SQL 的同步口径 `后端-04a-完整建表SQL.sql` 当前标注为 V1-V18 实际落地 SQL,不是本文件目标 Schema 的自动展开。只有当这些目标结构进入正式 migration 设计时,才同步改 `后端-04a`;不能为了让 SQL 看起来完整而把尚未确认的目标表伪装成已落地事实。 ## 7. 非目标 以下内容不在本版 Schema(结构定义) 中解决: - 多人协同编辑 - 版本回滚到任意历史快照 - 草稿层(用户私有 Draft(草稿层))与 Canonical(规范数据) 的双层正文模型 - 通用任务编排平台 - 把 New-API 的模型供应商、路由、成本策略和消耗日志复制到 Muse 作为新事实源 - 为作品规划台每个 UI 面板单独建表 ## 8. 关联阅读 - 模型与双轨规则:`架构-02-核心数据结构与双轨模型.md` - 接口契约:`后端-05-统一API契约-v1.md` - 生命周期与约束:`架构-04-状态机与约束清单.md` - 完整建表 SQL(当前实际落地状态):`后端-04a-完整建表SQL.sql`