chore(audit): 补追 96 份未入仓审计孤本 — 覆盖 2026-02-26 ~ 2026-04-08
这些审计记录原本堆积在 docs/audit/changes/changes/ 嵌套误产物目录下(由开发机迁移
79d3c2e 前后的不明批量操作产生)。由于同期 .gitignore 屏蔽了 docs/audit/ 全目录,
它们从未入过 git 任何分支 history。删除即永久丢失。
按 docs/specs/audit-gap-recovery/tasks.md 阶段 1 执行,将全部 96 份 D 类孤本
(主目录无同名、git history 亦无记录)复制到 docs/audit/changes/ 主目录入仓。
涵盖主题: P1-P18 全栈集成 / 多模块累积变更 / ETL bug 修复 / 业务日切 /
召回与任务引擎改造 / 租户管理与审批 / 董事会财务 / 客户与助教详情 /
DDL 基线合并 / Kiro 到 Claude Code 迁移
阶段 2(B 类内容漂移 1 份)和阶段 4(嵌套目录删除)独立推进。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
109
docs/audit/changes/2026-04-08__fix13-recall-events-refactor.md
Normal file
109
docs/audit/changes/2026-04-08__fix13-recall-events-refactor.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# 变更审计记录:Fix-13 回滚手动完成 + 广义召回完成机制
|
||||
|
||||
| 字段 | 值 |
|
||||
|------|-----|
|
||||
| 日期 | 2026-04-08 15:08:50 |
|
||||
|
||||
## 操作摘要
|
||||
|
||||
Fix-13 看板审计修复计划,包含两部分改动。
|
||||
|
||||
**第一部分:回滚手动完成路径。** 用户确认回访任务应通过提交备注自动完成(note_service 中 completed_by_note 逻辑),不需要手动完成按钮。删除 `POST /{task_id}/complete` 接口、`ManualCompleteRequest` 模型及 `manual_complete_task()` 函数。`completion_type` 字段保留,recall_detector 自动完成仍写 `'auto'`。
|
||||
|
||||
**第二部分:广义召回完成机制。** 原 recall_detector 只检测有 active 任务的客户到店。需求要求所有 MAIN 关系对的关联客户到店都算一次广义召回,都要分配回访任务。重写 recall_detector,新增 `biz.recall_events` 表记录召回事件(ON CONFLICT 按天去重),看板召回数改从该表统计。
|
||||
|
||||
## 变更文件
|
||||
|
||||
### 修改
|
||||
|
||||
| 文件 | 改动要点 |
|
||||
|------|----------|
|
||||
| `apps/backend/app/routers/xcx_tasks.py` | 删除 `POST /{task_id}/complete` 接口、`ManualCompleteRequest` 模型、pydantic `BaseModel, Field` 导入 |
|
||||
| `apps/backend/app/services/task_manager.py` | 删除 `manual_complete_task()` 函数(约 47 行) |
|
||||
| `apps/backend/app/services/recall_detector.py` | 重写。扫描范围从"有 active 任务"扩大为"所有 os_label='MAIN' 的关联客户"。新增写 recall_events 表(ON CONFLICT 按天去重)。无 active 任务的客户到店也生成 follow_up_visit(48h 过期) |
|
||||
| `apps/backend/app/services/board_service.py` | `_query_coach_tasks()` 召回数改从 `recall_events` 统计(天然去重),回访数保持从 `coach_tasks` 统计 |
|
||||
| `db/zqyy_app/schemas/biz.sql` | 新增 `recall_events` 表定义 |
|
||||
| `docs/database/ddl/zqyy_app__biz.sql` | 同步源 DDL |
|
||||
|
||||
## 改动注解
|
||||
|
||||
### `apps/backend/app/services/recall_detector.py`(高风险)
|
||||
完全重写。核心变化:
|
||||
- 扫描范围:从"有 active 任务的客户"扩大为"所有 os_label='MAIN' 的关联客户"
|
||||
- 新增逻辑:每次检测到客户到店,写入 `biz.recall_events`(按天去重)
|
||||
- 新增逻辑:无 active 任务的客户到店也生成 `follow_up_visit` 类型回访任务(48h 过期)
|
||||
- 每个 site_id 两次 `_fdw_context` 调用
|
||||
|
||||
### `apps/backend/app/services/board_service.py`(高风险)
|
||||
`_query_coach_tasks()` 中召回数数据源从 coach_tasks 改为 recall_events 表,天然去重不重复叠加。回访数统计逻辑不变。
|
||||
|
||||
### `apps/backend/app/routers/xcx_tasks.py`(高风险)
|
||||
删除手动完成接口及相关模型。路由数从 8 个减少到 7 个。
|
||||
|
||||
### `apps/backend/app/services/task_manager.py`(高风险)
|
||||
删除 `manual_complete_task()` 函数(约 47 行),其余逻辑不变。
|
||||
|
||||
### `db/zqyy_app/schemas/biz.sql`(高风险)
|
||||
新增 `recall_events` 表,详见数据库变更节。
|
||||
|
||||
### `docs/database/ddl/zqyy_app__biz.sql`
|
||||
同步源 DDL,无额外逻辑。
|
||||
|
||||
## 数据库变更
|
||||
|
||||
### 新增
|
||||
|
||||
| 对象 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `biz.recall_events` | 表 | 召回事件记录(8 字段:id, site_id, assistant_id, member_id, pay_time, task_id, task_type, created_at) |
|
||||
| `biz.recall_events_id_seq` | 序列 | recall_events 主键序列 |
|
||||
| `recall_events_pkey` | 主键约束 | PK on id |
|
||||
| `recall_events_task_id_fkey` | 外键约束 | FK → coach_tasks(id) |
|
||||
| `idx_recall_events_site_assistant_member_day` | 唯一索引 | (site_id, assistant_id, member_id, date(pay_time)),按天去重 |
|
||||
| `idx_recall_events_assistant_pay` | 索引 | (assistant_id, pay_time),查询优化 |
|
||||
|
||||
## 风险与回滚
|
||||
|
||||
### 风险
|
||||
|
||||
| 级别 | 描述 |
|
||||
|------|------|
|
||||
| 高 | 首次运行 recall_detector 会为所有历史有结算的 MAIN 关系对写 recall_events + 生成回访任务,数据量可能很大 |
|
||||
| 中 | ETL 连接开销,每个 site_id 两次 _fdw_context |
|
||||
| 低 | coach_tasks 唯一约束冲突(已通过先关闭旧回访再新建避免) |
|
||||
|
||||
### 回滚策略
|
||||
|
||||
数据库回滚(逆序执行):
|
||||
|
||||
```sql
|
||||
DROP INDEX IF EXISTS biz.idx_recall_events_assistant_pay;
|
||||
DROP INDEX IF EXISTS biz.idx_recall_events_site_assistant_member_day;
|
||||
ALTER TABLE biz.recall_events DROP CONSTRAINT IF EXISTS recall_events_task_id_fkey;
|
||||
ALTER TABLE biz.recall_events DROP CONSTRAINT IF EXISTS recall_events_pkey;
|
||||
DROP TABLE IF EXISTS biz.recall_events;
|
||||
DROP SEQUENCE IF EXISTS biz.recall_events_id_seq;
|
||||
```
|
||||
|
||||
后端代码回退:`git checkout HEAD~1 -- apps/backend/app/services/recall_detector.py apps/backend/app/services/board_service.py apps/backend/app/routers/xcx_tasks.py apps/backend/app/services/task_manager.py`
|
||||
|
||||
## 验证
|
||||
|
||||
| 验证项 | 结果 |
|
||||
|--------|------|
|
||||
| 模块导入 `recall_detector` | ✅ 通过 |
|
||||
| 路由验证 `xcx_tasks` 7 个路由,无 `/complete` | ✅ 通过 |
|
||||
| 数据库表结构(recall_events 8 字段) | ✅ 通过 |
|
||||
| 唯一索引(按天去重) | ✅ 通过 |
|
||||
| FK 约束(→ coach_tasks) | ✅ 通过 |
|
||||
| 后端 pytest | ⚠️ 无法运行(dashscope 依赖未安装,非本次改动引入) |
|
||||
|
||||
## 合规检查
|
||||
|
||||
| 检查项 | 结果 |
|
||||
|--------|------|
|
||||
| DDL 文档同步 `docs/database/ddl/zqyy_app__biz.sql` | ✅ 已同步 |
|
||||
| RLS 双 Schema 规则 | ⚠️ recall_events 为业务库表,非 ETL 层,不适用 |
|
||||
| API 文档 `apps/backend/docs/API-REFERENCE.md` | ⚠️ 待检查是否存在 |
|
||||
| 后端 README `apps/backend/README.md` | ⚠️ 待检查是否存在 |
|
||||
| 审计记录 | ✅ 本文件 |
|
||||
Reference in New Issue
Block a user