14 KiB
实现计划:小程序核心业务模块(miniapp-core-business)
概述
基于已批准的需求和设计文档,将小程序核心业务模块拆分为增量式编码任务。按照"DDL 建表 → 触发器调度框架 → 任务生成器 → 任务管理 → 有效期轮询 → 召回检测 → 备注系统 → 路由集成"的顺序实现。后端使用 Python + FastAPI,数据库使用 PostgreSQL 纯 SQL,属性测试使用 hypothesis。所有数据库操作在测试库 test_zqyy_app 中进行。
任务
-
1. 创建业务数据表和种子数据
-
1.1 创建迁移脚本
db/zqyy_app/migrations/YYYY-MM-DD__p4_create_biz_tables.sql- 在
bizSchema 下创建coach_tasks、coach_task_history、notes、trigger_jobs共 4 张表 - 包含所有字段定义、约束、CHECK 约束(评分 1-5)、外键(coach_task_history → coach_tasks、notes → coach_tasks、coach_tasks → coach_tasks 自引用)
- 创建部分唯一索引
idx_coach_tasks_site_assistant_member_type(仅 status='active') - 创建查询索引
idx_coach_tasks_assistant_status、idx_notes_target - 使用
IF NOT EXISTS幂等语法 - 包含回滚语句(注释形式)
- Requirements: 1.1-1.9
- 在
-
1.2 创建种子数据脚本
db/zqyy_app/migrations/YYYY-MM-DD__p4_seed_trigger_jobs.sql- 插入 4 条触发器配置:
task_generator(cron, 0 4 * * *)、task_expiry_check(interval, 3600s)、recall_completion_check(event, etl_data_updated)、note_reclassify_backfill(event, recall_completed) - 使用
ON CONFLICT (job_name) DO NOTHING幂等语法 - Requirements: 2.1-2.5
- 插入 4 条触发器配置:
-
1.3 在测试库执行迁移脚本并验证
- 在
test_zqyy_app中执行建表脚本和种子数据脚本 - 验证幂等性:连续执行两次无错误
- 验证表结构、约束、索引正确
- 验证种子数据完整(4 条触发器配置)
- Requirements: 11.1-11.5, 12.1
- 在
-
1.4 更新数据库手册和 DDL 基线
- 创建
docs/database/BD_Manual_biz_tables.md,包含变更说明、兼容性影响、回滚策略、验证 SQL(至少 3 条) - 运行
python scripts/ops/gen_consolidated_ddl.py刷新 DDL 基线 - 在数据库手册中记录种子数据内容(触发器配置)
- Requirements: 12.2, 12.3, 12.4
- 创建
-
1.5 编写迁移脚本幂等性属性测试
- Property 13: 迁移脚本幂等性
- 对 DDL 脚本和种子数据脚本连续执行两次,验证第二次执行无错误且数据库状态不变
- Validates: Requirements 1.8, 2.5, 11.4, 11.5
-
-
2. 检查点 - 确保 DDL 和种子数据正确
- 确保迁移脚本在测试库中执行成功,幂等性验证通过,如有问题请向用户确认。
-
3. 实现 Pydantic 模型和纯函数核心逻辑
-
3.1 创建 Pydantic 模型
apps/backend/app/schemas/xcx_tasks.py- 定义
TaskListItem(含 member_name、member_phone、rs_score、heart_icon) - 定义
AbandonRequest(reason 必填,min_length=1) - Requirements: 8.1, 8.2, 8.4, 8.7
- 定义
-
3.2 创建 Pydantic 模型
apps/backend/app/schemas/xcx_notes.py- 定义
NoteCreateRequest(含 target_type、target_id、content、task_id、rating_service_willingness、rating_revisit_likelihood,评分 ge=1 le=5) - 定义
NoteOut(含 type、content、评分、ai_score、ai_analysis) - Requirements: 9.1, 9.8
- 定义
-
3.3 创建任务生成器核心纯函数
apps/backend/app/services/task_generator.py- 定义
TaskPriority枚举、TASK_TYPE_PRIORITY映射 - 定义
IndexData数据类 - 实现
determine_task_type(index_data)纯函数:根据 WBI/NCI/RS 指数确定任务类型 - 实现
should_replace_task(existing_type, new_type)纯函数:判断是否应替换现有任务 - 实现
compute_heart_icon(rs_score)纯函数:根据 RS 指数计算爱心 icon 档位 - Requirements: 3.1-3.5, 3.8, 8.2
- 定义
-
3.4 编写任务类型确定正确性属性测试
- Property 1: 任务类型确定正确性
- 生成随机 WBI/NCI/RS 值(Decimal, 0-10, 2 位小数),验证
determine_task_type()返回值符合优先级规则 - Validates: Requirements 3.1, 3.2, 3.3, 3.5
-
3.5 编写星星评分范围约束属性测试
- Property 9: 星星评分范围约束
- 生成随机整数(-100 到 100),验证 Pydantic 模型对 1-5 范围外的值拒绝(ValidationError)
- Validates: Requirements 9.8, 14.5
-
3.6 编写爱心 icon 档位计算属性测试
- Property 11: 爱心 icon 档位计算
- 生成随机 RS 值(Decimal, 0-10, 1 位小数),验证
compute_heart_icon()返回正确 icon - Validates: Requirements 8.2
-
-
4. 实现触发器调度框架
-
4.1 创建
apps/backend/app/services/trigger_scheduler.py- 实现
_JOB_REGISTRY注册表和register_job(job_type, handler)函数 - 实现
fire_event(event_name, payload)方法:查找 event 类型触发器并执行 - 实现
check_scheduled_jobs()方法:检查 cron/interval 到期 job 并执行 - 实现
_calculate_next_run(trigger_condition, trigger_config)方法:计算下次运行时间 - 每个 job 独立事务,失败不影响其他触发器
- Requirements: 10.1-10.7
- 实现
-
4.2 编写触发器 next_run_at 计算属性测试
- Property 12: 触发器 next_run_at 计算
- 生成随机 cron/interval 配置和当前时间,验证 cron 类型 next_run_at > 当前时间,interval 类型 next_run_at = 当前时间 + interval_seconds
- Validates: Requirements 10.1, 10.2
-
-
5. 实现任务生成器完整流程
-
5.1 实现
TaskGenerator.run()主流程- 通过
auth.user_assistant_binding获取所有已绑定助教 - 对每个助教,通过 FDW 读取 WBI/NCI/RS 指数(
SET LOCAL app.current_site_id) - 调用
determine_task_type()确定任务类型 - 检查已存在的 active 任务:相同 task_type → 跳过;不同 task_type → 关闭旧任务 + 创建新任务 + 记录 history
- 处理
follow_up_visit的 48 小时滞留机制(expires_at 填充) - 更新
trigger_jobs时间戳 - Requirements: 3.1-3.10, 4.1-4.5, 5.1-5.4
- 通过
-
5.2 编写活跃任务唯一性不变量属性测试
- Property 2: 活跃任务唯一性不变量
- 生成随机 (site_id, assistant_id, member_id, task_type) 组合,模拟插入操作,验证 active 任务最多一条
- Validates: Requirements 1.5, 3.6, 14.1
-
5.3 编写任务类型变更状态机属性测试
- Property 3: 任务类型变更状态机
- 生成随机现有任务 + 新任务类型,执行变更,验证旧任务 inactive + 新任务 active + history 记录
- Validates: Requirements 3.7, 5.1, 5.4, 14.2
-
5.4 编写 48 小时滞留机制属性测试
- Property 4: 48 小时滞留机制
- 生成随机 follow_up_visit 任务 + 时间偏移,验证 expires_at 填充和过期逻辑
- Validates: Requirements 4.1, 4.2, 4.3, 4.4, 14.3
-
-
6. 检查点 - 确保任务生成器测试通过
- 运行属性测试:
cd C:\NeoZQYY && pytest tests/test_core_business_properties.py -v -k "property_1 or property_2 or property_3 or property_4" - 确保所有属性测试通过,如有问题请向用户确认。
- 运行属性测试:
-
7. 实现任务管理服务
-
7.1 创建
apps/backend/app/services/task_manager.py- 实现
get_task_list(user_id, site_id)异步方法:查询活跃任务 + FDW 读取客户信息和 RS 指数 + 爱心 icon 计算 + 排序 - 实现
pin_task(task_id, user_id, site_id)异步方法:验证归属 + 设置 is_pinned=TRUE + 记录 history - 实现
unpin_task(task_id, user_id, site_id)异步方法:验证归属 + 设置 is_pinned=FALSE - 实现
abandon_task(task_id, user_id, site_id, reason)异步方法:验证 reason 非空 + 设置 abandoned + 记录 history - 实现
cancel_abandon(task_id, user_id, site_id)异步方法:恢复 active + 清空 abandon_reason + 记录 history - 实现
_record_history()内部方法 - Requirements: 8.1-8.8
- 实现
-
7.2 编写放弃与取消放弃往返属性测试
- Property 5: 放弃与取消放弃往返
- 生成随机 active 任务 + 非空放弃原因,执行放弃→取消放弃,验证状态恢复;空原因应返回 422
- Validates: Requirements 8.4, 8.6, 8.7, 14.4
-
7.3 编写任务列表排序正确性属性测试
- Property 10: 任务列表排序正确性
- 生成随机任务列表(不同 is_pinned/priority_score/created_at),验证排序为 is_pinned DESC, priority_score DESC, created_at ASC
- Validates: Requirements 8.1
-
7.4 编写状态变更历史完整性属性测试
- Property 15: 状态变更历史完整性
- 生成随机状态变更操作序列(置顶/放弃/取消放弃),验证 history 记录数量和内容正确
- Validates: Requirements 5.4, 8.3
-
-
8. 实现有效期轮询器
- 8.1 创建
apps/backend/app/services/task_expiry.py- 实现
run()方法:查询 expires_at 不为 NULL 且已过期的 active 任务,标记为 inactive,记录 history - Requirements: 4.3, 4.5
- 实现
- 8.1 创建
-
9. 实现召回完成检测器
-
9.1 创建
apps/backend/app/services/recall_detector.py- 实现
run(payload)方法:通过 FDW 读取新增服务记录,匹配 active 任务标记 completed,记录 completed_at 和 completed_task_type 快照,触发recall_completed事件 - Requirements: 6.1-6.5
- 实现
-
9.2 编写召回完成检测与类型快照属性测试
- Property 6: 召回完成检测与类型快照
- 生成随机 active 任务 + 服务记录,执行完成检测,验证 completed_task_type 记录了完成时的 task_type 快照
- Validates: Requirements 6.2, 6.3, 14.6
-
-
10. 检查点 - 确保任务管理和召回检测测试通过
- 运行属性测试:
cd C:\NeoZQYY && pytest tests/test_core_business_properties.py -v -k "property_5 or property_6 or property_10 or property_15" - 确保所有属性测试通过,如有问题请向用户确认。
- 运行属性测试:
-
[-] 11. 实现备注系统
-
11.1 创建备注服务
apps/backend/app/services/note_service.py- 实现
create_note()异步方法:验证评分范围 + 确定 note type(关联 follow_up_visit 任务 → follow_up,否则 normal)+ INSERT + 触发 AI 应用 6 接口(占位)+ 若 ai_score >= 6 标记任务 completed - 实现
get_notes()异步方法:按 created_at DESC 排序,包含评分和 AI 评分 - 实现
delete_note()异步方法:验证归属后硬删除 - Requirements: 9.1-9.9
- 实现
-
11.2 创建备注回溯重分类器
apps/backend/app/services/note_reclassifier.py- 实现
run(payload)方法:查找 service_time 之后的第一条 normal 备注 → 更新为 follow_up → 触发 AI 应用 6 接口(占位)→ 根据 ai_score 生成 follow_up_visit 任务 - 实现
ai_analyze_note(note_id)占位函数(返回 None,P5 实现后替换) - Requirements: 7.1-7.5
- 实现
-
11.3 编写备注回溯重分类属性测试
- Property 7: 备注回溯重分类
- 生成随机备注列表 + service_time,执行回溯,验证符合条件的 normal 备注 type 变为 follow_up
- Validates: Requirements 7.1, 7.2, 14.7
-
11.4 编写备注类型自动设置属性测试
- Property 8: 备注类型自动设置
- 生成随机 task_type + 备注创建,验证关联 follow_up_visit → type=follow_up,其他 → type=normal
- Validates: Requirements 9.2, 9.3
-
11.5 编写 AI 评分驱动的任务完成判定属性测试
- Property 14: AI 评分驱动的任务完成判定
- 生成随机 ai_score + 任务状态,验证 ai_score >= 6 且 active → completed,ai_score < 6 → 保持 active
- Validates: Requirements 7.4, 7.5, 9.5
-
-
12. 实现 API 路由层
-
12.1 创建小程序任务路由
apps/backend/app/routers/xcx_tasks.py- 实现
GET /api/xcx/tasks:获取任务列表(require_approved) - 实现
POST /api/xcx/tasks/{id}/pin:置顶任务 - 实现
POST /api/xcx/tasks/{id}/unpin:取消置顶 - 实现
POST /api/xcx/tasks/{id}/abandon:放弃任务(AbandonRequest 校验) - 实现
POST /api/xcx/tasks/{id}/cancel-abandon:取消放弃 - Requirements: 8.1-8.8
- 实现
-
12.2 创建小程序备注路由
apps/backend/app/routers/xcx_notes.py- 实现
POST /api/xcx/notes:创建备注(NoteCreateRequest 校验) - 实现
GET /api/xcx/notes:查询备注列表(query: target_type, target_id) - 实现
DELETE /api/xcx/notes/{id}:删除备注 - Requirements: 9.1-9.9
- 实现
-
12.3 在
apps/backend/app/main.py中注册新路由- 注册
xcx_tasks和xcx_notes路由 - 验证无路由冲突
- Requirements: 全部
- 注册
-
12.4 注册触发器 job handler
- 在应用启动时调用
register_job()注册task_generator、task_expiry_check、recall_completion_check、note_reclassify_backfill四个 handler - Requirements: 10.1-10.6
- 在应用启动时调用
-
-
13. 检查点 - 确保所有测试通过
- 运行属性测试:
cd C:\NeoZQYY && pytest tests/test_core_business_properties.py -v - 26/26 全部通过(16.81s)
- 运行属性测试:
-
14. 最终检查点 - 全量验证
- 运行全部属性测试:26/26 通过(16.81s)
- 验证迁移脚本幂等性:Property 13(3 个测试)通过
- 验证种子数据完整性:4 条触发器配置全部存在
- 验证表结构:coach_tasks / coach_task_history / notes / trigger_jobs 全部存在
- 验证部分唯一索引:idx_coach_tasks_site_assistant_member_type 存在
备注
- 标记
*的子任务为可选(属性测试),可跳过以加速 MVP - 每个任务引用了具体的需求编号,确保可追溯
- 检查点确保增量验证
- 属性测试验证通用正确性属性(hypothesis,最少 200 次迭代)
- 所有数据库操作在测试库
test_zqyy_app进行 - 迁移脚本放在
db/zqyy_app/migrations/目录 - 属性测试放在
tests/test_core_business_properties.py(Monorepo 级) - AI 应用 6 接口为占位实现(返回 None),由 P5 AI 集成层替换
- 维客线索功能由独立模块
routers/member_retention_clue.py处理,不在本 SPEC 范围内 - FDW 查询需在事务中
SET LOCAL app.current_site_id设置 RLS 隔离