Files
Neo-ZQYY/docs/database/BD_Manual_biz_tables.md
Neo 70324d8542 chore: 文档与 IDE 配置整理
- .kiro/specs/ → docs/specs/(41 个历史需求 spec 迁移,移除 .config.kiro)
- CLAUDE.md 三层拆分:根文件精简 + apps/backend/CLAUDE.md + .claude/commands/
- 新增 /spec-close、/pre-change 两个工作流命令
- DDL 基线刷新(从测试库重新导出 11 个文件,dws 35→38 表,biz 18→21 表)
- BD_Manual → BD_manual 命名统一(48 个文件)
- 修复 3 处文档与数据库不一致(auth.users.status 默认值、scheduled_tasks 字段、RLS 视图数)
- 新增 BD_manual_public_rbac_tables.md(public schema 8 张 RBAC/工作流表)
- 合并 biz.trigger_jobs 文档(10→12 字段,归档独立文档)
- docs/database/README.md 索引更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 00:02:37 +08:00

21 KiB
Raw Permalink Blame History

BD_Manualbiz Schema 业务表(助教任务系统 + 备注系统 + 触发器调度)

目标库:test_zqyy_app(通过 APP_DB_DSN 连接) 迁移脚本:

  • db/zqyy_app/migrations/2026-02-27__p4_create_biz_tables.sql(建表)
  • db/zqyy_app/migrations/2026-02-27__p4_seed_trigger_jobs.sql(种子数据)
  • db/zqyy_app/migrations/2026-03-24__p17_task_engine_ownership.sqlP17 客户归属与转移)
  • db/zqyy_app/migrations/2026-03-24__p18_task_engine_dashboard.sqlP18 运营看板字段扩展) 关联 SPEC04-miniapp-core-businessP4P17-assistant-ownership-task-engineP17P18-admin-task-engine-dashboardP18

1. 变更说明

新增表6 张)

# 表名 用途 字段数 来源
1 biz.coach_tasks 助教任务表:存储任务分配、状态、有效期、置顶、放弃原因、转移追踪等 18 P4+P17
2 biz.coach_task_history 任务变更历史表:记录任务关闭/新建/置顶/放弃/转移的追溯链 9 P4
3 biz.notes 统一备注表:通过 type 字段区分普通备注/回访备注/放弃原因,含星星评分 15 P4
4 biz.trigger_jobs 触发器配置表:存储 cron/interval/event 三种触发方式的配置与执行状态 12 P4+P18+P23
5 biz.cfg_task_generator_params 任务引擎参数配置表:支持全局默认 + 门店级覆盖 7 P17+P18
6 biz.coach_task_transfer_log 客户转移日志表:记录每次转移的完整上下文 11 P17

表字段明细

biz.coach_tasks18 字段)

字段 类型 约束 说明
id BIGSERIAL PK 自增主键
site_id BIGINT NOT NULL 门店 ID多门店隔离
assistant_id BIGINT NOT NULL 助教 ID
member_id BIGINT NOT NULL 客户 ID
task_type VARCHAR(50) NOT NULL 任务类型:high_priority_recall / priority_recall / follow_up_visit / relationship_building
status VARCHAR(20) NOT NULL DEFAULT 'active' 状态:active / inactive / completed / abandoned / transferredP17/ pending_reviewP17
priority_score NUMERIC(5,2) 可空 优先级分数,取 max(WBI, NCI) 快照
expires_at TIMESTAMPTZ 可空 有效期时间戳NULL 表示无限期
is_pinned BOOLEAN DEFAULT FALSE 是否置顶
abandon_reason TEXT 可空 放弃原因(放弃时必填)
completed_at TIMESTAMPTZ 可空 完成时间
completed_task_type VARCHAR(50) 可空 完成时的任务类型快照
parent_task_id BIGINT FK → biz.coach_tasks(id),可空 父任务 ID自引用
transfer_count INTEGER NOT NULL DEFAULT 0 该客户在此任务链上的累计转移次数P17 新增)
transferred_from BIGINT FK → biz.coach_tasks(id),可空 转移来源任务 IDP17 新增)
transferred_at TIMESTAMPTZ 可空 转移发生时间P17 新增)
created_at TIMESTAMPTZ DEFAULT NOW() 创建时间
updated_at TIMESTAMPTZ DEFAULT NOW() 更新时间

biz.coach_task_history9 字段)

