Files
ai-contract-platform/project-docs/V2-phase3-schema-hardening-design-review-2026-06-30.md
T
yuqei a3bb78e06b
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (pull_request) Failing after 16m35s
release: freeze V2 release candidate
2026-07-12 15:32:24 +08:00

16 KiB
Raw Blame History

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 仍未完成的功能如下。

合同平台:

  1. 合同正文版本化:新增 contract_versions,逐步把正文历史从 contracts.body_content 迁入版本表。
  2. 正式审批模型:新增 approval_instances、approval_steps、approval_actions,把当前 timeline 事件升级为可追溯审批实例。
  3. UI 展示字段迁出:逐步迁出 status_label、status_tone、next_action、next_actions,让数据库保存业务事实,展示文案由 domain/serializer 派生。
  4. 治理字段补齐:核心表补 created_by、updated_by、deleted_at,并统一租户字段、软删除和索引策略。
  5. 审查结果结构化:把 review_tasks.risk_items、citations、primary_sources 里的 JSON 快照拆出风险项、引用、推荐条款、已应用修复动作。
  6. 资产版本关系固化:模板、标准条款、审查规则、法律全文、法规变更影响扫描建立明确的版本、发布快照和引用关系。

AI 平台:

  1. 租户字段补齐:知识库、AI Trace、质量评估相关表补 tenant_id。
  2. AI Trace 治理:增加脱敏状态、保留周期、归档策略和归档标记。
  3. 密钥治理:Provider/OCR/API key 改为加密存储或密钥服务引用,避免明文配置长期留在业务表。
  4. 高频表分区评估:ai_run_audits、worker_run_executions、knowledge_ingestion_jobs 进入按时间分区或归档表设计。
  5. 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 与运维脚本。

总体原则

  1. 不新建 V2 数据库。所有 Phase 3 迁移目标必须先确认归属 yuqei_contract 或 yuqei_ai。
  2. 不复用 V1 单体表结构。只吸收业务语义和资产数据。
  3. 不破坏现有 API path 和响应结构。外部响应兼容由 serializer/domain 层负责。
  4. 不先删旧字段。先新增表/字段、回填、双写、切读,稳定后再评审清理。
  5. 不继续扩大 SQLite 验收范围。关键 schema 迁移必须以 PostgreSQL smoke 为准,SQLite 只保留轻量单测兼容。
  6. 每个 migration slice 都必须有回滚策略、空库到 head 验证、已有 smoke 库升级验证和接口回归。

拆分顺序

Slice 3.1:合同正文版本表

目标:

  • 新增 contract_versions。
  • 让合同创建、编辑、模板起草、条款修复都能产生版本记录。
  • 暂时保留 contracts.body_content 作为兼容缓存。

建议表:

contract_versions

  • id
  • tenant_id
  • contract_id
  • version_no
  • version_label
  • body_content
  • body_hash
  • source_type
  • source_id
  • created_by
  • created_at
  • published_at
  • change_summary
  • metadata

关键约束:

  • 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

  • id
  • tenant_id
  • contract_id
  • status
  • started_by
  • started_at
  • completed_at
  • current_step_id
  • metadata

approval_steps

  • id
  • tenant_id
  • approval_instance_id
  • step_no
  • step_type
  • assignee_role
  • assignee_user_id
  • status
  • due_at
  • completed_at
  • metadata

approval_actions

  • id
  • tenant_id
  • approval_instance_id
  • approval_step_id
  • action
  • actor_user_id
  • actor_name
  • comment
  • created_at
  • metadata

兼容策略:

  • 现有审批/驳回动作继续写 timeline,同时写 formal approval action。
  • 工作台待办先可继续读当前逻辑,待 formal approval 稳定后切读。

验收:

  • 每个审批动作都能追溯到实例、步骤、人员、时间和结果。
  • 现有 timeline API 不变。

Slice 3.3:治理字段和软删除

目标:

  • 给核心业务表补齐治理字段。
  • 统一列表查询对 deleted_at is null 的过滤。

优先表:

  • contracts
  • contract_files
  • review_tasks
  • contract_search_documents
  • approval_timeline_items
  • approval_instances / approval_steps / approval_actions
  • template_lifecycle_events
  • legal_asset_lifecycle_events
  • legal_change_impact_scans

建议字段:

  • created_by
  • updated_by
  • deleted_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

  • id
  • tenant_id
  • review_task_id
  • contract_id
  • risk_type
  • risk_level
  • title
  • summary
  • source_excerpt
  • position
  • recommended_clause_id
  • created_at

review_citations

  • id
  • tenant_id
  • review_task_id
  • risk_item_id
  • source_id
  • article_id
  • title
  • reference
  • quote
  • created_at

review_repair_actions

  • id
  • tenant_id
  • review_task_id
  • risk_item_id
  • clause_id
  • action
  • before_text_hash
  • after_text_hash
  • applied_by
  • applied_at
  • metadata

