feat: P1-P3 全栈集成 — 数据库基础 + DWS 扩展 + 小程序鉴权 + 工程化体系

## P1 数据库基础
- zqyy_app: 创建 auth/biz schema、FDW 连接 etl_feiqiu
- etl_feiqiu: 创建 app schema RLS 视图、商品库存预警表
- 清理 assistant_abolish 残留数据

## P2 ETL/DWS 扩展
- 新增 DWS 助教订单贡献度表 (dws.assistant_order_contribution)
- 新增 assistant_order_contribution_task 任务及 RLS 视图
- member_consumption 增加充值字段、assistant_daily 增加处罚字段
- 更新 ODS/DWD/DWS 任务文档及业务规则文档
- 更新 consistency_checker、flow_runner、task_registry 等核心模块

## P3 小程序鉴权系统
- 新增 xcx_auth 路由/schema(微信登录 + JWT)
- 新增 wechat/role/matching/application 服务层
- zqyy_app 鉴权表迁移 + 角色权限种子数据
- auth/dependencies.py 支持小程序 JWT 鉴权

## 文档与审计
- 新增 DOCUMENTATION-MAP 文档导航
- 新增 7 份 BD_Manual 数据库变更文档
- 更新 DDL 基线快照(etl_feiqiu 6 schema + zqyy_app auth)
- 新增全栈集成审计记录、部署检查清单更新
- 新增 BACKLOG 路线图、FDW→Core 迁移计划

## Kiro 工程化
- 新增 5 个 Spec(P1/P2/P3/全栈集成/核心业务)
- 新增审计自动化脚本(agent_on_stop/build_audit_context/compliance_prescan)
- 新增 6 个 Hook(合规检查/会话日志/提交审计等)
- 新增 doc-map steering 文件

## 运维与测试
- 新增 ops 脚本:迁移验证/API 健康检查/ETL 监控/集成报告
- 新增属性测试:test_dws_contribution / test_auth_system
- 清理过期 export 报告文件
- 更新 .gitignore 排除规则
This commit is contained in:
Neo
2026-02-26 08:03:53 +08:00
parent fafc95e64c
commit b25308c3f4
224 changed files with 17660 additions and 32198 deletions

View File