字段 类型 约束 说明
id BIGSERIAL PK 自增主键
task_id BIGINT NOT NULL, FK → biz.coach_tasks(id) 关联任务
action VARCHAR(50) NOT NULL 操作类型:created / type_changed / type_change_close / pinned / abandoned / cancel_abandon / expired / completed / expires_at_filled / transferred_outP17/ transferred_inP17
old_status VARCHAR(20) 可空 变更前状态
new_status VARCHAR(20) 可空 变更后状态
old_task_type VARCHAR(50) 可空 变更前任务类型
new_task_type VARCHAR(50) 可空 变更后任务类型
detail JSONB 可空 附加详情(如放弃原因等)
created_at TIMESTAMPTZ DEFAULT NOW() 记录时间

biz.notes15 字段)

字段 类型 约束 说明
id BIGSERIAL PK 自增主键
site_id BIGINT NOT NULL 门店 ID
user_id INTEGER NOT NULL 小程序用户 ID
target_type VARCHAR(50) NOT NULL 目标类型(如 member
target_id BIGINT NOT NULL 目标 ID如 member_id
type VARCHAR(20) NOT NULL DEFAULT 'normal' 备注类型:normal / follow_up / abandon_reason
content TEXT NOT NULL 备注内容
rating_service_willingness SMALLINT CHECK (1-5),可空 再次服务意愿评分
rating_revisit_likelihood SMALLINT CHECK (1-5),可空 再来店可能性评分
task_id BIGINT FK → biz.coach_tasks(id),可空 关联任务
ai_score SMALLINT 可空 AI 应用 6 评分P5 实现)
ai_analysis TEXT 可空 AI 分析结果P5 实现)
created_at TIMESTAMPTZ DEFAULT NOW() 创建时间
updated_at TIMESTAMPTZ DEFAULT NOW() 更新时间
score SMALLINT CHECK (1-5),可空 备注星星评分,助教创建备注时可选填写,不参与 AI 分析RNS1.1 新增)

biz.trigger_jobs12 字段)

字段 类型 约束 说明
id SERIAL PK 自增主键
job_type VARCHAR(100) NOT NULL 任务类型标识,映射到 Python handler_JOB_REGISTRY 注册键)
job_name VARCHAR(100) NOT NULL, UNIQUE 任务名称(唯一标识,如 task_generator
trigger_condition VARCHAR(20) NOT NULL 触发方式:cron / interval / event
trigger_config JSONB NOT NULL 触发配置cron 表达式 / 间隔秒数 / 事件名)
last_run_at TIMESTAMPTZ 可空 上次运行时间
next_run_at TIMESTAMPTZ 可空 下次运行时间event 类型为 NULL
status VARCHAR(20) NOT NULL DEFAULT 'enabled' 状态:enabled / disabled
description TEXT 可空 任务中文描述管理后台页面展示P23 新增)
last_error TEXT 可空 最后一次执行异常的错误信息,成功后清空为 NULLP23 新增)
last_stats JSONB 可空 最近一次执行的统计结果 JSON{"created":5,"replaced":2,"skipped":10,"transferred":1}P18 新增)
created_at TIMESTAMPTZ DEFAULT NOW() 创建时间

biz.cfg_task_generator_params7 字段P17+P18

字段 类型 约束 说明
id BIGSERIAL PK 自增主键
site_id BIGINT 可空 NULL=全局默认非NULL=门店级覆盖
param_key VARCHAR(64) NOT NULL 参数键名
param_value NUMERIC NOT NULL 参数值
description TEXT 可空 参数说明
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() 更新时间
updated_by BIGINT 可空 最近修改人 user_id用于审计追溯P18 新增)

继承链:代码默认 → 全局默认site_id IS NULL→ 门店覆盖site_id = ?

biz.coach_task_transfer_log11 字段P17 新增)

字段 类型 约束 说明
id BIGSERIAL PK 自增主键
site_id BIGINT NOT NULL 门店 ID
member_id BIGINT NOT NULL 客户 ID
from_assistant_id BIGINT NOT NULL 原助教 ID
to_assistant_id BIGINT NOT NULL 新助教 ID
from_task_id BIGINT NOT NULL, FK → biz.coach_tasks(id) 原任务 ID
to_task_id BIGINT FK → biz.coach_tasks(id),可空 新任务 ID
transfer_reason TEXT 可空 转移原因描述
guard_checks JSONB 可空 三重保护检查结果快照
transfer_score NUMERIC 可空 转移候选得分
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() 创建时间

