chore: v1 整理 — 清理历史文件、DDL 合并、文档归档

- 清理 1155 个已删除的历史文件(废弃 prompt_logs、tmp、旧 ops 脚本)
- export/ 数据文件从 git 移除(已在 .gitignore)
- demo-miniprogram 从 tmp/ 移入 apps/,添加 CLAUDE.md 注解
- DDL 合并:完整 schema 定义填充到 db/*/schemas/(从 docs/database/ddl/ 复制)
- 39 个 v1 迁移脚本归档到 db/_archived/migrations_v1_merged/
- 4 个迁移变更类 BD_Manual 文档归档到 docs/database/_archived/
- .gitignore 补充 .vite/ 和 apps/*.zip
- settings.json 添加 effortLevel 默认配置
- scripts/ops/ 新增运维脚本入库

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Neo
2026-04-06 00:39:27 +08:00
parent 6f8f12314f
commit 779b2f6d52
1340 changed files with 9124 additions and 132087 deletions

View File

@@ -0,0 +1,35 @@
-- 迁移:为 BOARD 看板新增 3 个 app schema RLS 视图
-- 日期2026-03-19
-- 原因BOARD-1 技能筛选、BOARD-2 项目筛选/消费潜力指数需要这些视图通过 FDW 暴露给业务库
-- 回滚DROP VIEW IF EXISTS app.v_dws_assistant_project_tag, app.v_dws_member_project_tag, app.v_dws_member_spending_power_index;
-- 1. 助教项目标签视图BOARD-1 技能筛选用)
CREATE OR REPLACE VIEW app.v_dws_assistant_project_tag AS
SELECT id, site_id, tenant_id, assistant_id, time_window,
category_code, category_name, short_name,
duration_seconds, total_seconds, percentage, is_tagged,
computed_at, created_at, updated_at
FROM dws.dws_assistant_project_tag
WHERE site_id = current_setting('app.current_site_id')::bigint;
-- 2. 会员项目标签视图BOARD-2 项目筛选用)
CREATE OR REPLACE VIEW app.v_dws_member_project_tag AS
SELECT id, site_id, tenant_id, member_id, time_window,
category_code, category_name, short_name,
duration_seconds, total_seconds, percentage, is_tagged,
computed_at, created_at, updated_at
FROM dws.dws_member_project_tag
WHERE site_id = current_setting('app.current_site_id')::bigint;
-- 3. 会员消费潜力指数视图BOARD-2 potential 维度用)
CREATE OR REPLACE VIEW app.v_dws_member_spending_power_index AS
SELECT spi_id, site_id, member_id,
spend_30, spend_90, recharge_90,
orders_30, orders_90, visit_days_30, visit_days_90,
avg_ticket_90, active_weeks_90, daily_spend_ewma_90,
score_level_raw, score_speed_raw, score_stability_raw,
score_level_display, score_speed_display, score_stability_display,
raw_score, display_score,
calc_time, created_at, updated_at
FROM dws.dws_member_spending_power_index
WHERE site_id = current_setting('app.current_site_id')::bigint;

View File

@@ -0,0 +1,12 @@
-- 赠送卡按卡类型拆分:新增 6 个细分字段
-- 需求BOARD-3 赠送卡矩阵需要按酒水卡/台费卡/抵用券展示余额和新增
-- 恒等式gift_card_balance = gift_liquor_balance + gift_table_fee_balance + gift_voucher_balance
-- recharge_gift = gift_liquor_recharge + gift_table_fee_recharge + gift_voucher_recharge
ALTER TABLE dws.dws_finance_recharge_summary
ADD COLUMN IF NOT EXISTS gift_liquor_balance NUMERIC(14,2) NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS gift_table_fee_balance NUMERIC(14,2) NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS gift_voucher_balance NUMERIC(14,2) NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS gift_liquor_recharge NUMERIC(14,2) NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS gift_table_fee_recharge NUMERIC(14,2) NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS gift_voucher_recharge NUMERIC(14,2) NOT NULL DEFAULT 0;

View File

@@ -0,0 +1,48 @@
-- 迁移:给 cfg_area_category 加 sort_order 字段 + 创建 app.v_cfg_area_category 视图
-- 关联R3 修复(项目类型筛选接口重建)
-- 日期2026-03-20
-- 回滚:见文件末尾
-- ============================================================
-- 1. 给 cfg_area_category 加 sort_order 字段
-- ============================================================
ALTER TABLE dws.cfg_area_category
ADD COLUMN IF NOT EXISTS sort_order INTEGER DEFAULT 100 NOT NULL;
COMMENT ON COLUMN dws.cfg_area_category.sort_order
IS '前端筛选器显示排序(值越小越靠前)';
-- 按业务优先级设置排序值
UPDATE dws.cfg_area_category SET sort_order = 10 WHERE category_code = 'BILLIARD';
UPDATE dws.cfg_area_category SET sort_order = 20 WHERE category_code = 'SNOOKER';
UPDATE dws.cfg_area_category SET sort_order = 30 WHERE category_code = 'MAHJONG';
UPDATE dws.cfg_area_category SET sort_order = 40 WHERE category_code = 'KTV';
UPDATE dws.cfg_area_category SET sort_order = 900 WHERE category_code = 'SPECIAL';
UPDATE dws.cfg_area_category SET sort_order = 999 WHERE category_code = 'OTHER';
-- ============================================================
-- 2. 创建 app.v_cfg_area_category 视图
-- 去重到 category 级别,排除 SPECIAL/OTHER不在前端筛选器显示
-- ============================================================
CREATE OR REPLACE VIEW app.v_cfg_area_category AS
SELECT DISTINCT
category_code,
category_name,
display_name,
short_name,
sort_order
FROM dws.cfg_area_category
WHERE is_active = TRUE
AND category_code NOT IN ('SPECIAL', 'OTHER')
ORDER BY sort_order;
GRANT SELECT ON app.v_cfg_area_category TO app_reader;
COMMENT ON VIEW app.v_cfg_area_category
IS '项目类型筛选器配置视图(去重到 category 级别,排除 SPECIAL/OTHER';
-- ============================================================
-- 回滚
-- ============================================================
-- DROP VIEW IF EXISTS app.v_cfg_area_category;
-- ALTER TABLE dws.cfg_area_category DROP COLUMN IF EXISTS sort_order;

View File

@@ -0,0 +1,58 @@
-- =============================================================================
-- 迁移:移除废弃的 dws_member_recall_index 表及 RLS 视图
-- 日期: 2026-03-20
-- 原因: RecallIndexTask 已于 2026-02-13 被 WBI+NCI 替代,但表和视图的 DDL
-- 在 2026-02-19 schema 重命名billiards_dws → dws时残留至今。
-- 表中无有效数据ETL 任务已删除),属于孤儿对象。
-- 影响: 无下游消费者依赖此表数据(后端 recall 维度已改用 v_dws_member_winback_index
-- 回滚: 从 git 历史恢复 DDL 定义并重建表和视图
-- =============================================================================
BEGIN;
-- 1. 删除 RLS 视图
DROP VIEW IF EXISTS app.v_dws_member_recall_index;
-- 2. 删除索引
DROP INDEX IF EXISTS dws.idx_dws_recall_display;
-- 3. 删除表CASCADE 会自动清理约束)
DROP TABLE IF EXISTS dws.dws_member_recall_index CASCADE;
-- 4. 删除序列
DROP SEQUENCE IF EXISTS dws.dws_member_recall_index_recall_id_seq;
COMMIT;
-- =============================================================================
-- 验证
-- =============================================================================
DO $$
DECLARE
tbl_exists BOOLEAN;
view_exists BOOLEAN;
seq_exists BOOLEAN;
BEGIN
SELECT EXISTS(
SELECT 1 FROM information_schema.tables
WHERE table_schema = 'dws' AND table_name = 'dws_member_recall_index'
) INTO tbl_exists;
SELECT EXISTS(
SELECT 1 FROM information_schema.views
WHERE table_schema = 'app' AND table_name = 'v_dws_member_recall_index'
) INTO view_exists;
SELECT EXISTS(
SELECT 1 FROM information_schema.sequences
WHERE sequence_schema = 'dws' AND sequence_name = 'dws_member_recall_index_recall_id_seq'
) INTO seq_exists;
RAISE NOTICE '表存在: % (应为 false)', tbl_exists;
RAISE NOTICE '视图存在: % (应为 false)', view_exists;
RAISE NOTICE '序列存在: % (应为 false)', seq_exists;
IF tbl_exists OR view_exists OR seq_exists THEN
RAISE EXCEPTION '清理不完整,仍有残留对象';
END IF;
END $$;

View File

@@ -0,0 +1,41 @@
-- 迁移:补录 cfg_skill_type 缺失的 3 条 skill_id
-- 原因dwd_assistant_service_log 中存在 5525 条记录引用了不在 cfg_skill_type 中的 skill_id
-- 导致 WBI/NCI 的到店判定settle_type=3 + BONUS EXISTS 检查)漏掉了这些到店记录。
-- 典型案例:会员"梅"实际 5 天前到店,但 WBI 显示 16 天未到店display_score 虚高至 9.42。
-- 影响WBI、NCI、关系指数、助教服务统计、工资计算等所有依赖 cfg_skill_type JOIN 的下游。
-- 回滚DELETE FROM dws.cfg_skill_type WHERE skill_id IN (2790683529513797, 2790683529513798, 3039912271463941);
BEGIN;
INSERT INTO dws.cfg_skill_type (skill_id, skill_name, course_type_code, course_type_name, is_active, description)
VALUES
(2790683529513797, '基础课', 'BASE', '基础课', TRUE,
'基础课:飞球系统原始课程类型,与"台球基础陪打"同类'),
(2790683529513798, '附加课', 'BONUS', '附加课', TRUE,
'附加课:飞球系统原始课程类型,与"台球超休服务"同类'),
(3039912271463941, '包厢课', 'BASE', '基础课', TRUE,
'包厢课:飞球系统原始课程类型,与"包厢服务"同类')
ON CONFLICT (skill_id) DO NOTHING;
COMMIT;
-- 验证 SQL执行后应返回 6 行,且无 NULL 的 course_type_code
-- SELECT skill_id, skill_name, course_type_code, is_active FROM dws.cfg_skill_type ORDER BY skill_id;
--
-- 验证受影响会员数(应 > 0
-- SELECT COUNT(DISTINCT asl.tenant_member_id)
-- FROM dwd.dwd_assistant_service_log asl
-- JOIN dws.cfg_skill_type st ON asl.skill_id = st.skill_id
-- WHERE asl.skill_id IN (2790683529513797, 2790683529513798, 3039912271463941)
-- AND asl.is_delete = 0;
--
-- 验证梅的到店记录是否被正确识别:
-- SELECT s.order_settle_id, s.pay_time, s.settle_type,
-- EXISTS (
-- SELECT 1 FROM dwd.dwd_assistant_service_log asl
-- JOIN dws.cfg_skill_type st ON asl.skill_id = st.skill_id AND st.course_type_code = 'BONUS' AND st.is_active = TRUE
-- WHERE asl.order_settle_id = s.order_settle_id AND asl.site_id = s.site_id AND asl.tenant_member_id = s.member_id AND asl.is_delete = 0
-- ) AS has_bonus_service
-- FROM dwd.dwd_settlement_head s
-- WHERE s.member_id = 2975065345119045 AND s.pay_time >= '2026-03-08'
-- ORDER BY s.pay_time DESC;

View File

@@ -0,0 +1,71 @@
-- =============================================================================
-- 迁移:补充 ETL 字段差异分析中识别的缺失字段
-- 日期2026-03-26
-- 来源field_gap_analysis.md 深度评估
-- 影响5 张 ODS 表 + 6 张 DWD 表
-- =============================================================================
BEGIN;
-- ── ODS 层新增列 ──
-- 1. member_profiles: 4 个 API 字段
ALTER TABLE ods.member_profiles ADD COLUMN IF NOT EXISTS other_pay_money_sum numeric(18,2);
ALTER TABLE ods.member_profiles ADD COLUMN IF NOT EXISTS last_consume_time timestamp without time zone;
ALTER TABLE ods.member_profiles ADD COLUMN IF NOT EXISTS non_consume_day_num integer;
ALTER TABLE ods.member_profiles ADD COLUMN IF NOT EXISTS first_consumption integer;
-- 2. assistant_service_records: 1 个 API 字段
ALTER TABLE ods.assistant_service_records ADD COLUMN IF NOT EXISTS deduct_leave_seconds integer DEFAULT 0;
-- 3. store_goods_sales_records: 2 个 API 字段
ALTER TABLE ods.store_goods_sales_records ADD COLUMN IF NOT EXISTS activity_amount numeric(18,2) DEFAULT 0;
ALTER TABLE ods.store_goods_sales_records ADD COLUMN IF NOT EXISTS activity_id bigint DEFAULT 0;
-- 4. goods_stock_summary: 1 个 API 字段(注意 ODS 列名全小写)
ALTER TABLE ods.goods_stock_summary ADD COLUMN IF NOT EXISTS createtime timestamp without time zone;
-- 5. table_fee_transactions: order_from
ALTER TABLE ods.table_fee_transactions ADD COLUMN IF NOT EXISTS order_from integer;
-- 6. assistant_service_records: order_from
ALTER TABLE ods.assistant_service_records ADD COLUMN IF NOT EXISTS order_from integer;
-- 7. store_goods_sales_records: order_from
ALTER TABLE ods.store_goods_sales_records ADD COLUMN IF NOT EXISTS order_from integer;
-- 8. settlement_records: order_from来自 settleList.orderFrom展开后为 orderfrom
-- 注意settlement_records 的 ODS 列名是全小写无下划线(与 API camelCase 对应)
ALTER TABLE ods.settlement_records ADD COLUMN IF NOT EXISTS orderfrom integer;
-- ── DWD 层新增列 ──
-- 1. dim_member_ex: 4 个字段 + birthday
ALTER TABLE dwd.dim_member_ex ADD COLUMN IF NOT EXISTS other_pay_money_sum numeric(18,2);
ALTER TABLE dwd.dim_member_ex ADD COLUMN IF NOT EXISTS last_consume_time timestamp with time zone;
ALTER TABLE dwd.dim_member_ex ADD COLUMN IF NOT EXISTS non_consume_day_num integer;
ALTER TABLE dwd.dim_member_ex ADD COLUMN IF NOT EXISTS first_consumption integer;
-- birthday 已在 dim_member 主表中存在,无需重复添加
-- 2. dim_member_card_account_ex: pdassisnatlevel + cxassisnatlevel 已存在于 DDL 中
-- 确认goodscategoryid, tableareaid, pdassisnatlevel, cxassisnatlevel 已在 DWD DDL 和 FACT_MAPPINGS 中
-- 3. dwd_assistant_service_log_ex: deduct_leave_seconds + order_from
ALTER TABLE dwd.dwd_assistant_service_log_ex ADD COLUMN IF NOT EXISTS deduct_leave_seconds integer DEFAULT 0;
ALTER TABLE dwd.dwd_assistant_service_log_ex ADD COLUMN IF NOT EXISTS order_from integer;
-- 4. dwd_store_goods_sale_ex: activity_amount + activity_id + order_from
ALTER TABLE dwd.dwd_store_goods_sale_ex ADD COLUMN IF NOT EXISTS activity_amount numeric(18,2) DEFAULT 0;
ALTER TABLE dwd.dwd_store_goods_sale_ex ADD COLUMN IF NOT EXISTS activity_id bigint DEFAULT 0;
ALTER TABLE dwd.dwd_store_goods_sale_ex ADD COLUMN IF NOT EXISTS order_from integer;
-- 5. dwd_goods_stock_summary: create_time
ALTER TABLE dwd.dwd_goods_stock_summary ADD COLUMN IF NOT EXISTS create_time timestamp with time zone;
-- 6. dwd_table_fee_log_ex: order_from
ALTER TABLE dwd.dwd_table_fee_log_ex ADD COLUMN IF NOT EXISTS order_from integer;
-- 7. dwd_settlement_head_ex: order_from
ALTER TABLE dwd.dwd_settlement_head_ex ADD COLUMN IF NOT EXISTS order_from integer;
COMMIT;

View File

@@ -0,0 +1,51 @@
-- 迁移:财务日报新增支付方式拆分字段
-- 关联board-finance-integration SPEC T1.1
-- 日期2026-03-27
-- 回滚:见文件末尾
-- ============================================================
-- 1. 新增字段
-- ============================================================
ALTER TABLE dws.dws_finance_daily_summary
ADD COLUMN IF NOT EXISTS cash_paper_amount NUMERIC(14,2) DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS scan_pay_amount NUMERIC(14,2) DEFAULT 0 NOT NULL;
COMMENT ON COLUMN dws.dws_finance_daily_summary.cash_paper_amount
IS '纸币现金收款dwd_payment.payment_method=2';
COMMENT ON COLUMN dws.dws_finance_daily_summary.scan_pay_amount
IS '扫码收款/离线支付dwd_payment.payment_method=4含微信/支付宝)';
-- ============================================================
-- 2. 更新 RLS 视图暴露新字段
-- ============================================================
CREATE OR REPLACE VIEW app.v_dws_finance_daily_summary AS
SELECT id, site_id, tenant_id, stat_date,
gross_amount, table_fee_amount, goods_amount,
assistant_pd_amount, assistant_cx_amount,
discount_total, discount_groupbuy, discount_vip,
discount_gift_card, discount_manual, discount_rounding, discount_other,
confirmed_income,
cash_inflow_total, cash_pay_amount,
cash_paper_amount, scan_pay_amount,
groupbuy_pay_amount, platform_settlement_amount, platform_fee_amount,
recharge_cash_inflow,
card_consume_total, recharge_card_consume AS cash_card_consume, gift_card_consume,
cash_outflow_total, cash_balance_change,
recharge_count, recharge_total, recharge_cash, recharge_gift,
first_recharge_count, first_recharge_amount,
renewal_count, renewal_amount,
order_count, member_order_count, guest_order_count, avg_order_amount,
created_at, updated_at
FROM dws.dws_finance_daily_summary
WHERE site_id = (current_setting('app.current_site_id'::text))::bigint;
GRANT SELECT ON app.v_dws_finance_daily_summary TO app_reader;
-- ============================================================
-- 回滚
-- ============================================================
-- DROP VIEW IF EXISTS app.v_dws_finance_daily_summary;
-- ALTER TABLE dws.dws_finance_daily_summary
-- DROP COLUMN IF EXISTS cash_paper_amount,
-- DROP COLUMN IF EXISTS scan_pay_amount;
-- 然后重建原始视图(见 docs/database/ddl/etl_feiqiu__app.sql

View File

@@ -0,0 +1,106 @@
-- 迁移:创建区域日粒度财务原子层表 dws_finance_area_daily 及 RLS 视图
-- 关联board-finance-dws-area-refactor SPEC T2.1
-- 日期2026-03-28
-- 回滚:见文件末尾
-- ============================================================
-- 1. 创建 dws_finance_area_daily 表
-- ============================================================
CREATE TABLE dws.dws_finance_area_daily (
id BIGSERIAL PRIMARY KEY,
site_id BIGINT NOT NULL,
tenant_id BIGINT NOT NULL,
stat_date DATE NOT NULL,
area_code VARCHAR(20) NOT NULL,
-- 收入结构4 项 + gross_amount
table_fee_amount NUMERIC(14,2) NOT NULL DEFAULT 0,
goods_amount NUMERIC(14,2) NOT NULL DEFAULT 0,
assistant_pd_amount NUMERIC(14,2) NOT NULL DEFAULT 0,
assistant_cx_amount NUMERIC(14,2) NOT NULL DEFAULT 0,
gross_amount NUMERIC(14,2) NOT NULL DEFAULT 0,
-- 优惠拆分6 项 + discount_total
-- 恒等式discount_total = groupbuy + vip + manual + gift_card + rounding + other
discount_groupbuy NUMERIC(14,2) NOT NULL DEFAULT 0,
discount_vip NUMERIC(14,2) NOT NULL DEFAULT 0,
discount_manual NUMERIC(14,2) NOT NULL DEFAULT 0,
discount_gift_card NUMERIC(14,2) NOT NULL DEFAULT 0,
discount_rounding NUMERIC(14,2) NOT NULL DEFAULT 0,
discount_other NUMERIC(14,2) NOT NULL DEFAULT 0,
discount_total NUMERIC(14,2) NOT NULL DEFAULT 0,
-- 确认收入gross_amount - discount_total
confirmed_income NUMERIC(14,2) NOT NULL DEFAULT 0,
-- 现金流(仅 area_code='all' 时有效值,其余区域为 0
cash_pay_amount NUMERIC(14,2) NOT NULL DEFAULT 0,
cash_paper_amount NUMERIC(14,2) NOT NULL DEFAULT 0,
scan_pay_amount NUMERIC(14,2) NOT NULL DEFAULT 0,
groupbuy_pay_amount NUMERIC(14,2) NOT NULL DEFAULT 0,
recharge_cash_inflow NUMERIC(14,2) NOT NULL DEFAULT 0,
cash_inflow_total NUMERIC(14,2) NOT NULL DEFAULT 0,
cash_outflow_total NUMERIC(14,2) NOT NULL DEFAULT 0,
cash_balance_change NUMERIC(14,2) NOT NULL DEFAULT 0,
-- 卡消费(仅 area_code='all' 时有效值)
card_consume_total NUMERIC(14,2) NOT NULL DEFAULT 0,
recharge_card_consume NUMERIC(14,2) NOT NULL DEFAULT 0,
gift_card_consume NUMERIC(14,2) NOT NULL DEFAULT 0,
-- 充值(仅 area_code='all' 时有效值)
recharge_cash NUMERIC(14,2) NOT NULL DEFAULT 0,
first_recharge_cash NUMERIC(14,2) NOT NULL DEFAULT 0,
renewal_cash NUMERIC(14,2) NOT NULL DEFAULT 0,
-- 订单统计
order_count INTEGER NOT NULL DEFAULT 0,
-- 元数据
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
-- 唯一约束:每个站点每天每区域一行
UNIQUE (site_id, stat_date, area_code)
);
COMMENT ON TABLE dws.dws_finance_area_daily
IS '区域日粒度财务原子层表,按 (site_id, stat_date, area_code) 存储 9 个区域的收入/优惠/现金流预计算数据';
COMMENT ON COLUMN dws.dws_finance_area_daily.area_code
IS '区域编码all/hall/hallA/hallB/hallC/vip/snooker/mahjong/ktv';
COMMENT ON COLUMN dws.dws_finance_area_daily.gross_amount
IS '毛收入 = table_fee_amount + goods_amount + assistant_pd_amount + assistant_cx_amount';
COMMENT ON COLUMN dws.dws_finance_area_daily.discount_total
IS '优惠合计 = groupbuy + vip + manual + gift_card + rounding + other';
COMMENT ON COLUMN dws.dws_finance_area_daily.confirmed_income
IS '确认收入 = gross_amount - discount_total';
COMMENT ON COLUMN dws.dws_finance_area_daily.discount_gift_card
IS '赠送卡消费金额口径(非结算单 gift_card_amount';
-- ============================================================
-- 2. 创建 RLS 视图
-- ============================================================
CREATE OR REPLACE VIEW dws.v_dws_finance_area_daily AS
SELECT *
FROM dws.dws_finance_area_daily
WHERE site_id = (current_setting('app.current_site_id'::text))::bigint;
GRANT SELECT ON dws.v_dws_finance_area_daily TO app_reader;
-- ============================================================
-- 3. 创建 app schema 导出视图(后端通过 app.v_* 访问)
-- ============================================================
CREATE OR REPLACE VIEW app.v_dws_finance_area_daily AS
SELECT *
FROM dws.dws_finance_area_daily
WHERE site_id = (current_setting('app.current_site_id'::text))::bigint;
GRANT SELECT ON app.v_dws_finance_area_daily TO app_reader;
-- ============================================================
-- 回滚
-- ============================================================
-- DROP VIEW IF EXISTS app.v_dws_finance_area_daily;
-- DROP VIEW IF EXISTS dws.v_dws_finance_area_daily;
-- DROP TABLE IF EXISTS dws.dws_finance_area_daily;

View File

@@ -0,0 +1,102 @@
-- 迁移:创建看板缓存层表 dws_finance_board_cache 及 RLS 视图
-- 关联board-finance-dws-area-refactor SPEC T5.1
-- 日期2026-03-28
-- 回滚:见文件末尾
-- ============================================================
-- 1. 创建 dws_finance_board_cache 表
-- ============================================================
CREATE TABLE dws.dws_finance_board_cache (
id BIGSERIAL PRIMARY KEY,
site_id BIGINT NOT NULL,
time_range VARCHAR(20) NOT NULL,
area_code VARCHAR(20) NOT NULL,
start_date DATE NOT NULL,
end_date DATE NOT NULL,
prev_start_date DATE,
prev_end_date DATE,
-- overview 8 项核心指标
occurrence NUMERIC(14,2) NOT NULL DEFAULT 0,
discount NUMERIC(14,2) NOT NULL DEFAULT 0,
discount_rate NUMERIC(8,4) NOT NULL DEFAULT 0,
confirmed_revenue NUMERIC(14,2) NOT NULL DEFAULT 0,
cash_in NUMERIC(14,2) NOT NULL DEFAULT 0,
cash_out NUMERIC(14,2) NOT NULL DEFAULT 0,
cash_balance NUMERIC(14,2) NOT NULL DEFAULT 0,
balance_rate NUMERIC(8,4) NOT NULL DEFAULT 0,
-- 数据指纹MD5用于检测源数据变化触发缓存失效
data_fingerprint VARCHAR(64),
computed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
-- 元数据
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
-- 唯一约束:每个站点每个时间范围每区域一行
UNIQUE (site_id, time_range, area_code)
);
COMMENT ON TABLE dws.dws_finance_board_cache
IS '看板缓存层表,缓存已完成周期的 overview 聚合结果,按 (site_id, time_range, area_code) 唯一';
COMMENT ON COLUMN dws.dws_finance_board_cache.time_range
IS '时间范围lastMonth/lastWeek/lastQuarter/quarter3/half6仅已完成周期缓存';
COMMENT ON COLUMN dws.dws_finance_board_cache.area_code
IS '区域编码all/hall/hallA/hallB/hallC/vip/snooker/mahjong/ktv';
COMMENT ON COLUMN dws.dws_finance_board_cache.start_date
IS '当期起始日期';
COMMENT ON COLUMN dws.dws_finance_board_cache.end_date
IS '当期结束日期';
COMMENT ON COLUMN dws.dws_finance_board_cache.prev_start_date
IS '上期起始日期(环比用),无上期时为 NULL';
COMMENT ON COLUMN dws.dws_finance_board_cache.prev_end_date
IS '上期结束日期(环比用),无上期时为 NULL';
COMMENT ON COLUMN dws.dws_finance_board_cache.occurrence
IS '发生额(毛收入 gross_amount 的周期汇总)';
COMMENT ON COLUMN dws.dws_finance_board_cache.discount
IS '优惠合计discount_total 的周期汇总)';
COMMENT ON COLUMN dws.dws_finance_board_cache.discount_rate
IS '优惠占比 = discount / occurrence';
COMMENT ON COLUMN dws.dws_finance_board_cache.confirmed_revenue
IS '确认收入 = occurrence - discount';
COMMENT ON COLUMN dws.dws_finance_board_cache.cash_in
IS '现金流入合计(仅 area_code=all 时有效值)';
COMMENT ON COLUMN dws.dws_finance_board_cache.cash_out
IS '现金流出合计(仅 area_code=all 时有效值)';
COMMENT ON COLUMN dws.dws_finance_board_cache.cash_balance
IS '现金余额变动 = cash_in - cash_out';
COMMENT ON COLUMN dws.dws_finance_board_cache.balance_rate
IS '余额变动率';
COMMENT ON COLUMN dws.dws_finance_board_cache.data_fingerprint
IS '源数据指纹MD5用于检测补录导致的数据变化';
COMMENT ON COLUMN dws.dws_finance_board_cache.computed_at
IS '缓存计算时间';
-- ============================================================
-- 2. 创建 RLS 视图
-- ============================================================
CREATE OR REPLACE VIEW dws.v_dws_finance_board_cache AS
SELECT *
FROM dws.dws_finance_board_cache
WHERE site_id = (current_setting('app.current_site_id'::text))::bigint;
GRANT SELECT ON dws.v_dws_finance_board_cache TO app_reader;
-- ============================================================
-- 3. 创建 app schema 导出视图(后端通过 app.v_* 访问)
-- ============================================================
CREATE OR REPLACE VIEW app.v_dws_finance_board_cache AS
SELECT *
FROM dws.dws_finance_board_cache
WHERE site_id = (current_setting('app.current_site_id'::text))::bigint;
GRANT SELECT ON app.v_dws_finance_board_cache TO app_reader;
-- ============================================================
-- 回滚
-- ============================================================
-- DROP VIEW IF EXISTS app.v_dws_finance_board_cache;
-- DROP VIEW IF EXISTS dws.v_dws_finance_board_cache;
-- DROP TABLE IF EXISTS dws.dws_finance_board_cache;

View File

@@ -0,0 +1,13 @@
-- 回滚脚本board-finance-dws-area-refactor
-- 逆序 DROP VIEW → DROP TABLE
-- 日期2026-03-28
--
-- 执行顺序:先删缓存层(依赖日粒度),再删日粒度
-- 1. 删除缓存层 RLS 视图和表
DROP VIEW IF EXISTS dws.v_dws_finance_board_cache;
DROP TABLE IF EXISTS dws.dws_finance_board_cache;
-- 2. 删除日粒度 RLS 视图和表
DROP VIEW IF EXISTS dws.v_dws_finance_area_daily;
DROP TABLE IF EXISTS dws.dws_finance_area_daily;

View File

@@ -0,0 +1,30 @@
-- 关系指数表新增任务统计字段2026-03-31
-- C: 历史总计字段
BEGIN;
ALTER TABLE dws.dws_member_assistant_relation_index
ADD COLUMN IF NOT EXISTS recall_created_total INT NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS recall_completed_total INT NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS follow_up_created_total INT NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS follow_up_completed_total INT NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS total_created INT NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS total_completed INT NOT NULL DEFAULT 0;
COMMENT ON COLUMN dws.dws_member_assistant_relation_index.recall_created_total IS '历史累计召回任务创建数';
COMMENT ON COLUMN dws.dws_member_assistant_relation_index.recall_completed_total IS '历史累计召回任务完成数';
COMMENT ON COLUMN dws.dws_member_assistant_relation_index.follow_up_created_total IS '历史累计回访任务创建数';
COMMENT ON COLUMN dws.dws_member_assistant_relation_index.follow_up_completed_total IS '历史累计回访任务完成数';
COMMENT ON COLUMN dws.dws_member_assistant_relation_index.total_created IS '历史累计任务创建总数';
COMMENT ON COLUMN dws.dws_member_assistant_relation_index.total_completed IS '历史累计任务完成总数';
COMMIT;
-- ROLLBACK:
-- ALTER TABLE dws.dws_member_assistant_relation_index
-- DROP COLUMN IF EXISTS recall_created_total,
-- DROP COLUMN IF EXISTS recall_completed_total,
-- DROP COLUMN IF EXISTS follow_up_created_total,
-- DROP COLUMN IF EXISTS follow_up_completed_total,
-- DROP COLUMN IF EXISTS total_created,
-- DROP COLUMN IF EXISTS total_completed;