# 第1章监管信息材料包生成数据库设计 ## 文档信息 | 项目 | 内容 | | --- | --- | | 需求分析文档 | docs/1.需求分析/5.第1章监管信息材料包生成.md | | 功能设计文档 | docs/2.功能设计/5.第1章监管信息材料包生成.md | | 数据库类型 | SQLite / Django ORM | | 表名前缀 | ra_ | | 工作流编码 | regulatory_info_package | | 设计日期 | 2026-06-10 | | 设计版本 | V1.0 | --- ## 一、设计原则 | 原则 | 说明 | | --- | --- | | 独立工作流批次 | 第1章监管信息材料包生成使用独立批次表,不复用自动填表批次 | | 附件优先 | 输入说明书优先绑定 `FileAttachment`,兼容最近成功 `FileSummaryBatch` 与 `FileSummaryItem` | | 过程产物文件化 | 大 JSON、追溯清单、模板副本、生成文件和 zip 均保存为文件,数据库只保存路径、hash、摘要 | | 导出记录复用 | zip、单文件、追溯清单继续写入 `ExportedSummaryFile`,统一下载权限 | | 工作流通用表复用 | 节点状态和 SSE 事件复用 `WorkflowNodeRun`、`WorkflowEvent` | | 通知独立留痕 | 新增专项通知记录表,结构与自动填表通知记录保持一致 | | SQLite 兼容 | 使用 Django ORM 常规字段和 JSONField,避免数据库特定语法 | | 原始模板保护 | 数据库只记录批次工作目录产物,不记录对原始模板的写操作 | --- ## 二、ER 图 ```mermaid erDiagram AUTH_USER ||--o{ CONVERSATION : owns CONVERSATION ||--o{ MESSAGE : contains CONVERSATION ||--o{ RA_FILE_ATTACHMENT : has CONVERSATION ||--o{ RA_REGULATORY_INFO_PACKAGE_BATCH : has AUTH_USER ||--o{ RA_REGULATORY_INFO_PACKAGE_BATCH : runs MESSAGE ||--o{ RA_REGULATORY_INFO_PACKAGE_BATCH : triggers RA_FILE_ATTACHMENT ||--o{ RA_REGULATORY_INFO_PACKAGE_BATCH : provides_instruction RA_FILE_SUMMARY_BATCH ||--o{ RA_REGULATORY_INFO_PACKAGE_BATCH : optionally_feeds RA_REGULATORY_INFO_PACKAGE_BATCH ||--o{ RA_REGULATORY_INFO_PACKAGE_ARTIFACT : keeps RA_REGULATORY_INFO_PACKAGE_BATCH ||--o{ RA_REGULATORY_INFO_PACKAGE_NOTIFICATION_RECORD : sends RA_REGULATORY_INFO_PACKAGE_BATCH ||--o{ RA_EXPORTED_SUMMARY_FILE : exports RA_REGULATORY_INFO_PACKAGE_BATCH ||--o{ RA_WORKFLOW_NODE_RUN : tracks RA_REGULATORY_INFO_PACKAGE_BATCH ||--o{ RA_WORKFLOW_EVENT : emits ``` 说明:`ra_workflow_node_run`、`ra_workflow_event`、`ra_exported_summary_file` 通过 `workflow_type` 与 `workflow_batch_id` 支持多工作流。本功能统一使用 `workflow_type=regulatory_info_package`。 现状补充:当前通用节点表已有 `batch + node_code` 唯一约束主要服务文件汇总批次。RIP 批次不应强依赖 `FileSummaryBatch.batch`,因此实现时必须为 `workflow_type + workflow_batch_id + node_code` 增加数据库唯一约束,或在创建节点时使用同等幂等逻辑,避免同一 RIP 批次重复初始化节点。 --- ## 三、表结构设计 ### 3.1 ra_regulatory_info_package_batch 一次第1章监管信息材料包生成工作流批次。记录触发来源、输入说明书、产品名称、生成状态、待确认摘要、zip 名称、配置版本和工作目录。 | 字段名 | Django 类型 | SQLite 类型 | 必填 | 说明 | | --- | --- | --- | --- | --- | | id | BigAutoField | integer | 是 | 主键 | | conversation_id | ForeignKey | bigint | 是 | 所属对话 | | user_id | ForeignKey | bigint | 是 | 发起用户 | | trigger_message_id | ForeignKey | bigint | 否 | 触发本工作流的用户消息 | | source_attachment_id | ForeignKey | bigint | 否 | 直接选中的说明书附件 | | source_summary_batch_id | ForeignKey | bigint | 否 | 可选,最近成功文件汇总批次 | | source_summary_item_id | PositiveBigIntegerField | integer | 否 | 可选,文件汇总条目 ID | | batch_no | CharField(64) | varchar(64) | 是 | 批次编号,格式 `RIP-YYYYMMDDHHMMSS-abcdef`,唯一 | | status | CharField(30) | varchar(30) | 是 | pending、running、waiting_user、success、partial_success、failed、cancelled | | source_file_name | CharField(255) | varchar(255) | 否 | 说明书原文件名 | | source_storage_path | CharField(500) | varchar(500) | 否 | 说明书存储路径 | | product_name | CharField(200) | varchar(200) | 否 | 抽取到的产品名称 | | output_zip_name | CharField(255) | varchar(255) | 否 | 主输出 zip 文件名,默认 `第1章 监管信息(预生成版).zip` | | generated_files | JSONField | text/json | 是 | 7 个文件生成状态摘要 | | missing_fields | JSONField | text/json | 是 | 缺失并填 `/` 的字段 | | llm_only_fields | JSONField | text/json | 是 | 仅 LLM 命中的字段 | | conflict_fields | JSONField | text/json | 是 | 规则和 LLM 冲突字段 | | risk_notes | JSONField | text/json | 是 | `.doc` 适配器、知识库不可用、zip 失败等提示 | | template_config_version | CharField(80) | varchar(80) | 否 | 模板配置版本 | | template_config_hash | CharField(128) | varchar(128) | 否 | 模板配置 hash | | adapter_summary | JSONField | text/json | 是 | docx/doc 适配器使用情况 | | work_dir | CharField(500) | varchar(500) | 否 | 批次工作目录 | | error_message | TextField | text | 否 | 批次异常说明 | | created_at | DateTimeField | datetime | 是 | 创建时间 | | started_at | DateTimeField | datetime | 否 | 开始时间 | | finished_at | DateTimeField | datetime | 否 | 完成时间 | | archived_at | DateTimeField | datetime | 否 | 归档时间 | | is_deleted | BooleanField | bool | 是 | 软删除标记 | 唯一约束: | 约束名 | 字段 | | --- | --- | | uq_ra_rip_batch_no | batch_no | 索引: | 索引名 | 字段 | 说明 | | --- | --- | --- | | idx_ra_rip_batch_conv_status | conversation_id, status | 查询对话下材料包批次状态 | | idx_ra_rip_batch_user_created | user_id, created_at | 查询用户发起历史 | | idx_ra_rip_batch_attachment | source_attachment_id | 查询某说明书附件生成历史 | | idx_ra_rip_batch_summary | source_summary_batch_id | 查询文件汇总关联的材料包批次 | | idx_ra_rip_batch_created | created_at | 后台按时间排查 | --- ### 3.2 ra_regulatory_info_package_artifact 第1章监管信息材料包生成过程产物表。仅保存文件元数据,不保存大文本正文。 | 字段名 | Django 类型 | SQLite 类型 | 必填 | 说明 | | --- | --- | --- | --- | --- | | id | BigAutoField | integer | 是 | 主键 | | batch_id | ForeignKey | bigint | 是 | 所属材料包批次 | | artifact_type | CharField(60) | varchar(60) | 是 | template_copy、instruction_extract、field_extract_result、merged_fields、generated_document、traceability、zip_package、notification_record | | file_format | CharField(20) | varchar(20) | 是 | json、excel、docx、doc、zip、markdown | | name | CharField(160) | varchar(160) | 是 | 产物名称 | | file_name | CharField(255) | varchar(255) | 是 | 文件名 | | storage_path | CharField(500) | varchar(500) | 是 | 文件存储路径 | | file_size | BigIntegerField | bigint | 是 | 文件大小 | | content_hash | CharField(128) | varchar(128) | 否 | 文件 SHA-256 hash | | metadata | JSONField | text/json | 是 | 模板编码、生成状态、高亮数量、适配器、错误摘要等 | | created_by_node | CharField(60) | varchar(60) | 否 | 生成该产物的工作流节点 | | created_at | DateTimeField | datetime | 是 | 创建时间 | | is_deleted | BooleanField | bool | 是 | 软删除标记 | 索引: | 索引名 | 字段 | 说明 | | --- | --- | --- | | idx_ra_rip_artifact_batch_type | batch_id, artifact_type | 查询批次过程产物 | | idx_ra_rip_artifact_format | file_format | 按文件格式查询 | | idx_ra_rip_artifact_created | created_at | 按时间追溯 | --- ### 3.3 ra_regulatory_info_package_notification_record 第1章监管信息材料包生成通知记录表。通知失败不阻断下载,但需要留痕和支持后续重试。 | 字段名 | Django 类型 | SQLite 类型 | 必填 | 说明 | | --- | --- | --- | --- | --- | | id | BigAutoField | integer | 是 | 主键 | | batch_id | ForeignKey | bigint | 是 | 所属材料包批次 | | recipient_id | ForeignKey(User) | bigint | 是 | 通知对象,默认发起人 | | channel | CharField(30) | varchar(30) | 是 | feishu_cli、feishu_api、mock | | export_ids | JSONField | text/json | 是 | 本次通知关联导出文件 ID | | message_summary | TextField | text | 是 | 通知摘要 | | send_status | CharField(20) | varchar(20) | 是 | pending、success、failed | | retry_count | PositiveIntegerField | integer | 是 | 已重试次数 | | external_message_id | CharField(120) | varchar(120) | 否 | 飞书外部消息 ID | | error_message | TextField | text | 否 | 失败原因 | | sent_at | DateTimeField | datetime | 否 | 发送成功时间 | | created_at | DateTimeField | datetime | 是 | 创建时间 | | updated_at | DateTimeField | datetime | 是 | 更新时间 | | is_deleted | BooleanField | bool | 是 | 软删除标记 | 索引: | 索引名 | 字段 | 说明 | | --- | --- | --- | | idx_ra_rip_notify_batch | batch_id, created_at | 查询批次通知 | | idx_ra_rip_notify_recipient | recipient_id, send_status | 查询用户通知状态 | | idx_ra_rip_notify_status | send_status, retry_count | 查询待重试通知 | --- ## 四、既有表扩展 ### 4.1 ra_exported_summary_file 继续复用导出文件表,新增 zip 导出类型,并支持 `regulatory_info_package` 权限反查。 | 字段/枚举 | 处理 | | --- | --- | | export_type | 增加 `zip` | | workflow_type | 使用 `regulatory_info_package` | | workflow_batch_id | 记录 `RegulatoryInfoPackageBatch.id` | | export_category | 使用 `regulatory_info_package`、`generated_document`、`traceability` | 导出类型枚举: | value | 中文展示 | 说明 | | --- | --- | --- | | markdown | Markdown | 既有报告 | | excel | Excel | 追溯清单 | | json | JSON | 抽取结果、合并字段 | | word | Word | 生成的 Word 文件,包含 `.docx` 和可下载 `.doc` | | pdf | PDF | 既有预留 | | zip | ZIP | 第1章监管信息材料包主下载 | 下载 MIME 规则: | 条件 | content_type | | --- | --- | | export_type=zip | application/zip | | export_type=word 且文件名后缀 `.doc` | application/msword | | export_type=word 且文件名后缀 `.docx` | application/vnd.openxmlformats-officedocument.wordprocessingml.document | ### 4.2 ra_workflow_node_run 本功能使用通用工作流节点表: | 字段 | 值 | | --- | --- | | workflow_type | regulatory_info_package | | workflow_batch_id | RegulatoryInfoPackageBatch.id | | node_group | regulatory_info_package | | batch_id | 可为空;如为兼容旧查询,不建议绑定文件汇总批次 | 幂等约束建议: | 约束/策略 | 字段 | 说明 | | --- | --- | --- | | uq_ra_node_workflow_batch_code | workflow_type, workflow_batch_id, node_code | 推荐新增数据库唯一约束,防止同一 RIP 批次重复节点 | | get_or_create 幂等 | workflow_type, workflow_batch_id, node_code | 若暂不改通用表约束,节点初始化必须使用该组合做代码层幂等 | 建议新增节点: ```text prepare, template_copy, text_extract, field_extract, field_merge, generate_docs, highlight_review_items, trace_export, zip_export, notify, completed ``` ### 4.3 ra_workflow_event 本功能事件写入: | 字段 | 值 | | --- | --- | | workflow_type | regulatory_info_package | | workflow_batch_id | RegulatoryInfoPackageBatch.id | | conversation_id | 当前对话 ID | | payload | 节点状态、文件生成状态、导出 ID、待确认摘要等 | --- ## 五、枚举设计 ### 5.1 RegulatoryInfoPackageBatch.status | value | 中文展示 | 说明 | | --- | --- | --- | | pending | 待执行 | 批次已创建,等待执行 | | running | 执行中 | 工作流正在执行 | | waiting_user | 等待用户 | 未找到唯一说明书,需要用户选择 | | success | 成功 | 7 个文件、zip 和必要追溯产物生成成功 | | partial_success | 部分成功 | zip 或主要文件已生成,但部分单文件、`.doc` 原生处理、`.docx` 兜底、追溯或通知存在失败 | | failed | 失败 | 关键输入、模板或全部目标文件生成失败 | | cancelled | 已取消 | 用户或系统取消执行 | ### 5.2 RegulatoryInfoPackageArtifact.artifact_type | value | 说明 | | --- | --- | | template_copy | 模板副本 | | instruction_extract | 说明书文本、章节、表格抽取结果 | | field_extract_result | 规则与 LLM 抽取原始结果 | | merged_fields | 合并字段、高亮决策、标准候选 | | generated_document | 生成后的单个目标文件 | | traceability | 追溯清单 | | zip_package | 主下载 zip 包 | | notification_record | 通知记录产物 | ### 5.3 RegulatoryInfoPackageArtifact.file_format | value | 说明 | | --- | --- | | json | JSON 产物 | | excel | Excel 追溯清单 | | docx | Word OpenXML 文件 | | doc | Word 97-2003 文件 | | zip | 压缩包 | | markdown | Markdown 摘要或报告 | ### 5.4 通知枚举 | 字段 | value | | --- | --- | | channel | feishu_cli、feishu_api、mock | | send_status | pending、success、failed | --- ## 六、JSON 字段结构 ### 6.1 generated_files ```json [ { "template_code": "ch1_4_application_form", "file_name": "CH1.4 申请表.docx", "status": "success", "artifact_id": 12, "export_id": 34, "highlight_count": 8, "missing_count": 5, "llm_only_count": 2, "error_message": "" } ] ``` ### 6.2 missing_fields ```json [ { "target_file": "CH1.4 申请表.docx", "field_key": "applicant_name", "field_label": "申请人名称", "final_value": "/", "highlight_reason": "missing", "needs_review": true } ] ``` ### 6.3 llm_only_fields ```json [ { "target_file": "CH1.4 申请表.docx", "field_key": "detection_targets", "field_label": "检测靶标", "final_value": "ORF1ab、N基因", "evidence": "预期用途和检测原理章节", "highlight_reason": "llm_only", "needs_review": true } ] ``` ### 6.4 conflict_fields ```json [ { "field_key": "package_specification", "field_label": "包装规格", "rule_value": "规格A:24人份/盒、48人份/盒、96人份/盒", "llm_value": "规格A、规格B均为24/48/96人份", "selected_value": "规格A:24人份/盒、48人份/盒、96人份/盒", "handling": "规则优先,写入值高亮并进入追溯清单" } ] ``` ### 6.5 risk_notes ```json [ { "type": "legacy_doc_adapter_unavailable", "message": "CH1.9 为 .doc 文件,当前环境未检测到可写入适配器。", "template_code": "ch1_9_pre_submission" }, { "type": "knowledge_base_unavailable", "message": "标准清单知识库查询不可用,未自动写入候选标准。" } ] ``` ### 6.6 adapter_summary ```json { "docx": { "adapter": "DocxDocumentAdapter", "status": "available" }, "doc": { "adapter": "WordComDocAdapter", "status": "available", "fallback_used": false } } ``` ### 6.7 artifact.metadata ```json { "template_code": "ch1_5_product_list", "strategy": "product_list", "source_template": "CH1.5 产品列表.docx", "generated_status": "success", "highlight_count": 12, "missing_count": 6, "llm_only_count": 1, "adapter": "DocxDocumentAdapter", "created_by_node": "generate_docs" } ``` --- ## 七、存储路径设计 批次目录: ```text media/regulatory_info_package/{user_id}/{conversation_id}/{batch_no}/ ``` 目录结构: ```text media/regulatory_info_package/12/1001/RIP-20260610153000-abcdef/ templates/ ch1_2_directory.source.docx ch1_9_pre_submission.source.doc extracted/ instruction_extract.json field_extract_result.json merged_fields.json generated/ CH1.2 监管信息目录.docx CH1.4 申请表.docx CH1.5 产品列表.docx CH1.9 产品申报前沟通的说明.doc CH1.11.1 符合标准的清单.docx CH1.11.5 真实性声明.docx CH1.11.6 符合性声明.docx exports/ traceability.xlsx 第1章 监管信息(预生成版).zip logs/ instruction_extract.json field_extract_result.json merged_fields.json traceability.json doc_adapter_result.json ``` 路径安全要求: | 要求 | 说明 | | --- | --- | | 输出目录校验 | 所有输出路径必须位于当前批次 `work_dir` 下 | | 原始模板只读 | 不允许覆盖 `docs/0.原始材料` | | 导出路径 | `ExportedSummaryFile.storage_path` 保存实际文件路径,下载时校验权限 | --- ## 八、权限关系 ### 8.1 批次权限 ```text RegulatoryInfoPackageBatch.conversation.user_id == request.user.id ``` ### 8.2 输入附件权限 ```text FileAttachment.conversation_id == batch.conversation_id FileAttachment.user_id == batch.user_id FileAttachment.upload_status != deleted ``` ### 8.3 导出下载权限 `ExportedSummaryFile` 下载时按 `workflow_type` 分支: ```text workflow_type == "regulatory_info_package" -> workflow_batch_id 反查 RegulatoryInfoPackageBatch -> conversation__user == request.user -> is_deleted == false ``` --- ## 九、迁移设计 建议新增一个迁移文件,包含: | 变更 | 说明 | | --- | --- | | 新增 `RegulatoryInfoPackageBatch` | 批次表 | | 新增 `RegulatoryInfoPackageArtifact` | 产物表 | | 新增 `RegulatoryInfoPackageNotificationRecord` | 通知记录表 | | 扩展 `ExportedSummaryFile.ExportType` | 增加 `zip` 枚举 | Django 模型建议仍集中放在 `review_agent/models.py`,业务逻辑放入 `review_agent/regulatory_info_package/`。 --- ## 十、DDL 参考 以下 DDL 为 SQLite / Django ORM 参考,实际以 migration 生成为准。 ```sql CREATE TABLE ra_regulatory_info_package_batch ( id integer NOT NULL PRIMARY KEY AUTOINCREMENT, conversation_id bigint NOT NULL REFERENCES review_agent_conversation(id), user_id bigint NOT NULL REFERENCES auth_user(id), trigger_message_id bigint NULL REFERENCES review_agent_message(id), source_attachment_id bigint NULL REFERENCES ra_file_attachment(id), source_summary_batch_id bigint NULL REFERENCES ra_file_summary_batch(id), source_summary_item_id integer NULL, batch_no varchar(64) NOT NULL UNIQUE, status varchar(30) NOT NULL, source_file_name varchar(255) NOT NULL DEFAULT '', source_storage_path varchar(500) NOT NULL DEFAULT '', product_name varchar(200) NOT NULL DEFAULT '', output_zip_name varchar(255) NOT NULL DEFAULT '', generated_files text NOT NULL DEFAULT '[]', missing_fields text NOT NULL DEFAULT '[]', llm_only_fields text NOT NULL DEFAULT '[]', conflict_fields text NOT NULL DEFAULT '[]', risk_notes text NOT NULL DEFAULT '[]', template_config_version varchar(80) NOT NULL DEFAULT '', template_config_hash varchar(128) NOT NULL DEFAULT '', adapter_summary text NOT NULL DEFAULT '{}', work_dir varchar(500) NOT NULL DEFAULT '', error_message text NOT NULL DEFAULT '', created_at datetime NOT NULL, started_at datetime NULL, finished_at datetime NULL, archived_at datetime NULL, is_deleted bool NOT NULL DEFAULT 0 ); CREATE INDEX idx_ra_rip_batch_conv_status ON ra_regulatory_info_package_batch(conversation_id, status); CREATE INDEX idx_ra_rip_batch_user_created ON ra_regulatory_info_package_batch(user_id, created_at); CREATE INDEX idx_ra_rip_batch_attachment ON ra_regulatory_info_package_batch(source_attachment_id); CREATE INDEX idx_ra_rip_batch_summary ON ra_regulatory_info_package_batch(source_summary_batch_id); CREATE INDEX idx_ra_rip_batch_created ON ra_regulatory_info_package_batch(created_at); ``` --- ## 十一、实现注意事项 | 注意事项 | 说明 | | --- | --- | | JSONField 默认值 | 使用 `default=list` 或 `default=dict`,禁止使用可变对象字面量 | | 外键删除策略 | conversation/user 使用 CASCADE;输入附件和文件汇总批次建议 PROTECT 或 SET_NULL,避免历史批次断链 | | `source_summary_item_id` | 当前没有强制外键到 `FileSummaryItem`,可先保存 ID,后续需要强约束时再改 FK | | 工作流节点幂等 | RIP 节点不得只依赖 `WorkflowNodeRun.batch + node_code` 唯一约束;必须使用 `workflow_type + workflow_batch_id + node_code` 保证幂等 | | `.doc` 失败记录 | `.doc` 原生适配器不可用或执行失败时必须写入 `risk_notes` 和 artifact metadata;若 `.docx` 兜底成功则 generated_files 状态为 `fallback_success` | | zip 主入口 | zip 导出记录的 `export_category` 固定为 `regulatory_info_package` | | 单文件下载 | 7 个生成文件也写入 `ExportedSummaryFile`,作为辅助下载 | | 软删除 | 批次和产物使用 `is_deleted`,下载权限需过滤软删除批次 | --- ## 十二、验收标准 | 序号 | 验收项 | 标准 | | --- | --- | --- | | 1 | 模型创建 | 三张 RIP 专项表可通过 migration 创建 | | 2 | 批次编号 | `batch_no` 唯一,符合 `RIP-...` 格式 | | 3 | 附件关联 | 批次可绑定直接说明书附件 | | 4 | 汇总兼容 | 批次可选绑定 `FileSummaryBatch` 与 `source_summary_item_id` | | 5 | 产物留痕 | 模板副本、抽取结果、生成文件、zip、追溯清单均可写 artifact | | 6 | zip 导出 | `ExportedSummaryFile` 支持 `export_type=zip` | | 7 | 下载权限 | 非批次所属用户不能下载 RIP 导出 | | 8 | 节点事件 | `WorkflowNodeRun` 和 `WorkflowEvent` 可通过 `workflow_type=regulatory_info_package` 查询 | | 9 | 节点幂等 | 同一 `workflow_type + workflow_batch_id + node_code` 不会重复创建节点 | | 10 | 通知记录 | 通知成功、失败和重试次数可落库 | | 11 | JSON 摘要 | 缺失项、LLM-only、冲突项、风险提示结构符合本文约定 | --- ## 十三、规范依据与裁决 | 规范来源 | 命中规则 | 本设计裁决 | | --- | --- | --- | | GYRX 数据库设计流程 | 项目规范优先,未命中时回退基线规范 | 当前项目为 Django/SQLite,沿用既有数据库设计文档风格 | | 既有自动填表数据库设计 | 独立批次、产物、通知三表;大 JSON 文件化;通用导出表复用 | 本功能按同样模式新增 RIP 三表 | | 自动汇总数据库设计 | 对话隔离、多版本附件、工作流事件留痕 | 输入附件和批次权限沿用该关系 | | 飞书通知数据库设计 | 通知摘要入库、失败不阻断主流程 | RIP 通知表结构与自动填表通知对齐 | 冲突裁决:技能规范中的低代码/Java 表达不适用于当前 Django 项目,数据库设计以当前项目 ORM、SQLite 兼容和既有 `ra_` 表风格为准。