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