微信小程序页面迁移校验之前 P5任务处理之前

This commit is contained in:
Neo
2026-03-09 01:19:21 +08:00
parent 263bf96035
commit 6e20987d2f
1112 changed files with 153824 additions and 219694 deletions

View File

@@ -0,0 +1,99 @@
-- =============================================================================
-- 迁移member_birthday_manual → member_retention_clue维客线索重构
-- 日期2026-02-26
-- 目标库zqyy_app / test_zqyy_app
-- 说明:
-- 1. 删除 member_birthday_manual 表(生日不再单独记录,归入维客线索"客户基础信息"大类)
-- 2. 新建 member_retention_clue 表(维客线索:大类 + 摘要 + 详情)
-- 影响:
-- - 后端 API/api/member-birthday 废弃,替换为 /api/retention-clue
-- - ETL DWS移除 FDW 读取 member_birthday_manual 的逻辑
-- - FDWfdw_app.member_birthday_manual 外部表需在 ETL 库侧同步删除
-- 幂等DROP IF EXISTS / CREATE IF NOT EXISTS可重复执行
-- =============================================================================
BEGIN;
-- ============================================================
-- 1. 删除旧表 member_birthday_manual
-- ============================================================
DROP TABLE IF EXISTS member_birthday_manual CASCADE;
-- ============================================================
-- 2. 创建 member_retention_clue 表
-- ============================================================
CREATE TABLE IF NOT EXISTS member_retention_clue (
id BIGSERIAL PRIMARY KEY,
member_id BIGINT NOT NULL,
category VARCHAR(20) NOT NULL
CONSTRAINT chk_retention_clue_category CHECK (
category IN ('客户基础信息', '消费习惯', '玩法偏好', '促销偏好', '社交关系', '重要反馈')
),
summary VARCHAR(200) NOT NULL,
detail TEXT,
recorded_by_assistant_id BIGINT,
recorded_by_name VARCHAR(50),
recorded_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
site_id BIGINT NOT NULL
);
COMMENT ON TABLE member_retention_clue
IS '维客线索:助教为会员记录的销售/维护线索(大类 + 摘要 + 详情)';
COMMENT ON COLUMN member_retention_clue.category
IS '线索大类枚举:客户基础信息、消费习惯、玩法偏好、促销偏好、社交关系、重要反馈';
COMMENT ON COLUMN member_retention_clue.summary
IS '摘要:重点信息';
COMMENT ON COLUMN member_retention_clue.detail
IS '详情:分析及扩展说明,可为空';
-- ============================================================
-- 3. 创建索引
-- ============================================================
CREATE INDEX IF NOT EXISTS idx_retention_clue_member
ON member_retention_clue (member_id);
CREATE INDEX IF NOT EXISTS idx_retention_clue_site
ON member_retention_clue (site_id);
CREATE INDEX IF NOT EXISTS idx_retention_clue_category
ON member_retention_clue (member_id, category);
COMMIT;
-- ============================================================
-- 回滚(需手动执行,不在事务内)
-- ============================================================
-- BEGIN;
-- DROP TABLE IF EXISTS member_retention_clue CASCADE;
-- -- 如需恢复旧表,执行 2026-02-22__C2_member_birthday_manual.sql
-- COMMIT;
-- ============================================================
-- 验证 SQL
-- ============================================================
-- 1. 确认旧表已删除
-- SELECT table_name FROM information_schema.tables
-- WHERE table_schema = 'public' AND table_name = 'member_birthday_manual';
-- 预期0 行
-- 2. 确认新表存在
-- SELECT table_name FROM information_schema.tables
-- WHERE table_schema = 'public' AND table_name = 'member_retention_clue';
-- 预期1 行
-- 3. 确认列结构完整9 列)
-- SELECT column_name, data_type, is_nullable
-- FROM information_schema.columns
-- WHERE table_schema = 'public' AND table_name = 'member_retention_clue'
-- ORDER BY ordinal_position;
-- 预期id, member_id, category, summary, detail,
-- recorded_by_assistant_id, recorded_by_name, recorded_at, site_id
-- 4. 确认 CHECK 约束存在
-- SELECT conname, consrc FROM pg_constraint
-- WHERE conrelid = 'member_retention_clue'::regclass AND contype = 'c';
-- 预期1 行chk_retention_clue_category
-- 5. 确认索引存在
-- SELECT indexname FROM pg_indexes
-- WHERE tablename = 'member_retention_clue';
-- 预期3 行idx_retention_clue_member, idx_retention_clue_site, idx_retention_clue_category
-- + 1 行主键索引

