303 lines
12 KiB
Markdown
303 lines
12 KiB
Markdown
# 飞书通知与问答接入数据库设计
|
||
|
||
## 文档信息
|
||
|
||
| 项目 | 内容 |
|
||
| --- | --- |
|
||
| 需求分析文档 | docs/1.需求分析/4.飞书通知与问答接入.md |
|
||
| 功能设计文档 | docs/2.功能设计/4.飞书通知与问答接入.md |
|
||
| 数据库类型 | SQLite / Django ORM |
|
||
| 表名前缀 | ra_ |
|
||
| 设计日期 | 2026-06-07 |
|
||
| 设计版本 | V1.0 |
|
||
|
||
---
|
||
|
||
## 一、设计原则
|
||
|
||
| 原则 | 说明 |
|
||
| --- | --- |
|
||
| 统一通知抽象 | 三个工作流共用统一通知服务和通用通知记录,减少重复实现 |
|
||
| 兼容现有表 | 现有法规通知、填表通知可保留;新增通用表作为后续统一入口 |
|
||
| 可判重 | 通知记录必须支持同一批次、同一流程、同一状态只发送一次 |
|
||
| 摘要入库 | 只保存发送摘要、状态、错误,不保存完整富文本 payload |
|
||
| 映射可维护 | 系统用户与飞书用户映射独立建表,通过 Django Admin 维护 |
|
||
| 问答可扩展 | 预留问答日志表,首期可不接事件回调 |
|
||
| SQLite 兼容 | 使用 Django ORM 常规字段,避免数据库特有能力 |
|
||
|
||
---
|
||
|
||
## 二、ER 图
|
||
|
||
```mermaid
|
||
erDiagram
|
||
AUTH_USER ||--o{ RA_FEISHU_USER_MAPPING : maps
|
||
AUTH_USER ||--o{ RA_WORKFLOW_NOTIFICATION_RECORD : triggers
|
||
RA_FEISHU_USER_MAPPING ||--o{ RA_WORKFLOW_NOTIFICATION_RECORD : resolves
|
||
AUTH_USER ||--o{ RA_FEISHU_QUESTION_LOG : asks
|
||
|
||
RA_WORKFLOW_NOTIFICATION_RECORD {
|
||
bigint id
|
||
string workflow_type
|
||
bigint workflow_batch_id
|
||
string workflow_status
|
||
string dedupe_key
|
||
string channel
|
||
string target
|
||
string send_status
|
||
}
|
||
|
||
RA_FEISHU_USER_MAPPING {
|
||
bigint id
|
||
bigint system_user_id
|
||
string feishu_open_id
|
||
string feishu_user_id
|
||
string feishu_mobile
|
||
boolean is_active
|
||
}
|
||
|
||
RA_FEISHU_QUESTION_LOG {
|
||
bigint id
|
||
bigint system_user_id
|
||
string feishu_open_id
|
||
string intent
|
||
string query_object
|
||
string status
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 三、表结构设计
|
||
|
||
### 3.1 ra_feishu_user_mapping
|
||
|
||
系统用户与飞书用户标识映射表。首期通知发送给环境变量中配置的指定个人账号,本表通过 Django Admin 手工维护,用于后续按发起人私聊通知和飞书私聊问答身份识别。
|
||
|
||
| 字段名 | Django 类型 | SQLite 类型 | 必填 | 说明 |
|
||
| --- | --- | --- | --- | --- |
|
||
| id | BigAutoField | integer | 是 | 主键 |
|
||
| system_user_id | ForeignKey | bigint | 是 | 关联 Django 用户 |
|
||
| feishu_display_name | CharField(120) | varchar(120) | 否 | 飞书展示名,便于后台识别 |
|
||
| feishu_open_id | CharField(120) | varchar(120) | 否 | 飞书 open_id,优先用于 @ |
|
||
| feishu_user_id | CharField(120) | varchar(120) | 否 | 飞书 user_id,第二优先级 |
|
||
| feishu_mobile | CharField(40) | varchar(40) | 否 | 飞书手机号,兜底 |
|
||
| is_active | BooleanField | bool | 是 | 是否启用 |
|
||
| remark | CharField(255) | varchar(255) | 否 | 备注 |
|
||
| created_at | DateTimeField | datetime | 是 | 创建时间 |
|
||
| updated_at | DateTimeField | datetime | 是 | 更新时间 |
|
||
|
||
约束:
|
||
|
||
| 约束名 | 字段 | 说明 |
|
||
| --- | --- | --- |
|
||
| uq_ra_feishu_mapping_user | system_user_id | 一个系统用户首期只维护一条启用映射 |
|
||
|
||
索引:
|
||
|
||
| 索引名 | 字段 | 说明 |
|
||
| --- | --- | --- |
|
||
| idx_ra_feishu_mapping_active | is_active | 后台筛选启用映射 |
|
||
| idx_ra_feishu_mapping_open | feishu_open_id | 后续私聊事件反查用户 |
|
||
| idx_ra_feishu_mapping_userid | feishu_user_id | 后续私聊事件反查用户 |
|
||
| idx_ra_feishu_mapping_mobile | feishu_mobile | 手机号兜底查询 |
|
||
|
||
校验规则:
|
||
|
||
| 规则 | 说明 |
|
||
| --- | --- |
|
||
| 至少一个飞书标识 | `feishu_open_id`、`feishu_user_id`、`feishu_mobile` 至少填写一个 |
|
||
| @ 优先级 | `feishu_open_id -> feishu_user_id -> feishu_mobile` |
|
||
|
||
---
|
||
|
||
### 3.2 ra_workflow_notification_record
|
||
|
||
通用工作流通知记录表。用于记录自动汇总、法规核查、自动填表的飞书通知发送结果。现有专项通知表可继续保留,后续逐步收敛到本表。
|
||
|
||
| 字段名 | Django 类型 | SQLite 类型 | 必填 | 说明 |
|
||
| --- | --- | --- | --- | --- |
|
||
| id | BigAutoField | integer | 是 | 主键 |
|
||
| workflow_type | CharField(40) | varchar(40) | 是 | file_summary、regulatory_review、application_form_fill |
|
||
| workflow_batch_id | PositiveBigIntegerField | bigint | 是 | 对应工作流批次 ID |
|
||
| workflow_batch_no | CharField(80) | varchar(80) | 是 | 批次编号冗余,便于展示 |
|
||
| workflow_status | CharField(40) | varchar(40) | 是 | success、partial_success、failed 等 |
|
||
| dedupe_key | CharField(160) | varchar(160) | 是 | 判重键 |
|
||
| trigger_user_id | ForeignKey | bigint | 是 | 发起人或上传人 |
|
||
| feishu_mapping_id | ForeignKey | bigint | 否 | 命中的飞书用户映射 |
|
||
| channel | CharField(40) | varchar(40) | 是 | mock、feishu_api、disabled |
|
||
| target | CharField(160) | varchar(160) | 否 | 指定个人账号名称、open_id、user_id 或目标标识 |
|
||
| at_display_name | CharField(120) | varchar(120) | 否 | 被 @ 人展示名 |
|
||
| at_identifier_type | CharField(30) | varchar(30) | 否 | open_id、user_id、mobile、missing |
|
||
| at_identifier_masked | CharField(120) | varchar(120) | 否 | 脱敏后的 @ 标识 |
|
||
| send_status | CharField(30) | varchar(30) | 是 | pending、success、failed、skipped_duplicate、disabled |
|
||
| message_title | CharField(200) | varchar(200) | 是 | 通知标题 |
|
||
| message_summary | TextField | text | 否 | 发送摘要,不保存完整 payload |
|
||
| result_url | CharField(500) | varchar(500) | 否 | 系统结果入口 |
|
||
| external_message_id | CharField(120) | varchar(120) | 否 | Webhook 一般为空,API 发送时保存 |
|
||
| error_code | CharField(80) | varchar(80) | 否 | 飞书或客户端错误码 |
|
||
| error_message | TextField | text | 否 | 失败原因 |
|
||
| request_duration_ms | PositiveIntegerField | integer | 否 | HTTP 请求耗时 |
|
||
| sent_at | DateTimeField | datetime | 否 | 成功发送时间 |
|
||
| created_at | DateTimeField | datetime | 是 | 创建时间 |
|
||
| updated_at | DateTimeField | datetime | 是 | 更新时间 |
|
||
|
||
唯一约束:
|
||
|
||
| 约束名 | 字段 | 说明 |
|
||
| --- | --- | --- |
|
||
| uq_ra_notify_dedupe_key | dedupe_key | 同一批次、流程、状态只保留一个成功发送意图 |
|
||
|
||
索引:
|
||
|
||
| 索引名 | 字段 | 说明 |
|
||
| --- | --- | --- |
|
||
| idx_ra_notify_workflow | workflow_type, workflow_batch_id | 批次详情页查询通知 |
|
||
| idx_ra_notify_user_created | trigger_user_id, created_at | 用户通知历史 |
|
||
| idx_ra_notify_status | send_status, created_at | 排查失败通知 |
|
||
| idx_ra_notify_batch_no | workflow_batch_no | 按批次编号检索 |
|
||
|
||
dedupe_key 生成规则:
|
||
|
||
```text
|
||
{workflow_type}:{workflow_batch_id}:{workflow_status}
|
||
```
|
||
|
||
---
|
||
|
||
### 3.3 ra_feishu_question_log
|
||
|
||
飞书问答日志预留表。首期可创建表但不接入事件回调;后续私聊问答 MVP 使用该表记录问题、意图、查询对象、回答摘要和错误信息。
|
||
|
||
| 字段名 | Django 类型 | SQLite 类型 | 必填 | 说明 |
|
||
| --- | --- | --- | --- | --- |
|
||
| id | BigAutoField | integer | 是 | 主键 |
|
||
| system_user_id | ForeignKey | bigint | 否 | 识别出的系统用户 |
|
||
| feishu_mapping_id | ForeignKey | bigint | 否 | 命中的飞书映射 |
|
||
| feishu_open_id | CharField(120) | varchar(120) | 否 | 事件中的 open_id |
|
||
| feishu_user_id | CharField(120) | varchar(120) | 否 | 事件中的 user_id |
|
||
| source_type | CharField(30) | varchar(30) | 是 | private_chat、group_mention |
|
||
| message_id | CharField(120) | varchar(120) | 否 | 飞书消息 ID |
|
||
| question_text | TextField | text | 是 | 用户原始问题 |
|
||
| intent | CharField(60) | varchar(60) | 否 | batch_status、risk_summary、export_summary 等 |
|
||
| query_object | JSONField | text/json | 是 | 批次号、工作流类型、最近批次等查询对象 |
|
||
| answer_summary | TextField | text | 否 | 回答摘要,不保存完整回答正文 |
|
||
| permission_result | CharField(40) | varchar(40) | 否 | allowed、denied、unbound |
|
||
| status | CharField(30) | varchar(30) | 是 | success、failed、ignored |
|
||
| error_message | TextField | text | 否 | 异常说明 |
|
||
| processed_at | DateTimeField | datetime | 否 | 处理完成时间 |
|
||
| created_at | DateTimeField | datetime | 是 | 创建时间 |
|
||
|
||
索引:
|
||
|
||
| 索引名 | 字段 | 说明 |
|
||
| --- | --- | --- |
|
||
| idx_ra_feishu_q_user_created | system_user_id, created_at | 用户问答历史 |
|
||
| idx_ra_feishu_q_intent | intent, created_at | 按意图分析 |
|
||
| idx_ra_feishu_q_status | status, created_at | 排查失败问答 |
|
||
| idx_ra_feishu_q_message | message_id | 消息幂等 |
|
||
|
||
---
|
||
|
||
## 四、状态枚举
|
||
|
||
### 4.1 WorkflowNotificationRecord.channel
|
||
|
||
| 值 | 说明 |
|
||
| --- | --- |
|
||
| mock | 模拟通知 |
|
||
| disabled | 真实通知未启用 |
|
||
| feishu_api | 飞书官方智能体/企业自建应用消息 API |
|
||
| feishu_webhook | 备选自定义机器人 Webhook,非首期主方案 |
|
||
|
||
### 4.2 WorkflowNotificationRecord.send_status
|
||
|
||
| 值 | 说明 |
|
||
| --- | --- |
|
||
| pending | 待发送 |
|
||
| success | 发送成功 |
|
||
| failed | 发送失败 |
|
||
| skipped_duplicate | 重复通知跳过 |
|
||
| disabled | 未启用真实发送 |
|
||
|
||
### 4.3 FeishuQuestionLog.intent
|
||
|
||
| 值 | 说明 |
|
||
| --- | --- |
|
||
| batch_status | 查询批次状态 |
|
||
| risk_summary | 查询风险摘要 |
|
||
| missing_summary | 查询缺失摘要 |
|
||
| export_summary | 查询导出摘要 |
|
||
| unknown | 未识别 |
|
||
|
||
---
|
||
|
||
## 五、与现有表的兼容关系
|
||
|
||
| 现有表 | 处理建议 |
|
||
| --- | --- |
|
||
| `ra_regulatory_notification_record` | 保留现有数据;法规核查真实飞书通知可新增写入通用表,后续再决定是否迁移 |
|
||
| `ra_application_form_fill_notification_record` | 保留现有数据;自动填表通知状态展示可优先读通用表,兼容旧表 |
|
||
| `ra_exported_summary_file` | 通知摘要中的导出文件数量来自该表 |
|
||
| `ra_workflow_event` | 可记录通知节点事件,但不替代通知记录表 |
|
||
| `auth_user` | 飞书映射通过外键关联系统用户 |
|
||
|
||
---
|
||
|
||
## 六、数据脱敏与安全
|
||
|
||
| 数据 | 入库策略 |
|
||
| --- | --- |
|
||
| App ID | 不入库,只在环境变量中维护 |
|
||
| App Secret | 不入库,只在环境变量中维护 |
|
||
| tenant_access_token | 不持久化入库,仅允许进程内短期缓存 |
|
||
| 富文本完整 payload | 不入库 |
|
||
| 手机号 | 映射表保存原值;通知记录只保存脱敏值 |
|
||
| open_id/user_id | 映射表保存原值;通知记录保存脱敏值 |
|
||
| 用户问题 | 问答日志保存原始问题,用于审计;不保存完整回答正文 |
|
||
|
||
---
|
||
|
||
## 七、迁移计划
|
||
|
||
| 步骤 | 说明 |
|
||
| --- | --- |
|
||
| 1 | 新增 `FeishuUserMapping` 模型和迁移 |
|
||
| 2 | 新增 `WorkflowNotificationRecord` 模型和迁移 |
|
||
| 3 | 新增 `FeishuQuestionLog` 预留模型和迁移 |
|
||
| 4 | 注册 Django Admin 管理入口 |
|
||
| 5 | 批次详情页查询通用通知记录展示 |
|
||
| 6 | 保留现有专项通知表,不做破坏性迁移 |
|
||
|
||
---
|
||
|
||
## 八、验收 SQL 示例
|
||
|
||
查询某个批次通知状态:
|
||
|
||
```sql
|
||
SELECT workflow_type, workflow_batch_no, workflow_status, channel, send_status, sent_at, error_message
|
||
FROM ra_workflow_notification_record
|
||
WHERE workflow_type = 'application_form_fill'
|
||
AND workflow_batch_no = 'AFF-20260607-001'
|
||
ORDER BY created_at DESC;
|
||
```
|
||
|
||
查询未配置飞书映射的失败或降级通知:
|
||
|
||
```sql
|
||
SELECT workflow_type, workflow_batch_no, trigger_user_id, send_status, message_summary
|
||
FROM ra_workflow_notification_record
|
||
WHERE at_identifier_type = 'missing'
|
||
ORDER BY created_at DESC;
|
||
```
|
||
|
||
查询飞书用户映射:
|
||
|
||
```sql
|
||
SELECT u.username, m.feishu_display_name, m.feishu_open_id, m.feishu_user_id, m.feishu_mobile, m.is_active
|
||
FROM ra_feishu_user_mapping m
|
||
JOIN auth_user u ON u.id = m.system_user_id
|
||
ORDER BY u.username;
|
||
```
|