约束与索引

约束/索引名 类型 说明
coach_tasks idx_coach_tasks_site_assistant_member_type UNIQUE INDEX (partial) (site_id, assistant_id, member_id, task_type) WHERE status = 'active',保证同一组合下活跃任务最多一条
coach_tasks idx_coach_tasks_assistant_status INDEX (site_id, assistant_id, status),助教任务列表查询加速
coach_tasks FK parent_task_id FK biz.coach_tasks(id),自引用
coach_tasks FK fk_coach_tasks_transferred_from FK biz.coach_tasks(id)转移来源任务P17 新增)
coach_task_history FK task_id FK biz.coach_tasks(id)
notes idx_notes_target INDEX (site_id, target_type, target_id),按目标查询备注加速
notes CHECK rating_service_willingness CHECK BETWEEN 1 AND 5
notes CHECK rating_revisit_likelihood CHECK BETWEEN 1 AND 5
notes CHECK score CHECK score IS NULL OR (score >= 1 AND score <= 5)RNS1.1 新增)
notes FK task_id FK biz.coach_tasks(id)
trigger_jobs UNIQUE job_name UNIQUE 触发器名称唯一
cfg_task_generator_params UNIQUE (site_id, param_key) UNIQUE 全局+门店级参数唯一约束P17 新增)
coach_task_transfer_log FK from_task_id FK biz.coach_tasks(id)P17 新增)
coach_task_transfer_log FK to_task_id FK biz.coach_tasks(id)P17 新增)
coach_task_transfer_log idx_transfer_log_site_created INDEX (site_id, created_at DESC)P17 新增)
coach_task_transfer_log idx_transfer_log_member INDEX (member_id, created_at DESC)P17 新增)

P17 种子数据13 条任务引擎参数)

param_key param_value description
high_priority_recall_threshold 7.0 max(WBI,NCI) 超过此值生成高优先召回
priority_recall_threshold 5.0 max(WBI,NCI) 超过此值生成优先召回
rs_min_for_relationship 1.0 RS ≤ 此值不生成关系构建
rs_max_for_relationship 6.0 RS ≥ 此值不生成关系构建
consecutive_recall_fail_cycles 3 连续失败多少轮触发客户转移
min_wbi_for_transfer 5.0 WBI 低于此值不触发转移
guard_assistant_coverage_ratio 0.5 绑定率低于此值禁用转移
guard_new_assistant_days 10 新助教入驻保护天数
transfer_score_w_rs 0.5 转移候选排序RS 权重
transfer_score_w_ms 0.3 转移候选排序MS 权重
transfer_score_w_ml 0.2 转移候选排序ML 权重
max_transfer_count 2 单客户最大累计转移次数
follow_up_visit_retention_hours 48 回访任务最低保留时长(小时)

所有参数 site_id IS NULL(全局默认),门店可通过插入 site_id = ? 的行覆盖。

种子数据4 条触发器配置)

job_name job_type trigger_condition trigger_config next_run_at 说明
task_generator task_generator cron {"cron_expression": "0 4 * * *"} 次日 04:00 每日凌晨 4:00 运行任务生成器
task_expiry_check task_expiry_check interval {"interval_seconds": 3600} NOW() + 1h 每小时检查过期任务
recall_completion_check recall_completion_check event {"event_name": "etl_data_updated"} NULL ETL 数据更新后触发召回完成检测
note_reclassify_backfill note_reclassify_backfill event {"event_name": "recall_completed"} NULL 召回完成后触发备注回溯重分类

2. 兼容性影响

组件 影响
ETL 任务 无直接影响。biz Schema 表不参与 ETL 流程,但任务生成器通过 FDW 只读访问 ETL 库的 WBI/NCI/RS 指数数据
后端 API 直接依赖。FastAPI 后端将基于这些表实现任务 CRUD/api/xcx/tasks)、备注 CRUD/api/xcx/notes、触发器调度等功能。P17 新增:task_generator.py 完全重写,入口改为 OS 归属对;fdw_queries.py 新增 4 个批量查询方法
小程序 间接依赖。小程序通过后端 API 间接使用任务列表、备注功能
管理后台 P18 已实施。admin_task_engine router 提供 9 个端点(转移日志分页+历史、待审核任务分页+重新分配+关闭、参数管理 CRUD前端 3 个页面TransferLog/PendingReview/TaskEngineConfig通过 taskEngine.ts API 层调用
FDW 配置 无影响。fdw_etl Schema 独立于 biz,任务生成器和召回检测器通过 FDW 只读查询 ETL 库
auth Schema 间接依赖。P17 仍通过 auth.user_assistant_binding 获取 site_ids 和助教绑定信息(转移保护检查)
public Schema 无影响。member_retention_clue 表独立于本次变更
现有 biz Schema 兼容。coach_tasks 新增 3 字段均有默认值(transfer_count DEFAULT 0,其余可空),不影响现有查询。新增 transferred/pending_review 状态值7 个下游模块均使用显式 status 过滤,不会误匹配

2.1 RNS1.3 看板接口引用说明2026-03-20 补充)