View File

@@ -0,0 +1,21 @@
-- 迁移:为 auth.users.status 的 CHECK 约束添加 'new' 值
-- 原因:新用户注册后初始状态为 'new'(尚未提交申请),提交申请后变为 'pending'
-- 影响:后端 wx_login 新用户创建、dev_login mock 登录
-- 回滚:见文件末尾
-- 1. 删除旧约束
ALTER TABLE auth.users DROP CONSTRAINT IF EXISTS users_status_check;
-- 2. 添加包含 'new' 的新约束
ALTER TABLE auth.users ADD CONSTRAINT users_status_check
CHECK (status IN ('new', 'pending', 'approved', 'rejected', 'disabled'));
-- 3. 修改默认值:新用户初始状态为 'new'(尚未提交申请)
ALTER TABLE auth.users ALTER COLUMN status SET DEFAULT 'new';
-- ── 回滚 SQL ──
-- ALTER TABLE auth.users ALTER COLUMN status SET DEFAULT 'pending';
-- ALTER TABLE auth.users DROP CONSTRAINT IF EXISTS users_status_check;
-- ALTER TABLE auth.users ADD CONSTRAINT users_status_check
-- CHECK (status IN ('pending', 'approved', 'rejected', 'disabled'));
-- UPDATE auth.users SET status = 'pending' WHERE status = 'new';

View File

@@ -0,0 +1,52 @@
-- =============================================================================
-- 迁移member_retention_clue 新增 source 字段
-- 日期2026-02-27
-- 目标库zqyy_app / test_zqyy_app
-- 说明:
-- 区分维客线索来源manual助教手动/ ai_consumption应用3/ ai_note应用6
-- 影响:
-- - 后端 APIPOST /api/retention-clue 已引用 source 列,本次补齐 DDL
-- - 已有数据自动填充 DEFAULT 'manual'
-- 幂等IF NOT EXISTS 检查列是否存在,可重复执行
-- =============================================================================
BEGIN;
-- 仅在列不存在时添加PostgreSQL 11+ 支持 IF NOT EXISTS
ALTER TABLE member_retention_clue
ADD COLUMN IF NOT EXISTS source VARCHAR(20) NOT NULL DEFAULT 'manual';
COMMENT ON COLUMN member_retention_clue.source
IS '线索来源manual助教手动/ ai_consumption应用3 消费分析)/ ai_note应用6 备注分析)';
COMMIT;
-- ============================================================
-- 回滚(需手动执行)
-- ============================================================
-- BEGIN;
-- ALTER TABLE member_retention_clue DROP COLUMN IF EXISTS source;
-- COMMIT;
-- ============================================================
-- 验证 SQL
-- ============================================================
-- 1. 确认 source 列存在
-- SELECT column_name, data_type, column_default, is_nullable
-- FROM information_schema.columns
-- WHERE table_schema = 'public'
-- AND table_name = 'member_retention_clue'
-- AND column_name = 'source';
-- 预期1 行varchar, 'manual'::character varying, NO
-- 2. 确认已有数据的 source 值
-- SELECT source, COUNT(*) FROM member_retention_clue GROUP BY source;
-- 预期:全部为 'manual'(或空表)
-- 3. 确认列注释
-- SELECT col_description(
-- (SELECT oid FROM pg_class WHERE relname = 'member_retention_clue'),
-- (SELECT ordinal_position FROM information_schema.columns
-- WHERE table_name = 'member_retention_clue' AND column_name = 'source')
-- );
-- 预期:包含 'manual' / 'ai_consumption' / 'ai_note'

View File

