涵盖(每条对应已存的审计记录): - AI 模块拆分:apps/backend/app/ai/apps -> prompts/(8 个 APP + app2a 派生) audit: 2026-04-20__ai-module-complete.md - admin-web AI 管理套件:AIDashboard / AIOperations / AIRunLogs / AITriggers / TriggerManager audit: 2026-04-21__admin-web-ai-management-suite.md - App2 财务洞察 prompt v3 -> v5.1 + 小程序 AI 接入(chat / board-finance) audit: 2026-04-22__app2_prompt_v5_1_and_miniprogram_ai_insight.md - App2 prewarm 全过滤器 + AI 触发器 cron reschedule audit: 2026-04-21__app2-finance-prewarm-all-filters.md migration: 20260420_ai_trigger_jobs_and_app2_prewarm.sql / 20260421_app2_prewarm_cron_reschedule.sql - AppType 联合类型对齐 + adminAiAppTypes.test.ts audit: 2026-04-30__admin_web_ai_app_type_alignment.md - DashScope tokens_used 提取修复 audit: 2026-04-30__backend_dashscope_tokens_used_extraction.md - App3 线索完整详情 prompt audit: 2026-05-01__backend_app3_full_detail_prompt.md - Runtime Context 沙箱(5-1~5-2 主线): - 后端 schema/service + admin_runtime_context / xcx_runtime_clock 两个 router - admin-web RuntimeContext.tsx + miniprogram runtime-clock.ts - migration: 20260501__runtime_context_sandbox.sql - tools/db/verify_admin_web_sandbox.py + verify_sandbox_end_to_end.py - database/changes: 7 份 sandbox_* 验证报告 - 飞球 DWS 修复:finance_area_daily 区域汇总 + task_engine 调整 + RLS 视图业务日上界(migration 20260502 + scripts/ops/gen_rls_business_date_migration.py) 合规: - .gitignore 启用 tmp/ 排除 - 不入仓:apps/etl/connectors/feiqiu/.env(API_TOKEN secret,本地修改保留) 待验证清单: - docs/audit/changes/2026-05-04__cumulative_baseline_pending_verification.md 每个主题的功能完整性 / 上线验证几乎都未收口,按优先级 P0~P3 逐一处理
9.7 KiB
9.7 KiB
2026-05-02 沙箱「不看未来」彻底改造(A+B+C 全做)
目标
让 sandbox 真正模拟"设定历史日 sandbox_date 当时所有数据状态"—— 后台读取层、AI prompts、小程序业务看板/绩效/客户/任务页全部按 business_date 截断, 不再读取 sandbox_date 之后的真实生产数据。
端的归类(重要更正 2026-05-02):
- 小程序 才是业务看板(
board-finance / board-customer / board-coach)和绩效/客户/任务页面所在, 是沙箱「不看未来」的主要受益方。- admin-web 是开发/运维向,不展示业务看板;沙箱在它这边主要表现为
RuntimeContext开关、AIDashboard / AIOperations / AIRunLogs / TaskManager / TriggerManager等管理页能看到 sandbox 实例下的 AI 调用、任务写入与触发记录是隔离的(但 AI 计费/调度时间仍按真实系统时间,不受沙箱影响)。- tenant-admin 几乎不涉及业务数据展示,本轮基本不在沙箱范围。
总览:三层方案
| 层 | 范围 | 方法 | 状态 |
|---|---|---|---|
| A 文档/UI | admin-web、BD_Manual | 顶部 Alert + 路线章节,提示"读取层修复进行中" | ✅ |
| B 应用层 | backend service / AI prompts & fetchers / fdw_queries / 小程序 | 时间锚替换为 RuntimeContext.business_date / business_now,SQL 补上界 | ✅ |
| C 数据层 | etl_feiqiu app schema RLS 视图 | 引入 GUC app.current_business_date + app.business_date_now() 函数 + 关键视图 WHERE 上界 |
✅ |
关键改动
A 层
apps/admin-web/src/pages/RuntimeContext.tsx— 顶部 Alert 增加"读取层修复进行中"+ plan 链接。docs/database/BD_Manual_runtime_context_sandbox.md— 第 7 节新增"读取层不看未来路线"。
B 层 (后端)
apps/backend/app/services/runtime_context.py新增 helpers:as_runtime_year_month_param(site_id) -> 'YYYY-MM'as_runtime_business_now_str(site_id, fmt) -> strbusiness_date_upper_bound_sql(site_id, column, alias, cast)返回 SQL 片段apply_runtime_session_vars(conn, ctx | site_id)设置 GUC(C 层基础)
- AI prompts:app3/4/5/6/7 的
current_time改用as_runtime_business_now_str,不再datetime.now()。 - AI data_fetchers:
member_data._query_consumption_records/_query_visit_info接受ref_date,所有窗口加业务日上界。assistant_data._fetch_assistant_info_sync/_fetch_service_history_sync用业务日。page_context._text_board_finance/customer/coach/customer_service_records全部上界化。- 所有直连 ETL 库的 cursor 在
SET LOCAL app.current_site_id之后再下发app.current_business_date,供 RLS 视图 GUC 读取。
- service:
board_service._batch_coach_details接受 ref_date,60 天消费窗口按业务日截。chat_service._get_consumption_30d/_get_visit_count_30d业务日 30 天窗口。coach_service.get_coach_detail/_build_history_months用业务日年月。customer_service60 天助教统计上界化。task_generator转移子流程的now改用 business_now。task_manager.batch_query_for_task_list/build_performance_summary/ 任务详情 60 天窗口全部业务日。tenant_users.pySCD2 配置(cfg_assistant_level_price)用业务日。
- fdw_queries(关键修复):
_fdw_context进入事务后下发app.current_business_date+app.current_runtime_modeGUC。- 客户看板「最近到店」bug 修复:
get_last_visit_days/batch_query_for_task_list(last_visit 计算)改为 ETLlast_consume_date+business_date - last_consume_date实时计算,不再依赖 ETL 预计算的days_since_last,沙箱场景与 ETL 跑批延迟下都能正确显示"距上次到店 N 天"。 get_customer_board_recent/get_customer_board_recharge/get_customer_board_freq60/get_customer_board_recall/_get_weekly_visits_batch/get_coach_60d_stats/batch_query_for_task_list60 天窗口 / SCD2 配置等全部用业务日。
B 层 (小程序)
apps/backend/app/routers/xcx_runtime_clock.py新增端点GET /api/xcx/runtime/clock,返回 mode/business_date/business_year/business_month/business_year_month/business_now/is_sandbox/sandbox_date。apps/miniprogram/miniprogram/services/api.ts增加fetchRuntimeClock。apps/miniprogram/miniprogram/utils/runtime-clock.ts(新增)—— 60s 缓存 + 失败降级到本地时间。- 关键页面切换为业务时钟:
pages/performance/performance.ts—— G2 当月预估判断pages/performance-records/performance-records.ts—— onLoad / loadData / switchMonthpages/task-list/task-list.ts—— 月度判断pages/customer-records/customer-records.ts—— onLoadpages/customer-service-records/customer-service-records.ts—— onLoad
C 层 (RLS 视图)
- 新增迁移
db/etl_feiqiu/migrations/20260502__rls_views_business_date_upper_bound.sql:- 注册 STABLE SQL 函数
app.business_date_now():从 GUCapp.current_business_date读取业务日,未设置时回退CURRENT_DATE。 - 21 个视图重写 WHERE,加
<日期列> <= app.business_date_now():- 财务事实 6 个:
v_dws_finance_area_daily / daily_summary / discount_detail / expense_summary / income_structure / recharge_summary - 助教汇总 5 个:
v_assistant_daily / v_dws_assistant_daily_detail / monthly_summary / salary_calc / finance_analysis - 客户事实 3 个:
v_dws_member_consumption_summary / visit_detail / winback_index - DWD 事实 5 个:
v_dwd_settlement_head / assistant_service_log / recharge_order / store_goods_sale / table_fee_log - SCD2 配置 2 个:
v_cfg_assistant_level_price / performance_tier
- 财务事实 6 个:
- 列签名通过
pg_get_viewdef实时从测试库读取,确保CREATE OR REPLACE VIEW不会因列签名漂移而失败。
- 注册 STABLE SQL 函数
- 生成脚本:
scripts/ops/gen_rls_business_date_migration.py(可重复执行)。 - DDL 同步:
docs/database/ddl/etl_feiqiu__app.sql、db/etl_feiqiu/schemas/app.sql已同步。
验证
测试库迁移结果
test site_id = 2790685415443269
live: max(stat_date)=2026-04-27, count=2439
sandbox(=2025-09-01):
max(stat_date) finance_area_daily = 2025-09-01, count=432
max(visit_date) member_visit = 2025-09-01
max(create_time::date) settlement = 2025-09-01
RESULT: PASS
live 模式行为不变;sandbox 模式下所有事实视图严格不返回 sandbox_date 之后的数据。
静态检查
- 后端 99 个改动文件 AST 解析全部通过。
- 前端 admin-web、小程序关键页面 lint 无新增错误。
兼容性 / 回滚
- live 模式下 GUC 不设置 →
app.business_date_now()回退CURRENT_DATE,行为完全等同于改造前。 - 回滚:
DROP FUNCTION app.business_date_now() CASCADE;(视图会一并被 DROP),然后重新执行db/etl_feiqiu/schemas/app.sql即可恢复 live 行为。 - B 层 / 小程序的时间锚替换全部走 RuntimeContext(fail-soft 降级 live),不影响生产链路。
已知未覆盖
- page_context.py 中 7 处直连 ETL 的查询,已加 SQL 上界(B 层),但部分位置依赖 GUC(C 层)即可,未单独传 ref_date。
- 写入时间戳(
created_at、updated_at、finished_at、调度last_run_at、ai_run_logs 写入)保持系统真实时间,不应被沙箱影响(这是审计/运行时元数据),保留现状。 - 小程序 chat / customer-detail 页面用于"展示当前操作时间"的
new Date()保留(与会话/操作记录关联)。 - AI 调度的预算计算、限流仍按真实系统时间。
- DIM SCD2 维度(v_dim_assistant / v_dim_member / v_dim_member_card_account / v_dim_staff / v_dim_staff_ex / v_dim_table)保留
scd2_is_current=1当前快照语义,未按 sandbox_date 重建历史维度行;如需"sandbox 当时维度状态"另行评估。
2026-05-02 后续追加
B-2 / C 层补强
- 18 个非关键视图补业务日上界(详见
gen_rls_business_date_migration.py的VIEWS_WITH_BD):覆盖v_cfg_bonus_rules/v_cfg_index_parameters两个配置维度,及 16 个 DWS 业务事实/汇总(如v_dws_assistant_customer_stats、v_dws_member_assistant_intimacy、v_dws_finance_board_cache、v_finance_daily等)。总计 39 个 RLS 视图带业务日上界。 - 端到端验证:
tools/db/verify_sandbox_end_to_end.py一键跑 live + sandbox(2025-09-01) 对比,输出2026-05-02__sandbox_e2e_verify_report.md。本轮结果 31/31 PASS。- 注意:脚本里测的
get_customer_board_recent / recharge / freq60 / recall是fdw_queries函数,实际服务的是小程序board-customer,不是 admin-web。验证脚本同时覆盖 RLS 视图层(21+18=39 个视图),与端无关。
- 注意:脚本里测的
log 警告止血(独立于沙箱)
apps/etl/connectors/feiqiu/tasks/dws/finance_area_daily.py: 拓宽_is_all_only_area,把补时长N/虚拟台N编号变体、area_name=None & table_id 不空都归入 INFO(不再 WARNING),消除噪音。apps/etl/connectors/feiqiu/tasks/dws/task_engine.py: ETL → backend HTTP_TIMEOUT由(5, 30)改(10, 600),与flow_runner对齐,止血 30s 读超时。根因(同步长任务+30s timeout)已记录,长期方案是/api/internal/run-job改异步入队,待后续 PR。
相关文件清单
- 主迁移:
db/etl_feiqiu/migrations/20260502__rls_views_business_date_upper_bound.sql - 生成器:
scripts/ops/gen_rls_business_date_migration.py - 端到端验证:
tools/db/verify_sandbox_end_to_end.py - 验证报告:
docs/database/changes/2026-05-02__sandbox_e2e_verify_report.md - 文档:本文件 +
docs/database/BD_Manual_runtime_context_sandbox.md