兼容策略:

  • review_tasks.risk_items、citations 继续保留为 AI 原始快照和兼容缓存。
  • worker 完成审查时双写 JSON 和结构化表。
  • 条款推荐和一键修订优先读结构化表,缺失时 fallback 到 JSON。

验收:

  • 风险列表可按合同、任务、风险等级、条款 ID 查询。
  • 修复动作能追溯到风险项、推荐条款和应用人。

Slice 3.6:模板/法律资产发布快照关系

目标:

  • 把生命周期事件和真正可引用的发布快照分开。
  • 让审查推荐、模板起草、法规变更影响扫描都引用明确版本。

建议表:

template_published_snapshots

  • id
  • tenant_id
  • template_id
  • version
  • body_content
  • required_variables
  • optional_variables
  • clause_ids
  • review_rule_ids
  • published_event_id
  • published_at
  • created_by

legal_asset_published_snapshots

  • id
  • tenant_id
  • asset_type
  • asset_id
  • version
  • snapshot_payload
  • published_event_id
  • published_at
  • created_by

legal_fulltext_versions

  • id
  • tenant_id
  • source_id
  • article_id
  • version
  • effective_date
  • status
  • content_hash
  • content
  • metadata

兼容策略:

  • 当前生命周期事件继续保留审计意义。
  • 推荐逻辑和影响扫描逐步改为读取已发布快照。

验收:

  • 后台修改草稿不影响审查推荐。
  • 发布后推荐和扫描读取最新已发布版本。
  • 回滚后推荐和扫描跟随回滚后的发布快照。

Slice 3.7:AI 平台租户与 Trace 治理

目标:

  • AI 平台核心表补 tenant_id。
  • AI Trace 增加脱敏、保留、归档字段。

优先表:

  • knowledge_documents
  • knowledge_chunks
  • knowledge_import_batches
  • knowledge_ingestion_jobs
  • knowledge_reindex_executions
  • ai_run_audits
  • ai_quality_improvement_actions
  • worker_run_executions

建议字段:

  • tenant_id
  • redaction_status
  • retention_until
  • archived_at
  • archive_location

兼容策略:

  • 历史数据回填 default tenant。
  • 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_audits
  • worker_run_executions
  • knowledge_ingestion_jobs
  • contract_audit_events

建议策略:

  • 第一阶段不直接分区已有表。
  • 先补归档字段、查询边界和保留策略。
  • 当 smoke/准生产数据量继续增长后,再选择 PostgreSQL native range partition 或 archive table。

验收:

  • 高频列表接口默认有时间窗、limit 和索引命中。
  • 归档策略有 dry-run 和恢复方案。

依赖关系

推荐实施顺序:

  1. contract_versions
  2. formal approval tables
  3. governance fields and soft delete
  4. UI field derivation
  5. review result structured tables
  6. template/legal asset snapshots
  7. AI tenant and trace governance
  8. secret reference and pgvector checks
  9. partition/archive evaluation

原因:

  • contract_versions 是最低耦合的核心事实表,能先改善合同生命周期闭环。
  • approval tables 和 governance fields 会影响工作台、待办、审计和搜索,应在风险项结构化前先定底座。
  • UI 字段迁出需要已有稳定 domain mapper,不能和事实表新增混在一个迁移里。
  • review 结构化依赖条款/规则推荐已有发布快照语义,否则引用版本不清晰。
  • AI 平台租户和 Trace 治理涉及跨服务,需要独立验收。

每片迁移的固定验收清单

每个 slice 进入实现前必须补齐:

  1. Alembic migration 文件和 downgrade 策略。
  2. SQLAlchemy model 更新。
  3. repository/orchestration 双写或回填逻辑。
  4. runtime schema check 核心表/字段/扩展检查。
  5. OpenAPI response 兼容性确认。
  6. 空 PostgreSQL 从 base 到 head 验证。
  7. 权威 smoke 库从当前 head 升级验证。
  8. 关键接口回归测试。
  9. 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 可用,再禁止旧明文字段写入。

风险与待确认问题

  1. contract_versions 的版本号规则需要统一:建议先用单合同递增整数,同时保留 version_label 给前端展示。
  2. 审批模型是否支持会签、或签、加签、转交:第一版建议只建可扩展字段,不一次性实现复杂流程。
  3. 软删除是否适用于审计事件:审计事实原则上不软删,只做归档和权限过滤。
  4. AI Trace 脱敏策略需要确认哪些字段允许保存明文:prompt、question、answer、retrieved sources、provider error 应分级处理。
  5. 高频表分区不宜过早实施,需结合真实 p95、表大小、索引膨胀和备份恢复成本决策。

下一步建议

先评审并确认 Slice 3.1 contract_versions。确认后再进入实现:

  1. 写 Alembic migration。
  2. 更新 SQLAlchemy model。
  3. 增加回填和双写。
  4. 保持 contracts.body_content 兼容。
  5. 跑本地测试和 PostgreSQL smoke。

在评审确认前,不执行 Phase 3 migration。