@@ -0,0 +1,107 @@
-- =============================================================================
-- 迁移脚本:创建 biz Schema 业务表coach_tasks / coach_task_history / notes / trigger_jobs
-- 日期2026-02-27
-- 目标库test_zqyy_app通过 APP_DB_DSN 连接)
-- 说明:在 biz Schema 下创建助教任务系统和备注系统所需的 4 张业务表,
-- 包含字段定义、约束、CHECK 约束、外键、部分唯一索引和查询索引。
-- 前提biz Schema 已由 2026-02-24__p1_create_auth_biz_schemas.sql 创建
-- 需求1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9
-- =============================================================================
-- 确保 biz Schema 存在(幂等)
CREATE SCHEMA IF NOT EXISTS biz;
-- ---------------------------------------------------------------------------
-- 1. biz.coach_tasks — 助教任务表
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS biz.coach_tasks (
id BIGSERIAL PRIMARY KEY,
site_id BIGINT NOT NULL,
assistant_id BIGINT NOT NULL,
member_id BIGINT NOT NULL,
task_type VARCHAR(50) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'active',
priority_score NUMERIC(5,2),
expires_at TIMESTAMPTZ,
is_pinned BOOLEAN DEFAULT FALSE,
abandon_reason TEXT,
completed_at TIMESTAMPTZ,
completed_task_type VARCHAR(50),
parent_task_id BIGINT REFERENCES biz.coach_tasks(id),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- 部分唯一索引:同一 (site_id, assistant_id, member_id, task_type) 下 active 任务最多一条
CREATE UNIQUE INDEX IF NOT EXISTS idx_coach_tasks_site_assistant_member_type
ON biz.coach_tasks (site_id, assistant_id, member_id, task_type)
WHERE status = 'active';
-- 助教任务列表查询索引
CREATE INDEX IF NOT EXISTS idx_coach_tasks_assistant_status
ON biz.coach_tasks (site_id, assistant_id, status);
-- ---------------------------------------------------------------------------
-- 2. biz.coach_task_history — 任务变更历史表
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS biz.coach_task_history (
id BIGSERIAL PRIMARY KEY,
task_id BIGINT NOT NULL REFERENCES biz.coach_tasks(id),
action VARCHAR(50) NOT NULL,
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()
);
-- ---------------------------------------------------------------------------
-- 3. biz.notes — 统一备注表
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS biz.notes (
id BIGSERIAL PRIMARY KEY,
site_id BIGINT NOT NULL,
user_id INTEGER NOT NULL,
target_type VARCHAR(50) NOT NULL,
target_id BIGINT NOT NULL,
type VARCHAR(20) NOT NULL DEFAULT 'normal',
content TEXT NOT NULL,
rating_service_willingness SMALLINT CHECK (rating_service_willingness BETWEEN 1 AND 5),
rating_revisit_likelihood SMALLINT CHECK (rating_revisit_likelihood BETWEEN 1 AND 5),
task_id BIGINT REFERENCES biz.coach_tasks(id),
ai_score SMALLINT,
ai_analysis TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- 按目标查询备注索引
CREATE INDEX IF NOT EXISTS idx_notes_target
ON biz.notes (site_id, target_type, target_id);
-- ---------------------------------------------------------------------------
-- 4. biz.trigger_jobs — 触发器配置表
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS biz.trigger_jobs (
id SERIAL PRIMARY KEY,
job_type VARCHAR(100) NOT NULL,
job_name VARCHAR(100) NOT NULL UNIQUE,
trigger_condition VARCHAR(20) NOT NULL,
trigger_config JSONB NOT NULL,
last_run_at TIMESTAMPTZ,
next_run_at TIMESTAMPTZ,
status VARCHAR(20) NOT NULL DEFAULT 'enabled',
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- =============================================================================
-- 回滚脚本(按逆序执行)
-- =============================================================================
-- 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;
-- DROP TABLE IF EXISTS biz.trigger_jobs;
-- DROP TABLE IF EXISTS biz.notes;
-- DROP TABLE IF EXISTS biz.coach_task_history;
-- DROP TABLE IF EXISTS biz.coach_tasks;

View File

@@ -0,0 +1,43 @@
-- =============================================================================
-- 迁移脚本:预置触发器配置种子数据
-- 日期2026-02-27
-- 目标库test_zqyy_app通过 APP_DB_DSN 连接)
-- 说明:在 biz.trigger_jobs 表中插入 4 条核心触发器配置,
-- 驱动任务生成、有效期检查、召回完成检测、备注回溯重分类。
-- 前提biz.trigger_jobs 表已由 2026-02-27__p4_create_biz_tables.sql 创建
-- 需求2.1, 2.2, 2.3, 2.4, 2.5
-- =============================================================================
INSERT INTO biz.trigger_jobs (job_type, job_name, trigger_condition, trigger_config, next_run_at)
VALUES
-- 1. task_generator每日凌晨 4:00 运行,基于 WBI/NCI/RS 指数为助教生成任务
('task_generator', 'task_generator', 'cron',
'{"cron_expression": "0 4 * * *"}',
(CURRENT_DATE + 1) + INTERVAL '4 hours'),
-- 2. task_expiry_check每小时运行检查 expires_at 到期的任务并标记 inactive
('task_expiry_check', 'task_expiry_check', 'interval',
'{"interval_seconds": 3600}',
NOW() + INTERVAL '1 hour'),
-- 3. recall_completion_checkETL 数据更新后触发,检测助教服务记录匹配活跃任务
('recall_completion_check', 'recall_completion_check', 'event',
'{"event_name": "etl_data_updated"}',
NULL),
-- 4. note_reclassify_backfill召回完成后触发回溯重分类普通备注为回访备注
('note_reclassify_backfill', 'note_reclassify_backfill', 'event',
'{"event_name": "recall_completed"}',
NULL)
ON CONFLICT (job_name) DO NOTHING;
-- =============================================================================
-- 回滚脚本
-- =============================================================================
-- DELETE FROM biz.trigger_jobs
-- WHERE job_name IN (
-- 'task_generator',
-- 'task_expiry_check',
-- 'recall_completion_check',
-- 'note_reclassify_backfill'
-- );

View File

@@ -0,0 +1,50 @@
-- =============================================================================
-- 迁移auth.site_code_mapping.tenant_id INTEGER → BIGINT
-- 原因:飞球 tenant_id 值域(如 2790683160709957远超 int4 上限(~21 亿)
-- 日期2026-03-03
-- 目标库zqyy_app / test_zqyy_app
-- 注意:该列无外键、无索引依赖,可直接 ALTER
-- =============================================================================
BEGIN;
-- 1. ALTER 列类型
ALTER TABLE auth.site_code_mapping
ALTER COLUMN tenant_id TYPE bigint;
-- 2. 刷新 FDW 外部表ETL 库 tenant_id 变更后需重新导入)
-- 注意:此步骤需在 ETL 库迁移完成后执行
-- 如果 FDW 外部表类型不匹配,需要重新 IMPORT FOREIGN SCHEMA
-- DROP FOREIGN TABLE IF EXISTS fdw_etl.v_dws_assistant_order_contribution;
-- IMPORT FOREIGN SCHEMA app
-- LIMIT TO (v_dws_assistant_order_contribution)
-- FROM SERVER test_etl_feiqiu_server
-- INTO fdw_etl;
COMMIT;
-- =============================================================================
-- 回滚脚本
-- =============================================================================
-- BEGIN;
-- ALTER TABLE auth.site_code_mapping ALTER COLUMN tenant_id TYPE integer;
-- COMMIT;
-- =============================================================================
-- 验证 SQL
-- =============================================================================
-- 1. 确认列类型已变更
-- SELECT column_name, data_type, udt_name
-- FROM information_schema.columns
-- WHERE table_schema = 'auth'
-- AND table_name = 'site_code_mapping'
-- AND column_name = 'tenant_id';
-- 预期data_type = 'bigint', udt_name = 'int8'
-- 2. 确认现有数据完整
-- SELECT count(*) FROM auth.site_code_mapping;
-- 预期:行数与迁移前一致
-- 3. 确认可插入大值 tenant_id
-- SELECT 2790683160709957::bigint;
-- 预期:返回 2790683160709957不报溢出错误

View File

@@ -0,0 +1,11 @@
-- 2026-03-07 | 多实例任务隔离task_queue 增加 enqueued_by 列
-- 背景:发现有另一台机器(宿主机 D 盘部署)的后端也在消费同一个 task_queue
-- 导致任务被错误实例执行(路径不匹配 → UTF-8 解码失败)。
-- 通过 enqueued_by 列记录入队实例的 hostnameprocess_loop 只消费自己入队的任务。
ALTER TABLE task_queue ADD COLUMN IF NOT EXISTS enqueued_by VARCHAR(255) DEFAULT NULL;
COMMENT ON COLUMN task_queue.enqueued_by IS '入队实例的 hostnameplatform.node()),用于多实例任务隔离';
-- 回滚:
-- ALTER TABLE task_queue DROP COLUMN IF EXISTS enqueued_by;

View File

@@ -0,0 +1,82 @@
-- =============================================================================
-- 迁移member_retention_clue.category CHECK 约束枚举对齐
-- 日期2026-03-08
-- 目标库zqyy_app / test_zqyy_app
-- 说明:
-- 将 category CHECK 约束中 '客户基础信息' 改为 '客户基础'
-- 与 AI 应用 Prompt 枚举值统一P5 spec 2026-03-08 评审决定)。
-- '促销偏好' 保持不变(原 Prompt 中的 '促销接受' 已在 spec 侧对齐为 '促销偏好')。
-- 统一后 6 个枚举值:客户基础、消费习惯、玩法偏好、促销偏好、社交关系、重要反馈
-- 影响:
-- - 已有数据中 category='客户基础信息' 的行需更新为 '客户基础'
-- - 后端 APIPOST /api/retention-clue 的 category 校验需同步
-- - AI 应用 3/6/8 的 Prompt 枚举已在 P5 spec 中统一
-- 幂等:先检查约束是否存在再操作,可重复执行
-- =============================================================================
BEGIN;
-- ============================================================
-- 1. 更新已有数据(先于约束变更)
-- ============================================================
UPDATE member_retention_clue
SET category = '客户基础'
WHERE category = '客户基础信息';
-- ============================================================
-- 2. 删除旧 CHECK 约束
-- ============================================================
ALTER TABLE member_retention_clue
DROP CONSTRAINT IF EXISTS chk_retention_clue_category;
-- ============================================================
-- 3. 创建新 CHECK 约束('客户基础信息' → '客户基础'
-- ============================================================
ALTER TABLE member_retention_clue
ADD CONSTRAINT chk_retention_clue_category CHECK (
category IN ('客户基础', '消费习惯', '玩法偏好', '促销偏好', '社交关系', '重要反馈')
);
-- ============================================================
-- 4. 更新列注释
-- ============================================================
COMMENT ON COLUMN member_retention_clue.category
IS '线索大类枚举:客户基础、消费习惯、玩法偏好、促销偏好、社交关系、重要反馈';
COMMIT;
-- ============================================================
-- 回滚(需手动执行)
-- ============================================================
-- BEGIN;
-- UPDATE member_retention_clue SET category = '客户基础信息' WHERE category = '客户基础';
-- ALTER TABLE member_retention_clue DROP CONSTRAINT IF EXISTS chk_retention_clue_category;
-- ALTER TABLE member_retention_clue ADD CONSTRAINT chk_retention_clue_category CHECK (
-- category IN ('客户基础信息', '消费习惯', '玩法偏好', '促销偏好', '社交关系', '重要反馈')
-- );
-- COMMENT ON COLUMN member_retention_clue.category
-- IS '线索大类枚举:客户基础信息、消费习惯、玩法偏好、促销偏好、社交关系、重要反馈';
-- COMMIT;
-- ============================================================
-- 验证 SQL
-- ============================================================
-- 1. 确认无 '客户基础信息' 残留
-- SELECT COUNT(*) FROM member_retention_clue WHERE category = '客户基础信息';
-- 预期0
-- 2. 确认 CHECK 约束内容
-- SELECT conname, pg_get_constraintdef(oid) FROM pg_constraint
-- WHERE conrelid = 'member_retention_clue'::regclass AND contype = 'c';
-- 预期chk_retention_clue_category包含 '客户基础'(非 '客户基础信息'
-- 3. 测试新枚举值可写入
-- INSERT INTO member_retention_clue (member_id, category, summary, site_id)
-- VALUES (0, '客户基础', '测试', 0);
-- 预期:成功
-- DELETE FROM member_retention_clue WHERE member_id = 0 AND summary = '测试';
-- 4. 测试旧枚举值被拒绝
-- INSERT INTO member_retention_clue (member_id, category, summary, site_id)
-- VALUES (0, '客户基础信息', '测试', 0);
-- 预期CHECK 约束违反错误

View File

@@ -0,0 +1,65 @@
-- ============================================================
-- P5 AI 集成层:创建 AI 对话、消息、缓存三张表
-- 需求: 1.1, 1.2, 1.3, 1.4, 1.5
-- ============================================================
-- 1. biz.ai_conversations —— AI 对话记录
CREATE TABLE IF NOT EXISTS biz.ai_conversations (
id BIGSERIAL PRIMARY KEY,
user_id VARCHAR(50) NOT NULL,
nickname VARCHAR(100) NOT NULL DEFAULT '',
app_id VARCHAR(30) NOT NULL,
site_id BIGINT NOT NULL,
source_page VARCHAR(100),
source_context JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
COMMENT ON TABLE biz.ai_conversations IS 'AI 对话记录:每次 AI 调用(用户主动或系统自动)创建一条';
COMMENT ON COLUMN biz.ai_conversations.app_id IS '应用标识app1_chat / app2_finance / app3_clue / app4_analysis / app5_tactics / app6_note / app7_customer / app8_consolidation';
COMMENT ON COLUMN biz.ai_conversations.user_id IS '用户 ID系统自动调用时为 system';
CREATE INDEX IF NOT EXISTS idx_ai_conv_user_site ON biz.ai_conversations (user_id, site_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_ai_conv_app_site ON biz.ai_conversations (app_id, site_id, created_at DESC);
-- 2. biz.ai_messages —— AI 消息记录
CREATE TABLE IF NOT EXISTS biz.ai_messages (
id BIGSERIAL PRIMARY KEY,
conversation_id BIGINT NOT NULL REFERENCES biz.ai_conversations(id) ON DELETE CASCADE,
role VARCHAR(10) NOT NULL
CONSTRAINT chk_ai_msg_role CHECK (role IN ('user', 'assistant', 'system')),
content TEXT NOT NULL,
tokens_used INTEGER,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
COMMENT ON TABLE biz.ai_messages IS 'AI 消息记录:对话中的每条消息(输入/输出/系统)';
CREATE INDEX IF NOT EXISTS idx_ai_msg_conv ON biz.ai_messages (conversation_id, created_at);
-- 3. biz.ai_cache —— AI 应用缓存
CREATE TABLE IF NOT EXISTS biz.ai_cache (
id BIGSERIAL PRIMARY KEY,
cache_type VARCHAR(30) NOT NULL
CONSTRAINT chk_ai_cache_type CHECK (
cache_type IN (
'app2_finance', 'app3_clue', 'app4_analysis',
'app5_tactics', 'app6_note_analysis',
'app7_customer_analysis', 'app8_clue_consolidated'
)
),
site_id BIGINT NOT NULL,
target_id VARCHAR(100) NOT NULL,
result_json JSONB NOT NULL,
score INTEGER,
triggered_by VARCHAR(100),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
expires_at TIMESTAMPTZ
);
COMMENT ON TABLE biz.ai_cache IS 'AI 应用缓存:各应用的结构化输出结果';
COMMENT ON COLUMN biz.ai_cache.target_id IS '目标 IDApp2=时间维度编码 / App3,6,7,8=member_id / App4,5={assistant_id}_{member_id}';
COMMENT ON COLUMN biz.ai_cache.score IS '评分:仅应用 6 使用1-10 分)';
CREATE INDEX IF NOT EXISTS idx_ai_cache_lookup ON biz.ai_cache (cache_type, site_id, target_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_ai_cache_cleanup ON biz.ai_cache (cache_type, site_id, target_id, created_at);

View File

@@ -0,0 +1,13 @@
-- 给 task_execution_log 添加 schedule_id 字段,关联调度任务
-- 用于查询某个调度任务的执行历史
ALTER TABLE task_execution_log
ADD COLUMN IF NOT EXISTS schedule_id UUID REFERENCES scheduled_tasks(id) ON DELETE SET NULL;
-- 按 schedule_id 查询执行历史的部分索引
CREATE INDEX IF NOT EXISTS idx_execution_log_schedule_id
ON task_execution_log(schedule_id)
WHERE schedule_id IS NOT NULL;
-- 给 task_queue 添加 schedule_id 字段,追溯调度来源
ALTER TABLE task_queue
ADD COLUMN IF NOT EXISTS schedule_id UUID REFERENCES scheduled_tasks(id) ON DELETE SET NULL;

View File

@@ -0,0 +1,29 @@
-- 触发器INSERT task_execution_log 时自动从 task_queue 回填 schedule_id
-- 背景:队列处理循环中 schedule_id 可能未通过代码传递,用触发器兜底
CREATE OR REPLACE FUNCTION fn_backfill_schedule_id()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.schedule_id IS NULL AND NEW.queue_id IS NOT NULL THEN
SELECT schedule_id INTO NEW.schedule_id
FROM task_queue
WHERE id = NEW.queue_id;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trg_backfill_schedule_id ON task_execution_log;
CREATE TRIGGER trg_backfill_schedule_id
BEFORE INSERT ON task_execution_log
FOR EACH ROW
EXECUTE FUNCTION fn_backfill_schedule_id();
-- 回填历史数据
UPDATE task_execution_log el
SET schedule_id = tq.schedule_id
FROM task_queue tq
WHERE el.queue_id = tq.id
AND tq.schedule_id IS NOT NULL
AND el.schedule_id IS NULL;