@@ -0,0 +1,189 @@
# 需求文档:核心业务层 — 任务系统 + 备注系统 + 触发器机制miniapp-core-business
## 简介
本 SPEC 实现小程序的核心业务逻辑层,涵盖助教任务生成与管理、备注系统、后台触发器/轮询机制。系统基于 P1miniapp-db-foundation已建立的 `biz` Schema、P2etl-dws-miniapp-extensions提供的指数数据WBI/NCI/RS 等通过 FDW 读取、P3miniapp-auth-system提供的用户认证和助教绑定信息`test_zqyy_app.biz` 中创建任务、备注、触发器等业务表,并在 FastAPI 后端实现对应的服务层和 API 端点。
## 术语表
- **Task_System**:任务系统,负责任务生成、状态管理、完成检测的完整后端服务
- **Task_Generator**:任务生成器,每日 04:00 后运行的定时任务,基于指数数据为每个助教分配任务
- **Task_Expiry_Checker**:任务有效期检查器,每小时运行的轮询任务,将超过有效期的任务标记为无效
- **Recall_Completion_Detector**召回完成检测器ETL 数据更新后运行,检测助教是否已为匹配客户提供服务
- **Note_Reclassify_Service**:备注重分类服务,召回完成时触发,将普通备注回溯重分类为回访备注
- **Note_System**:备注系统,负责备注的创建、查询、删除和类型管理
- **Trigger_System**触发器系统统一管理所有条件触发的后台任务cron/event/interval 三种触发方式)
- **coach_task**:助教任务记录,存储在 `biz.coach_tasks` 表中
- **task_type**:任务类型枚举,取值为 `high_priority_recall`(高优先召回)/ `priority_recall`(优先召回)/ `follow_up_visit`(客户回访)/ `relationship_building`(关系构建)
- **task_status**:任务状态枚举,取值为 `active`(有效)/ `inactive`(无效)/ `completed`(已完成)/ `abandoned`(已放弃)
- **note_type**:备注类型枚举,取值为 `normal`(普通备注)/ `follow_up`(回访备注)/ `birthday`(生日信息)/ `abandon_reason`(放弃原因)
- **trigger_type**:触发器类型枚举,取值为 `cron`(定时触发)/ `event`(事件触发)/ `interval`(间隔触发)
- **priority_score**:优先级分数,取 max(WBI, NCI) 的快照值
- **expires_at**:任务有效期,默认为 NULL无有效期当指数不再满足条件时填充为 `created_at + 48h`
- **WBI**老客挽回指数Winback Index0-10 分,来自 `fdw_etl` 的 DWS 数据
- **NCI**新客转化指数New Customer Index0-10 分,来自 `fdw_etl` 的 DWS 数据
- **RS**关系强度指数Relationship Strength0-10 分,客户-助教配对维度
- **site_id**:门店标识符,类型为 `BIGINT`,用于多门店数据隔离
- **assistant_id**:助教标识符,来自 ETL 的 `dim_assistant`,通过 `auth.user_assistant_binding` 与小程序用户关联
- **member_id**:会员标识符,来自 ETL 的 `dim_member`
- **FDW**`postgres_fdw` 外部数据包装器,通过 `fdw_etl` Schema 读取 ETL 库数据
- **Migration_Script**:存放在 `db/zqyy_app/migrations/` 中的纯 SQL 迁移脚本,以日期前缀命名
## 需求
### 需求 1业务数据表创建
**用户故事:** 作为后端开发者,我需要在 `biz` Schema 中创建任务、备注、触发器相关的数据表,以便支撑核心业务功能。
#### 验收标准
1. WHEN Migration_Script 执行完成, THE Task_System SHALL 在 `biz` Schema 中创建 `coach_tasks` 表,包含 `id`SERIAL PK`site_id`BIGINT NOT NULL`assistant_id`BIGINT NOT NULL`member_id`BIGINT NOT NULL`task_type`VARCHAR NOT NULL`status`VARCHAR NOT NULL DEFAULT 'active')、`priority_score`NUMERIC(4,2))、`expires_at`TIMESTAMPTZ默认 NULL`is_pinned`BOOLEAN DEFAULT FALSE`abandon_reason`TEXT`completed_at`TIMESTAMPTZ`completed_task_type`VARCHAR`parent_task_id`INTEGERFK → coach_tasks.id`created_at`TIMESTAMPTZ DEFAULT NOW())、`updated_at`TIMESTAMPTZ DEFAULT NOW())字段
2. WHEN Migration_Script 执行完成, THE Task_System SHALL 在 `biz` Schema 中创建 `coach_task_history` 表,包含 `id`SERIAL PK`task_id`INTEGER FK → coach_tasks.id`action`VARCHAR NOT NULL`old_status`VARCHAR`new_status`VARCHAR`detail`JSONB`created_at`TIMESTAMPTZ DEFAULT NOW())字段
3. WHEN Migration_Script 执行完成, THE Note_System SHALL 在 `biz` Schema 中创建 `notes` 表,包含 `id`SERIAL PK`site_id`BIGINT NOT NULL`author_user_id`INTEGER NOT NULL`target_member_id`BIGINT NOT NULL`target_assistant_id`BIGINT`note_type`VARCHAR NOT NULL DEFAULT 'normal')、`content`TEXT NOT NULL`task_id`INTEGERFK → coach_tasks.id可空`ai_score`NUMERIC(3,1))、`ai_evaluation`TEXT`created_at`TIMESTAMPTZ DEFAULT NOW())、`updated_at`TIMESTAMPTZ DEFAULT NOW())字段
4. WHEN Migration_Script 执行完成, THE Trigger_System SHALL 在 `biz` Schema 中创建 `trigger_jobs` 表,包含 `id`SERIAL PK`job_type`VARCHAR NOT NULL`job_name`VARCHAR NOT NULL`trigger_type`VARCHAR NOT NULL`trigger_config`JSONB NOT NULL`last_run_at`TIMESTAMPTZ`next_run_at`TIMESTAMPTZ`status`VARCHAR NOT NULL DEFAULT 'enabled')、`created_at`TIMESTAMPTZ DEFAULT NOW())字段
5. WHEN Migration_Script 执行完成, THE Trigger_System SHALL 在 `biz` Schema 中创建 `trigger_execution_log` 表,包含 `id`SERIAL PK`job_id`INTEGER FK → trigger_jobs.id`started_at`TIMESTAMPTZ NOT NULL`finished_at`TIMESTAMPTZ`status`VARCHAR NOT NULL`result_summary`JSONB`error_message`TEXT字段
6. THE Migration_Script SHALL 对 `coach_tasks` 表创建索引:`(site_id, assistant_id, status)` 复合索引、`(site_id, member_id)` 复合索引、`(status, expires_at)` 复合索引用于有效期轮询
7. THE Migration_Script SHALL 对 `notes` 表创建索引:`(site_id, target_member_id)` 复合索引、`(author_user_id)` 索引、`(task_id)` 索引
8. THE Migration_Script SHALL 使用 `IF NOT EXISTS` / `OR REPLACE` 等幂等语法,确保重复执行不会报错
9. THE Migration_Script SHALL 在脚本中包含回滚语句(以注释形式)
### 需求 2触发器种子数据预置
**用户故事:** 作为系统管理员,我需要系统预置 4 个核心触发器配置,以便后台任务按预定规则自动运行。
#### 验收标准
1. WHEN 种子数据脚本执行完成, THE Trigger_System SHALL 在 `biz.trigger_jobs` 表中插入 `task_generator` 记录trigger_type=`cron`trigger_config 包含 cron 表达式 `0 4 * * *`,表示每日 04:00
2. WHEN 种子数据脚本执行完成, THE Trigger_System SHALL 在 `biz.trigger_jobs` 表中插入 `task_expiry_check` 记录trigger_type=`interval`trigger_config 包含间隔秒数 3600表示每小时
3. WHEN 种子数据脚本执行完成, THE Trigger_System SHALL 在 `biz.trigger_jobs` 表中插入 `recall_completion_check` 记录trigger_type=`event`trigger_config 包含事件名 `etl_data_updated`
4. WHEN 种子数据脚本执行完成, THE Trigger_System SHALL 在 `biz.trigger_jobs` 表中插入 `note_reclassify_backfill` 记录trigger_type=`event`trigger_config 包含事件名 `recall_completed`
5. THE 种子数据脚本 SHALL 使用 `ON CONFLICT DO NOTHING` 语法,确保重复执行不会产生重复数据
### 需求 3任务生成器
**用户故事:** 作为助教,我每天打开小程序能看到系统为我分配的任务列表,按优先级排序,以便我知道今天应该优先联系哪些客户。
#### 验收标准
1. WHEN Task_Generator 运行时, THE Task_System SHALL 从 `fdw_etl` 读取每个助教关联的客户的 WBI、NCI、RS 指数数据
2. WHEN 某客户的 max(WBI, NCI) > 7, THE Task_Generator SHALL 为该客户-助教配对生成 `high_priority_recall` 类型任务priority_score 记录为 max(WBI, NCI) 的快照值
3. WHEN 某客户的 max(WBI, NCI) > 5 且 ≤ 7, THE Task_Generator SHALL 为该客户-助教配对生成 `priority_recall` 类型任务
4. WHEN 某助教已完成某客户的召回任务且该客户无回访备注, THE Task_Generator SHALL 为该客户-助教配对生成 `follow_up_visit` 类型任务
5. WHEN 某客户-助教配对的 RS < 6, THE Task_Generator SHALL 为该客户-助教配对生成 `relationship_building` 类型任务
6. WHEN Task_Generator 生成任务时发现已存在相同 `(site_id, assistant_id, member_id, task_type)` 且 status 为 `active` 的任务, THE Task_Generator SHALL 跳过该任务,不创建新记录
7. WHEN Task_Generator 生成任务时发现已存在相同 `(site_id, assistant_id, member_id)` 但 task_type 不同且 status 为 `active` 的任务, THE Task_Generator SHALL 将旧任务的 status 更新为 `inactive`,创建新类型的任务,并将新任务的 `parent_task_id` 指向旧任务
8. WHEN Task_Generator 将旧任务标记为 `inactive`(因类型变更), THE Task_System SHALL 将旧任务的 `expires_at` 保持为 NULL类型变更导致的无效不设有效期
9. WHEN 任务类型按优先级排序时, THE Task_Generator SHALL 按以下优先级从高到低处理:`high_priority_recall`0> `priority_recall`0> `follow_up_visit`1> `relationship_building`2同优先级内按 priority_score 降序排列
10. WHEN Task_Generator 运行完成, THE Task_System SHALL 在 `biz.coach_task_history` 中记录本次生成的所有操作(创建、跳过、类型变更)
### 需求 448 小时滞留机制
**用户故事:** 作为系统,回访任务至少保留 48 小时,到期后自动失效,以便助教有足够时间完成回访。
#### 验收标准
1. WHEN Task_Generator 计算出某客户不再满足当前任务条件(指数变化)但该任务仍为 `active``expires_at` 为 NULL, THE Task_System SHALL 将该任务的 `expires_at` 填充为 `created_at + 48 小时`status 保持 `active`
2. WHEN Task_Expiry_Checker 每小时运行时, THE Task_System SHALL 查询所有 status 为 `active``expires_at` 不为 NULL 且 `expires_at` < 当前时间的任务,将其 status 更新为 `inactive`
3. WHEN 一个已有 `expires_at``follow_up_visit` 任务存在,且 Task_Generator 再次生成同客户-助教的 `follow_up_visit` 任务, THE Task_System SHALL 将旧任务标记为 `inactive`,创建新的 `follow_up_visit` 任务(新任务顶替旧任务)
4. WHEN 任务状态变更时, THE Task_System SHALL 在 `biz.coach_task_history` 中记录变更详情(包含旧状态、新状态、变更原因)
### 需求 5召回完成检测
**用户故事:** 作为助教,我完成召回任务后(客户到店被我服务),系统自动标记任务完成,无需手动操作。
#### 验收标准
1. WHEN ETL 数据更新后 Recall_Completion_Detector 运行时, THE Task_System SHALL 查询 `fdw_etl` 中的服务记录(`v_dwd_session_detail` 或等效视图),检测是否有新的助教-客户服务记录
2. WHEN 检测到助教 A 为客户 B 提供了新的服务记录, THE Task_System SHALL 查找助教 A 对客户 B 的所有 status 为 `active` 的任务(无论任务类型),将其 status 更新为 `completed`
3. WHEN 任务被标记为 `completed`, THE Task_System SHALL 记录 `completed_at` 为当前时间,`completed_task_type` 为任务完成时的 task_type 快照
4. WHEN 召回完成后发现该客户-助教配对无回访备注, THE Task_System SHALL 触发 `note_reclassify_backfill` 事件,检查是否需要数据回溯
### 需求 6数据回溯机制
**用户故事:** 作为系统,当 ETL 数据延迟导致召回完成晚于备注提交时,需要回溯重分类备注,确保回访任务正确完成。
#### 验收标准
1. WHEN 召回任务完成时, THE Note_Reclassify_Service SHALL 查询该助教在召回服务结束时间之后为该客户添加的所有 note_type 为 `normal` 的备注
2. WHEN 找到符合条件的普通备注, THE Note_Reclassify_Service SHALL 将第一条(按时间最早)普通备注的 note_type 更新为 `follow_up`,并关联到对应的回访任务(设置 `task_id`
3. WHEN 备注被重分类为 `follow_up` 后, THE Note_Reclassify_Service SHALL 触发 AI 应用 6 的含金量评分流程(评分结果写入 `notes.ai_score``notes.ai_evaluation`
4. WHEN AI 评分结果 ≥ 6 分, THE Task_System SHALL 将对应的回访任务标记为 `completed`
5. WHEN AI 评分结果 < 6 分, THE Task_System SHALL 保持回访任务的当前状态不变,等待助教提交新的备注
### 需求 7任务操作 API
**用户故事:** 作为助教,我可以查看任务列表、置顶/放弃任务、取消置顶/取消放弃,以便灵活管理我的工作优先级。
#### 验收标准
1. WHEN 助教请求任务列表, THE Task_System SHALL 返回该助教在当前 `site_id` 下所有 status 为 `active` 的任务按优先级分组priority 0 → 1 → 2同优先级内按 `is_pinned` 降序、`priority_score` 降序排列
2. WHEN 助教置顶某任务, THE Task_System SHALL 将该任务的 `is_pinned` 更新为 TRUE并在 `coach_task_history` 中记录操作
3. WHEN 助教取消置顶某任务, THE Task_System SHALL 将该任务的 `is_pinned` 更新为 FALSE并在 `coach_task_history` 中记录操作
4. WHEN 助教放弃某任务且提供了放弃原因, THE Task_System SHALL 将该任务的 status 更新为 `abandoned`,记录 `abandon_reason`,并在 `coach_task_history` 中记录操作
5. IF 助教放弃任务时未提供放弃原因(空字符串或纯空白字符), THEN THE Task_System SHALL 返回 HTTP 422 错误,拒绝操作
6. WHEN 助教取消放弃某任务, THE Task_System SHALL 将该任务的 status 恢复为 `active`,清空 `abandon_reason`,并在 `coach_task_history` 中记录操作
7. WHEN 助教请求任务详情, THE Task_System SHALL 返回任务的完整信息,包含客户基本信息(通过 FDW 查询)、指数快照、备注列表、近期服务记录
8. WHEN 助教请求已放弃任务列表, THE Task_System SHALL 返回该助教在当前 `site_id` 下所有 status 为 `abandoned` 的任务列表
### 需求 8备注 CRUD
**用户故事:** 作为助教,我可以为客户添加、查看、删除备注,以便记录客户信息和服务跟进情况。
#### 验收标准
1. WHEN 助教为某客户创建备注(提供 content 和可选的 note_type, THE Note_System SHALL 在 `biz.notes` 表中创建记录,`author_user_id` 为当前登录用户 ID`site_id` 为当前店铺 ID
2. WHEN 助教在回访任务上下文中创建备注, THE Note_System SHALL 将 note_type 设置为 `follow_up`,并将 `task_id` 关联到对应的回访任务
3. WHEN 回访备注创建后, THE Note_System SHALL 触发 AI 应用 6 的含金量评分流程,将评分结果写入 `notes.ai_score``notes.ai_evaluation`
4. WHEN AI 评分结果 ≥ 6 分, THE Task_System SHALL 将对应的回访任务标记为 `completed`
5. WHEN AI 评分结果 < 6 分, THE Task_System SHALL 保持回访任务状态不变
6. WHEN 助教查询某客户的备注列表, THE Note_System SHALL 返回该客户在当前 `site_id` 下的所有备注,按 `created_at` 降序排列
7. WHEN 助教删除某条备注, THE Note_System SHALL 从 `biz.notes` 表中删除该记录
8. IF 助教创建备注时 content 为空字符串或纯空白字符, THEN THE Note_System SHALL 返回 HTTP 422 错误,拒绝创建
### 需求 9生日信息隔离存储
**用户故事:** 作为助教,我为客户记录的生日信息独立于 ETL 数据,不会被 ETL 数据更新覆盖。
#### 验收标准
1. WHEN 助教为某客户添加生日备注note_type=`birthday`, THE Note_System SHALL 在 `biz.notes` 表中创建记录content 存储生日值
2. THE Note_System SHALL 确保 note_type 为 `birthday` 的备注记录独立于 ETL 数据管道ETL 数据更新不会修改或删除这些记录
3. WHEN 查询某客户的生日信息时, THE Note_System SHALL 从 `biz.notes` 表中查询 note_type 为 `birthday` 的最新记录,返回 content生日值`author_user_id`(记录者)
### 需求 10触发器调度框架
**用户故事:** 作为系统,我需要一个统一的触发器调度框架来管理所有后台任务的触发和执行。
#### 验收标准
1. THE Trigger_System SHALL 支持三种触发方式:`cron`(基于 cron 表达式的定时触发)、`event`(基于事件名的事件触发)、`interval`(基于固定间隔秒数的间隔触发)
2. WHEN cron 类型触发器到达触发时间, THE Trigger_System SHALL 执行对应的任务处理函数,并更新 `last_run_at``next_run_at`
3. WHEN event 类型触发器收到匹配的事件通知, THE Trigger_System SHALL 执行对应的任务处理函数,并更新 `last_run_at`
4. WHEN interval 类型触发器距上次运行超过配置的间隔秒数, THE Trigger_System SHALL 执行对应的任务处理函数,并更新 `last_run_at``next_run_at`
5. WHEN 触发器执行完成(成功或失败), THE Trigger_System SHALL 在 `biz.trigger_execution_log` 中记录执行日志,包含开始时间、结束时间、执行状态、结果摘要或错误信息
6. WHEN 触发器 status 为 `disabled`, THE Trigger_System SHALL 跳过该触发器的执行
7. IF 触发器执行过程中发生异常, THEN THE Trigger_System SHALL 捕获异常,在执行日志中记录错误信息,触发器状态保持 `enabled`(不因单次失败而禁用)
### 需求 11迁移脚本管理
**用户故事:** 作为后端开发者,我需要所有数据库变更都有对应的迁移脚本,以便变更可追溯、可重放。
#### 验收标准
1. THE Migration_Script SHALL 将所有业务相关表的 DDL 存放在 `db/zqyy_app/migrations/` 目录中
2. THE Migration_Script SHALL 使用日期前缀命名(格式:`YYYY-MM-DD__<描述>.sql`
3. THE Migration_Script SHALL 使用 UTF-8 编码,纯 SQL非 ORM
4. THE Migration_Script SHALL 在每个脚本中包含回滚语句(以注释形式)
5. THE Migration_Script SHALL 使用幂等语法(`IF NOT EXISTS``ON CONFLICT DO NOTHING`),确保重复执行不会报错
### 需求 12DDL 测试库落库与文档同步
**用户故事:** 作为后端开发者,我需要所有 DDL 变更在测试库(`test_zqyy_app`)中实际执行验证,并同步更新数据库手册和 DDL 基线,确保文档与实际 Schema 一致。
#### 验收标准
1. WHEN 迁移脚本编写完成, THE Task_System SHALL 在 `test_zqyy_app` 测试库中执行独立的迁移脚本(`db/zqyy_app/migrations/` 下的 SQL 文件)进行落库,验证无错误
2. WHEN 迁移脚本执行成功, THE Task_System SHALL 创建或更新 `biz` Schema 相关的数据库手册文档,包含变更说明、兼容性影响、回滚策略、验证 SQL至少 3 条)
3. WHEN 迁移脚本执行成功, THE Task_System SHALL 运行 `python scripts/ops/gen_consolidated_ddl.py` 将新表的 DDL 合并到主 DDL 基线文件中
4. WHEN 种子数据脚本执行成功, THE Task_System SHALL 在数据库手册中记录种子数据内容(触发器配置)
5. THE Task_System SHALL 同步更新所有相关文档包括数据库手册、DDL 基线、部署文档等),确保文档与实际 Schema 保持一致