RNS1.3三看板接口BOARD-1 助教看板的任务维度查询引用了 biz.coach_tasks(无 schema 变更,仅新增读取路径):

引用接口 用途
biz.coach_tasks BOARD-1 _query_coach_tasks() site_id + assistant_id + 日期范围查询任务完成数,按 task_type 分类统计 recall(召回类:high_priority_recall / priority_recall)和 callback(回访类:follow_up_visit / relationship_building),筛选条件 status = 'completed' + completed_at BETWEEN start_date AND end_date

查询模式:

SELECT assistant_id, task_type, COUNT(*) AS cnt
FROM biz.coach_tasks
WHERE site_id = :site_id
  AND assistant_id = ANY(:assistant_ids)
  AND status = 'completed'
  AND completed_at BETWEEN :start_date AND :end_date
GROUP BY assistant_id, task_type

该查询走 idx_coach_tasks_assistant_status 索引(site_id, assistant_id, status),无需新增索引。


2.2 RNS1.2 接口引用说明2026-03-18 补充)

RNS1.2(客户与助教接口)新增 3 个端点,引用了以下 biz/public 表(无 schema 变更,仅新增读取路径):

引用接口 用途
biz.coach_tasks CUST-1 coachTasks 模块、COACH-1 visibleTasks/hiddenTasks/abandonedTasks/tasksCompleted 查询客户关联的助教任务(按 member_id);查询助教任务分组(按 assistant_idstatus 分组);统计当月完成任务数
biz.notes CUST-1 notes 模块、COACH-1 notes/任务备注 查询客户备注(target_type='member',最多 20 条);查询助教相关备注(最多 20 条);查询任务关联备注(task_id 关联)
biz.ai_cache CUST-1 aiInsight 模块 查询 AI 分析缓存(cache_type='app4_analysis'target_id=customerId),解析 cache_value JSON 生成洞察摘要和策略建议
public.member_retention_clue CUST-1 retentionClues 模块 查询维客线索(按 created_at 倒序),格式与 TASK-2 一致

以上均为只读查询,不涉及表结构变更。biz.ai_cache 表由 P5AI 集成)创建,public.member_retention_clue 表由独立迁移创建。


3. 回滚策略

P4 回滚(原始 4 张表)

按逆序 DROP TABLE IF EXISTS CASCADE(迁移脚本末尾已包含注释形式的回滚语句):

-- 先删除种子数据(如需保留表结构)
DELETE FROM biz.trigger_jobs
WHERE job_name IN (
    'task_generator',
    'task_expiry_check',
    'recall_completion_check',
    'note_reclassify_backfill'
);

-- 删除索引
DROP INDEX IF EXISTS biz.idx_notes_target;
DROP INDEX IF EXISTS biz.idx_coach_tasks_assistant_status;
DROP INDEX IF EXISTS biz.idx_coach_tasks_site_assistant_member_type;

-- 删除表按逆序CASCADE 处理外键依赖)
DROP TABLE IF EXISTS biz.trigger_jobs CASCADE;
DROP TABLE IF EXISTS biz.notes CASCADE;
DROP TABLE IF EXISTS biz.coach_task_history CASCADE;
DROP TABLE IF EXISTS biz.coach_tasks CASCADE;

P17 回滚(增量变更)

-- 1. 删除 P17 种子数据
DELETE FROM biz.cfg_task_generator_params WHERE site_id IS NULL;

-- 2. 删除 P17 新增表
DROP TABLE IF EXISTS biz.coach_task_transfer_log;
DROP TABLE IF EXISTS biz.cfg_task_generator_params;

