21 KiB
21 KiB
第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 图
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。
三、表结构设计
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 |
| 既有预留 | ||
| 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 | 可为空;如为兼容旧查询,不建议绑定文件汇总批次 |
建议新增节点:
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
[
{
"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
[
{
"target_file": "CH1.4 申请表.docx",
"field_key": "applicant_name",
"field_label": "申请人名称",
"final_value": "/",
"highlight_reason": "missing",
"needs_review": true
}
]
6.3 llm_only_fields
[
{
"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
[
{
"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
[
{
"type": "legacy_doc_adapter_unavailable",
"message": "CH1.9 为 .doc 文件,当前环境未检测到可写入适配器。",
"template_code": "ch1_9_pre_submission"
},
{
"type": "knowledge_base_unavailable",
"message": "标准清单知识库查询不可用,未自动写入候选标准。"
}
]
6.6 adapter_summary
{
"docx": {
"adapter": "DocxDocumentAdapter",
"status": "available"
},
"doc": {
"adapter": "WordComDocAdapter",
"status": "available",
"fallback_used": false
}
}
6.7 artifact.metadata
{
"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"
}
七、存储路径设计
批次目录:
media/regulatory_info_package/{user_id}/{conversation_id}/{batch_no}/
目录结构:
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 批次权限
RegulatoryInfoPackageBatch.conversation.user_id == request.user.id
8.2 输入附件权限
FileAttachment.conversation_id == batch.conversation_id
FileAttachment.user_id == batch.user_id
FileAttachment.upload_status != deleted
8.3 导出下载权限
ExportedSummaryFile 下载时按 workflow_type 分支:
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 生成为准。
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 |
.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 | 通知记录 | 通知成功、失败和重试次数可落库 |
| 10 | JSON 摘要 | 缺失项、LLM-only、冲突项、风险提示结构符合本文约定 |
十三、规范依据与裁决
| 规范来源 | 命中规则 | 本设计裁决 |
|---|---|---|
| GYRX 数据库设计流程 | 项目规范优先,未命中时回退基线规范 | 当前项目为 Django/SQLite,沿用既有数据库设计文档风格 |
| 既有自动填表数据库设计 | 独立批次、产物、通知三表;大 JSON 文件化;通用导出表复用 | 本功能按同样模式新增 RIP 三表 |
| 自动汇总数据库设计 | 对话隔离、多版本附件、工作流事件留痕 | 输入附件和批次权限沿用该关系 |
| 飞书通知数据库设计 | 通知摘要入库、失败不阻断主流程 | RIP 通知表结构与自动填表通知对齐 |
冲突裁决:技能规范中的低代码/Java 表达不适用于当前 Django 项目,数据库设计以当前项目 ORM、SQLite 兼容和既有 ra_ 表风格为准。