16 KiB
AI 合同平台 V2 Phase 3 Schema 硬化设计评审
日期:2026-06-30
评审结论
本文件只做 Phase 3 数据库 schema 硬化的设计评审和拆分清单,不写 Alembic migration,不修改数据库结构,不创建新数据库。
当前判断:
- 阶段 0 已完成:
yuqei-contract-v2-smoke已登记为 V2 dev/smoke 权威环境。 - 阶段 1 已完成:Contract API 和 AI Platform API 已具备 runtime schema check。
- 阶段 2 已完成收口:Contract API 主仓储和路由边界已拆分,
contracts.py已退回兼容 facade。 - 阶段 3 尚未开始实际 schema 变更,必须先按本文拆分评审后再逐片实施。
Phase 3 不应做一次性大迁移。推荐采用 expand -> backfill -> dual-write -> read-switch -> cleanup 的节奏,先新增结构化表和兼容读写,再逐步迁移读路径,最后再决定是否删除旧字段。
当前未完成项
对照《AI 合同平台 V2 下一阶段开发优化方案》,Phase 3 仍未完成的功能如下。
合同平台:
- 合同正文版本化:新增
contract_versions,逐步把正文历史从contracts.body_content迁入版本表。 - 正式审批模型:新增
approval_instances、approval_steps、approval_actions,把当前 timeline 事件升级为可追溯审批实例。 - UI 展示字段迁出:逐步迁出
status_label、status_tone、next_action、next_actions,让数据库保存业务事实,展示文案由 domain/serializer 派生。 - 治理字段补齐:核心表补
created_by、updated_by、deleted_at,并统一租户字段、软删除和索引策略。 - 审查结果结构化:把
review_tasks.risk_items、citations、primary_sources里的 JSON 快照拆出风险项、引用、推荐条款、已应用修复动作。 - 资产版本关系固化:模板、标准条款、审查规则、法律全文、法规变更影响扫描建立明确的版本、发布快照和引用关系。
AI 平台:
- 租户字段补齐:知识库、AI Trace、质量评估相关表补
tenant_id。 - AI Trace 治理:增加脱敏状态、保留周期、归档策略和归档标记。
- 密钥治理:Provider/OCR/API key 改为加密存储或密钥服务引用,避免明文配置长期留在业务表。
- 高频表分区评估:
ai_run_audits、worker_run_executions、knowledge_ingestion_jobs进入按时间分区或归档表设计。 - pgvector 运维方案:固定 embedding 维度、索引策略、重建流程和运行时校验。
现状差距
当前 Contract API 模型中仍有 MVP 过渡字段:
contracts.body_content仍承载当前合同正文。contracts.status_label、status_tone、next_action、next_actions仍是 UI 展示字段。approval_timeline_items适合展示时间线,但不足以表达审批实例、步骤、动作和结果。review_tasks.risk_items、citations、primary_sources仍以 JSON 快照保存,不利于列表、搜索、统计和修复动作审计。template_lifecycle_events、legal_asset_lifecycle_events已有事件表,但还没有独立的发布快照表和清晰引用关系。
当前 AI Platform 模型中仍有 MVP 过渡字段:
knowledge_documents、knowledge_chunks、knowledge_import_batches、knowledge_ingestion_jobs还缺统一tenant_id。ai_run_audits还缺tenant_id、脱敏状态、保留策略、归档状态。ocr_provider_configs.api_key仍是可直接保存密钥的字段,后续应改为 encrypted value 或 secret reference。- 高频审计/worker/ingestion 表已有索引,但还没有分区或归档边界。
- pgvector 已可用,但维度、索引和 reindex 的长期运维契约还没有固化到 schema check 与运维脚本。
总体原则
- 不新建 V2 数据库。所有 Phase 3 迁移目标必须先确认归属
yuqei_contract或yuqei_ai。 - 不复用 V1 单体表结构。只吸收业务语义和资产数据。
- 不破坏现有 API path 和响应结构。外部响应兼容由 serializer/domain 层负责。
- 不先删旧字段。先新增表/字段、回填、双写、切读,稳定后再评审清理。
- 不继续扩大 SQLite 验收范围。关键 schema 迁移必须以 PostgreSQL smoke 为准,SQLite 只保留轻量单测兼容。
- 每个 migration slice 都必须有回滚策略、空库到 head 验证、已有 smoke 库升级验证和接口回归。
拆分顺序
Slice 3.1:合同正文版本表
目标:
- 新增
contract_versions。 - 让合同创建、编辑、模板起草、条款修复都能产生版本记录。
- 暂时保留
contracts.body_content作为兼容缓存。
建议表:
contract_versions
idtenant_idcontract_idversion_noversion_labelbody_contentbody_hashsource_typesource_idcreated_bycreated_atpublished_atchange_summarymetadata
关键约束:
contract_id + version_no唯一。tenant_id + contract_id + created_at索引。body_hash用于下载、审计和归档一致性检查。
兼容策略:
- 创建迁移后先从
contracts.body_content回填一版v1。 - 写路径进入双写:更新
contracts.body_content,同时插入contract_versions。 - 读路径先保持不变,后续再切换详情和版本比较读取版本表。
验收:
- 合同详情仍返回原响应。
- 合同版本列表可从版本表返回。
- 旧合同至少有一条初始版本。
Slice 3.2:正式审批模型
目标:
- 新增审批实例、步骤、动作表。
- 当前
approval_timeline_items保持为展示/兼容时间线。
建议表:
approval_instances
idtenant_idcontract_idstatusstarted_bystarted_atcompleted_atcurrent_step_idmetadata
approval_steps
idtenant_idapproval_instance_idstep_nostep_typeassignee_roleassignee_user_idstatusdue_atcompleted_atmetadata
approval_actions
idtenant_idapproval_instance_idapproval_step_idactionactor_user_idactor_namecommentcreated_atmetadata
兼容策略:
- 现有审批/驳回动作继续写 timeline,同时写 formal approval action。
- 工作台待办先可继续读当前逻辑,待 formal approval 稳定后切读。
验收:
- 每个审批动作都能追溯到实例、步骤、人员、时间和结果。
- 现有 timeline API 不变。
Slice 3.3:治理字段和软删除
目标:
- 给核心业务表补齐治理字段。
- 统一列表查询对
deleted_at is null的过滤。
优先表:
contractscontract_filesreview_taskscontract_search_documentsapproval_timeline_itemsapproval_instances / approval_steps / approval_actionstemplate_lifecycle_eventslegal_asset_lifecycle_eventslegal_change_impact_scans
建议字段:
created_byupdated_bydeleted_at
兼容策略:
- 第一阶段字段允许为空或使用系统默认值回填。
- repository 层先集中封装软删除过滤,避免各查询散落条件。
- 搜索索引同步需要跳过软删除记录。
验收:
- 删除合同/文件/资产时不物理删除事实记录。
- 普通列表、搜索、待办默认不显示软删除记录。
Slice 3.4:UI 展示字段派生
目标:
- 逐步让
status_label、status_tone、next_action、next_actions从业务状态派生,而不是作为事实字段长期维护。
策略:
- 先新增 domain mapper/serializer 的派生逻辑。
- 保留旧字段作为兼容缓存,暂不删除。
- 添加一致性检查:当数据库字段和派生值不一致时,以派生值作为响应输出,并记录 warning。
- 待接口和前端稳定后,再评审是否删除旧列。
验收:
- 合同列表、详情、搜索、工作台展示不依赖手工维护 UI 文案。
- 数据库字段表达业务事实,UI 文案集中在代码映射层。
Slice 3.5:审查结果结构化
目标:
- 从 review task JSON 快照中拆出可查询、可统计、可审计的结构化表。
建议表:
review_risk_items
idtenant_idreview_task_idcontract_idrisk_typerisk_leveltitlesummarysource_excerptpositionrecommended_clause_idcreated_at
review_citations
idtenant_idreview_task_idrisk_item_idsource_idarticle_idtitlereferencequotecreated_at
review_repair_actions
idtenant_idreview_task_idrisk_item_idclause_idactionbefore_text_hashafter_text_hashapplied_byapplied_atmetadata
兼容策略:
review_tasks.risk_items、citations继续保留为 AI 原始快照和兼容缓存。- worker 完成审查时双写 JSON 和结构化表。
- 条款推荐和一键修订优先读结构化表,缺失时 fallback 到 JSON。
验收:
- 风险列表可按合同、任务、风险等级、条款 ID 查询。
- 修复动作能追溯到风险项、推荐条款和应用人。
Slice 3.6:模板/法律资产发布快照关系
目标:
- 把生命周期事件和真正可引用的发布快照分开。
- 让审查推荐、模板起草、法规变更影响扫描都引用明确版本。
建议表:
template_published_snapshots
idtenant_idtemplate_idversionbody_contentrequired_variablesoptional_variablesclause_idsreview_rule_idspublished_event_idpublished_atcreated_by
legal_asset_published_snapshots
idtenant_idasset_typeasset_idversionsnapshot_payloadpublished_event_idpublished_atcreated_by
legal_fulltext_versions
idtenant_idsource_idarticle_idversioneffective_datestatuscontent_hashcontentmetadata
兼容策略:
- 当前生命周期事件继续保留审计意义。
- 推荐逻辑和影响扫描逐步改为读取已发布快照。
验收:
- 后台修改草稿不影响审查推荐。
- 发布后推荐和扫描读取最新已发布版本。
- 回滚后推荐和扫描跟随回滚后的发布快照。
Slice 3.7:AI 平台租户与 Trace 治理
目标:
- AI 平台核心表补
tenant_id。 - AI Trace 增加脱敏、保留、归档字段。
优先表:
knowledge_documentsknowledge_chunksknowledge_import_batchesknowledge_ingestion_jobsknowledge_reindex_executionsai_run_auditsai_quality_improvement_actionsworker_run_executions
建议字段:
tenant_idredaction_statusretention_untilarchived_atarchive_location
兼容策略:
- 历史数据回填
defaulttenant。 - AI Trace 列表先默认过滤未归档记录。
- 对 prompt、question、answer、retrieved sources 增加脱敏状态,但不在第一片迁移中直接清空历史内容。
验收:
- AI Trace、知识库、质量改进动作可按租户隔离查询。
- 归档记录不进入默认管理列表。
Slice 3.8:密钥引用与 pgvector 运维契约
目标:
- Provider/OCR/API key 不再以明文业务字段作为长期方案。
- 固定 pgvector 维度、索引、reindex 运行契约。
建议变更:
ocr_provider_configs.api_key过渡为api_key_secret_ref或api_key_ciphertext。- provider 配置同样预留
secret_ref。 - schema check 增加 vector 扩展、向量列维度、索引存在性检查。
- reindex execution 记录 embedding provider/model/dimension,且与实际 chunk 向量维度一致。
兼容策略:
- 不在第一阶段删除
api_key。 - 新配置优先读 secret ref,缺失时 fallback 旧字段并给出 schema/runtime warning。
验收:
- 新增/更新 OCR 配置不再要求明文长期存储。
- pgvector 维度不一致时 schema check 或 reindex 前置校验能发现。
Slice 3.9:高频表分区和归档评估
目标:
- 对高频表先完成评估和读写路径抽象,再决定是否执行分区迁移。
候选表:
ai_run_auditsworker_run_executionsknowledge_ingestion_jobscontract_audit_events
建议策略:
- 第一阶段不直接分区已有表。
- 先补归档字段、查询边界和保留策略。
- 当 smoke/准生产数据量继续增长后,再选择 PostgreSQL native range partition 或 archive table。
验收:
- 高频列表接口默认有时间窗、limit 和索引命中。
- 归档策略有 dry-run 和恢复方案。
依赖关系
推荐实施顺序:
contract_versions- formal approval tables
- governance fields and soft delete
- UI field derivation
- review result structured tables
- template/legal asset snapshots
- AI tenant and trace governance
- secret reference and pgvector checks
- partition/archive evaluation
原因:
contract_versions是最低耦合的核心事实表,能先改善合同生命周期闭环。- approval tables 和 governance fields 会影响工作台、待办、审计和搜索,应在风险项结构化前先定底座。
- UI 字段迁出需要已有稳定 domain mapper,不能和事实表新增混在一个迁移里。
- review 结构化依赖条款/规则推荐已有发布快照语义,否则引用版本不清晰。
- AI 平台租户和 Trace 治理涉及跨服务,需要独立验收。
每片迁移的固定验收清单
每个 slice 进入实现前必须补齐:
- Alembic migration 文件和 downgrade 策略。
- SQLAlchemy model 更新。
- repository/orchestration 双写或回填逻辑。
- runtime schema check 核心表/字段/扩展检查。
- OpenAPI response 兼容性确认。
- 空 PostgreSQL 从 base 到 head 验证。
- 权威 smoke 库从当前 head 升级验证。
- 关键接口回归测试。
- Docker smoke。
建议命令:
python -m compileall -q yuqei-contract-platform/services/contract-api/src/yuqei_contract_api
python -m pytest yuqei-contract-platform/services/contract-api/tests -q
python -m compileall -q yuqei-ai-platform/services/ai-platform-api/src/yuqei_ai_platform_api
python -m pytest yuqei-ai-platform/services/ai-platform-api/tests -q
PostgreSQL 验收必须在权威 smoke 环境或明确登记的测试库执行,不用 SQLite 作为 Phase 3 schema 验收结论。
回滚策略
Phase 3 回滚按 slice 设计:
- 新增表优先保留,不在业务回滚中直接 drop,避免丢失已经写入的新事实。
- 应用回滚时关闭新读路径和双写开关,恢复旧字段读写。
- 回填脚本必须幂等,可重复执行。
- 删除旧字段必须另起 cleanup slice,并在至少一轮 smoke/压测/安全扫描后再评审。
- 涉及密钥字段的迁移必须先验证新 secret ref 可用,再禁止旧明文字段写入。
风险与待确认问题
contract_versions的版本号规则需要统一:建议先用单合同递增整数,同时保留version_label给前端展示。- 审批模型是否支持会签、或签、加签、转交:第一版建议只建可扩展字段,不一次性实现复杂流程。
- 软删除是否适用于审计事件:审计事实原则上不软删,只做归档和权限过滤。
- AI Trace 脱敏策略需要确认哪些字段允许保存明文:prompt、question、answer、retrieved sources、provider error 应分级处理。
- 高频表分区不宜过早实施,需结合真实 p95、表大小、索引膨胀和备份恢复成本决策。
下一步建议
先评审并确认 Slice 3.1 contract_versions。确认后再进入实现:
- 写 Alembic migration。
- 更新 SQLAlchemy model。
- 增加回填和双写。
- 保持
contracts.body_content兼容。 - 跑本地测试和 PostgreSQL smoke。
在评审确认前,不执行 Phase 3 migration。