-- 3. 删除 P17 新增字段
ALTER TABLE biz.coach_tasks DROP COLUMN IF EXISTS transfer_count;
ALTER TABLE biz.coach_tasks DROP COLUMN IF EXISTS transferred_from;
ALTER TABLE biz.coach_tasks DROP COLUMN IF EXISTS transferred_at;

-- 注意enum 值transferred/pending_review一旦添加无法直接删除需重建类型

P18 回滚(字段扩展)

-- 删除 P18 新增字段
ALTER TABLE biz.trigger_jobs DROP COLUMN IF EXISTS last_stats;
ALTER TABLE biz.cfg_task_generator_params DROP COLUMN IF EXISTS updated_by;

注意:

  • CASCADE 会级联删除依赖对象(外键引用的子表数据)
  • 如果表中已有业务数据,需先备份再执行回滚
  • 回滚不会删除 biz Schema 本身(由 P1 创建,其他表可能依赖)

4. 验证 SQL

-- 1. 验证 biz Schema 下 6 张业务表全部存在
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'biz'
  AND table_name IN ('coach_tasks', 'coach_task_history', 'notes', 'trigger_jobs',
                     'cfg_task_generator_params', 'coach_task_transfer_log')
ORDER BY table_name;
-- 预期:返回 6 行

-- 2. 验证 coach_tasks 表字段数量P4 原 15 + P17 新增 3 = 18
SELECT column_name, data_type, is_nullable, column_default
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'coach_tasks'
ORDER BY ordinal_position;
-- 预期:返回 18 行,包含 transfer_count/transferred_from/transferred_at

-- 3. 验证 P17 新增字段的默认值和约束
SELECT column_name, data_type, is_nullable, column_default
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'coach_tasks'
  AND column_name IN ('transfer_count', 'transferred_from', 'transferred_at');
-- 预期transfer_count: integer, NOT NULL, DEFAULT 0
--       transferred_from: bigint, YES (nullable)
--       transferred_at: timestamp with time zone, YES (nullable)

-- 4. 验证 cfg_task_generator_params 表结构
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'cfg_task_generator_params'
ORDER BY ordinal_position;
-- 预期6 行id, site_id, param_key, param_value, description, updated_at

-- 5. 验证 P17 种子数据13 条全局默认参数)
SELECT param_key, param_value, description
FROM biz.cfg_task_generator_params
WHERE site_id IS NULL
ORDER BY param_key;
-- 预期:返回 13 行

-- 6. 验证 coach_task_transfer_log 表结构
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'coach_task_transfer_log'
ORDER BY ordinal_position;
-- 预期11 行id, site_id, member_id, from_assistant_id, to_assistant_id,
--       from_task_id, to_task_id, transfer_reason, guard_checks, transfer_score, created_at

-- 7. 验证 P17 新增索引
SELECT indexname
FROM pg_indexes
WHERE schemaname = 'biz'
  AND indexname IN ('idx_transfer_log_site_created', 'idx_transfer_log_member')
ORDER BY indexname;
-- 预期:返回 2 行

-- 8. 验证 transferred_from 外键约束
SELECT conname
FROM pg_constraint
WHERE conrelid = 'biz.coach_tasks'::regclass
  AND conname = 'fk_coach_tasks_transferred_from';
-- 预期:返回 1 行

-- 9. 验证部分唯一索引存在P4 原有)
SELECT indexname, indexdef
FROM pg_indexes
WHERE schemaname = 'biz' AND indexname = 'idx_coach_tasks_site_assistant_member_type';
-- 预期:返回 1 行indexdef 包含 "WHERE ((status)::text = 'active'::text)"

-- 10. 验证种子数据4 条触发器配置P4 原有)
SELECT job_name, job_type, trigger_condition
FROM biz.trigger_jobs
WHERE job_name IN ('task_generator', 'task_expiry_check', 'recall_completion_check', 'note_reclassify_backfill')
ORDER BY job_name;
-- 预期:返回 4 行

-- 11. 验证 P18 新增字段trigger_jobs.last_stats
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'trigger_jobs' AND column_name = 'last_stats';
-- 预期:返回 1 行data_type = 'jsonb'is_nullable = 'YES'

-- 12. 验证 P18 新增字段cfg_task_generator_params.updated_by
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = 'biz' AND table_name = 'cfg_task_generator_params' AND column_name = 'updated_by';
-- 预期:返回 1 行data_type = 'bigint'is_nullable = 'YES'