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>
This commit is contained in:
52
apps/backend/CLAUDE.md
Normal file
52
apps/backend/CLAUDE.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# CLAUDE.md — Backend (FastAPI)
|
||||
|
||||
进入本目录时自动加载。
|
||||
|
||||
## 架构模式
|
||||
|
||||
### 全局响应包装
|
||||
|
||||
`ResponseWrapperMiddleware` 把所有 2xx 响应包为 `{ "code": 0, "data": <payload> }`。
|
||||
非 2xx 响应保持原样。前端统一通过 `response.data` 解包。
|
||||
|
||||
### 序列化
|
||||
|
||||
`CamelModel` 基类:snake_case → camelCase 自动转换(小程序 API 用)。
|
||||
后端代码始终用 snake_case,JSON 输出自动转驼峰。
|
||||
|
||||
### JWT 双认证
|
||||
|
||||
| 认证方式 | 用途 | 表 | JWT aud |
|
||||
|---------|------|-----|---------|
|
||||
| 用户名+密码 | admin-web 登录 | `auth.admin_users` | `admin` |
|
||||
| 微信 code | 小程序登录 | `auth.users` | `miniapp` |
|
||||
| 用户名+密码 | tenant-admin 登录 | `auth.tenant_admins` | `tenant-admin` |
|
||||
|
||||
待审核用户有 limited token(仅可访问审核状态接口)。
|
||||
|
||||
### AI 集成
|
||||
|
||||
8 个千问应用通过 DashScope SDK:
|
||||
chat / finance / clue / analysis / tactics / note / customer / consolidate
|
||||
|
||||
特性:熔断(连续失败自动断路)、限流(每分钟/每日)、预算追踪、对话缓存。
|
||||
|
||||
### 后台服务(lifespan)
|
||||
|
||||
- `TaskQueue`:按 site_id 消费,FIFO 队列
|
||||
- `Scheduler`:读 `meta.scheduled_tasks` 自动入队
|
||||
- 4 个触发器:日结/月结/工资/关系指数
|
||||
|
||||
### 数据库访问
|
||||
|
||||
- 业务库通过 `APP_DB_DSN` 直连 `zqyy_app`
|
||||
- ETL 数据通过 FDW 映射的 `app.v_*` RLS 视图访问
|
||||
- 查询前必须 `SET LOCAL app.current_site_id = :site_id`
|
||||
|
||||
## 测试
|
||||
|
||||
```bash
|
||||
cd apps/backend && pytest tests/ -v
|
||||
```
|
||||
|
||||
使用测试库(`TEST_APP_DB_DSN`),禁止连正式库。
|
||||
@@ -0,0 +1,60 @@
|
||||
# cfg_skill_type 课程类型配置表
|
||||
|
||||
> 生成时间:2026-03-24
|
||||
|
||||
## 表信息
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| Schema | dws |
|
||||
| 表名 | cfg_skill_type |
|
||||
| 主键 | skill_type_id(自增) |
|
||||
| 唯一键 | skill_id |
|
||||
| 数据来源 | 手工维护,对应飞球系统的课程/技能类型 |
|
||||
| 更新频率 | 按需(新增课程类型时) |
|
||||
| 说明 | 将飞球系统的 skill_id 映射到业务课程分类(BASE/BONUS),供 ETL 到店判定、工资计算、绩效统计使用 |
|
||||
|
||||
## 字段说明
|
||||
|
||||
| 序号 | 字段名 | 类型 | 可空 | 说明 |
|
||||
|------|--------|------|------|------|
|
||||
| 1 | skill_type_id | SERIAL | NO | 自增主键 |
|
||||
| 2 | skill_id | BIGINT | NO | 飞球系统技能 ID(唯一) |
|
||||
| 3 | skill_name | VARCHAR | YES | 技能名称(来自飞球系统) |
|
||||
| 4 | course_type_code | VARCHAR | NO | 课程分类代码:BASE(基础课)/ BONUS(附加课/超休/激励课) |
|
||||
| 5 | course_type_name | VARCHAR | NO | 课程分类中文名 |
|
||||
| 6 | is_active | BOOLEAN | NO | 是否启用(默认 true) |
|
||||
| 7 | description | TEXT | YES | 备注说明 |
|
||||
| 8 | created_at | TIMESTAMPTZ | NO | 创建时间 |
|
||||
| 9 | updated_at | TIMESTAMPTZ | NO | 更新时间 |
|
||||
|
||||
## 当前数据(截至 2026-03-24)
|
||||
|
||||
| skill_id | skill_name | course_type_code | 来源说明 |
|
||||
|----------|-----------|-----------------|---------|
|
||||
| 2790683529513797 | 基础课 | BASE | 飞球系统原始课程类型(2026-03-24 补录) |
|
||||
| 2790683529513798 | 附加课 | BONUS | 飞球系统原始课程类型(2026-03-24 补录) |
|
||||
| 2791903611396869 | 台球基础陪打 | BASE | 初始种子数据 |
|
||||
| 2807440316432197 | 台球超休服务 | BONUS | 初始种子数据 |
|
||||
| 2807440316432198 | 包厢服务 | BASE | 初始种子数据 |
|
||||
| 3039912271463941 | 包厢课 | BASE | 飞球系统原始课程类型(2026-03-24 补录) |
|
||||
|
||||
## 业务口径
|
||||
|
||||
- `course_type_code = 'BONUS'` 用于 WBI/NCI 到店判定:settle_type=3 的商城订单,仅当关联了 BONUS 类型的助教服务记录时才算"到店"
|
||||
- `course_type_code = 'BASE'` 用于基础课工资计算(按助教等级计价)
|
||||
- `course_type_code = 'BONUS'` 用于附加课工资计算(固定 190 元/小时)
|
||||
|
||||
## 下游依赖
|
||||
|
||||
| 消费方 | 用途 |
|
||||
|--------|------|
|
||||
| `member_index_base._build_visit_condition_sql()` | WBI/NCI 到店判定 |
|
||||
| `index_verifier.visit_members` CTE | 指数验证器到店范围 |
|
||||
| 助教工资计算任务 | 区分基础课/附加课计价 |
|
||||
| 助教绩效统计 | 按课程类型分类统计服务时长 |
|
||||
|
||||
## 维护注意事项
|
||||
|
||||
- 飞球系统新增课程类型时,必须同步在此表补录,否则相关订单会被 WBI 到店判定漏掉
|
||||
- 2026-03-24 发现 3 条缺失记录导致 113 名会员、3766 条服务记录的到店判定失效
|
||||
@@ -1,6 +1,6 @@
|
||||
# cfg_area_category 台区分类映射表
|
||||
|
||||
> 生成时间:2026-02-03 | 更新时间:2026-03-09
|
||||
> 生成时间:2026-02-03 | 更新时间:2026-03-20
|
||||
|
||||
## 表信息
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
| 11 | description | TEXT | YES | | 说明 |
|
||||
| 12 | created_at | TIMESTAMPTZ | NO | | 创建时间 |
|
||||
| 13 | updated_at | TIMESTAMPTZ | NO | | 更新时间 |
|
||||
| 14 | sort_order | INTEGER | NO | | 前端筛选器显示排序(值越小越靠前),DEFAULT 100 |
|
||||
|
||||
## 变更说明(2026-03-09)
|
||||
|
||||
@@ -108,6 +109,7 @@
|
||||
| 2026-02-03 | 初始创建,区域级精确 + LIKE 模糊匹配 |
|
||||
| 2026-03-07 | 新增 source_table_name 支持台桌级细分;废弃 BILLIARD_VIP |
|
||||
| 2026-03-09 | 改为纯台桌级精确映射,删除所有 LIKE 和区域级映射 |
|
||||
| 2026-03-20 | 新增 sort_order 字段,控制前端筛选器分类显示排序 |
|
||||
|
||||
## 验证 SQL
|
||||
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
# dws_finance_area_daily 区域日粒度财务原子层表
|
||||
|
||||
> 生成时间:2026-03-28
|
||||
> 关联 SPEC:board-finance-dws-area-refactor
|
||||
|
||||
## 表信息
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| Schema | dws |
|
||||
| 表名 | dws_finance_area_daily |
|
||||
| 主键 | id |
|
||||
| 唯一键 | (site_id, stat_date, area_code) |
|
||||
| 数据来源 | dwd_settlement_head + dim_table + dws_finance_daily_summary |
|
||||
| 更新频率 | 每小时更新当日数据 |
|
||||
| 幂等策略 | delete-before-insert(按 site_id + stat_date 删除后插入 9 行) |
|
||||
| 说明 | 按 (site_id, stat_date, area_code) 粒度存储 9 个区域的收入/优惠/现金流预计算数据 |
|
||||
|
||||
## 字段说明
|
||||
|
||||
| 序号 | 字段名 | 类型 | 可空 | 说明 |
|
||||
|------|--------|------|------|------|
|
||||
| 1 | id | BIGSERIAL | NO | 自增主键 |
|
||||
| 2 | site_id | BIGINT | NO | 门店ID |
|
||||
| 3 | tenant_id | BIGINT | NO | 租户ID |
|
||||
| 4 | stat_date | DATE | NO | 统计日期(营业日,按 BUSINESS_DAY_START_HOUR=8 切点) |
|
||||
| 5 | area_code | VARCHAR(20) | NO | 区域编码:all/hall/hallA/hallB/hallC/vip/snooker/mahjong/ktv |
|
||||
| 6 | table_fee_amount | NUMERIC(14,2) | NO | 台费正价 |
|
||||
| 7 | goods_amount | NUMERIC(14,2) | NO | 商品正价 |
|
||||
| 8 | assistant_pd_amount | NUMERIC(14,2) | NO | 助教基础课正价(陪打) |
|
||||
| 9 | assistant_cx_amount | NUMERIC(14,2) | NO | 助教激励课正价(超休) |
|
||||
| 10 | gross_amount | NUMERIC(14,2) | NO | 毛收入 = 四项之和 |
|
||||
| 11 | discount_groupbuy | NUMERIC(14,2) | NO | 团购优惠 |
|
||||
| 12 | discount_vip | NUMERIC(14,2) | NO | 会员折扣 |
|
||||
| 13 | discount_manual | NUMERIC(14,2) | NO | 手动调整(adjust_amount) |
|
||||
| 14 | discount_gift_card | NUMERIC(14,2) | NO | 赠送卡消费金额口径 |
|
||||
| 15 | discount_rounding | NUMERIC(14,2) | NO | 抹零 |
|
||||
| 16 | discount_other | NUMERIC(14,2) | NO | 其他优惠 |
|
||||
| 17 | discount_total | NUMERIC(14,2) | NO | 优惠合计 = 六项之和 |
|
||||
| 18 | confirmed_income | NUMERIC(14,2) | NO | 确认收入 = gross_amount - discount_total |
|
||||
| 19 | cash_pay_amount | NUMERIC(14,2) | NO | 收银实付(仅 all 行有效) |
|
||||
| 20 | cash_paper_amount | NUMERIC(14,2) | NO | 纸币支付(仅 all 行有效) |
|
||||
| 21 | scan_pay_amount | NUMERIC(14,2) | NO | 扫码支付(仅 all 行有效) |
|
||||
| 22 | groupbuy_pay_amount | NUMERIC(14,2) | NO | 团购支付金额(仅 all 行有效) |
|
||||
| 23 | recharge_cash_inflow | NUMERIC(14,2) | NO | 充值现金流入(仅 all 行有效) |
|
||||
| 24 | cash_inflow_total | NUMERIC(14,2) | NO | 现金流入合计(仅 all 行有效) |
|
||||
| 25 | cash_outflow_total | NUMERIC(14,2) | NO | 现金流出合计(仅 all 行有效) |
|
||||
| 26 | cash_balance_change | NUMERIC(14,2) | NO | 现金余额变动(仅 all 行有效) |
|
||||
| 27 | card_consume_total | NUMERIC(14,2) | NO | 卡消费合计(仅 all 行有效) |
|
||||
| 28 | recharge_card_consume | NUMERIC(14,2) | NO | 充值卡消费(仅 all 行有效) |
|
||||
| 29 | gift_card_consume | NUMERIC(14,2) | NO | 赠送卡消费(仅 all 行有效) |
|
||||
| 30 | recharge_cash | NUMERIC(14,2) | NO | 充值现金(仅 all 行有效) |
|
||||
| 31 | first_recharge_cash | NUMERIC(14,2) | NO | 首充现金(仅 all 行有效) |
|
||||
| 32 | renewal_cash | NUMERIC(14,2) | NO | 续充现金(仅 all 行有效) |
|
||||
| 33 | order_count | INTEGER | NO | 结账单数 |
|
||||
| 34 | created_at | TIMESTAMPTZ | NO | 创建时间 |
|
||||
| 35 | updated_at | TIMESTAMPTZ | NO | 更新时间 |
|
||||
|
||||
|
||||
## 约束与索引
|
||||
|
||||
| 约束/索引 | 类型 | 列 |
|
||||
|-----------|------|-----|
|
||||
| dws_finance_area_daily_pkey | PRIMARY KEY | id |
|
||||
| dws_finance_area_daily_site_id_stat_date_area_code_key | UNIQUE | (site_id, stat_date, area_code) |
|
||||
|
||||
## RLS 视图
|
||||
|
||||
```sql
|
||||
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;
|
||||
```
|
||||
|
||||
## 数学恒等式
|
||||
|
||||
```
|
||||
gross_amount = table_fee_amount + goods_amount + assistant_pd_amount + assistant_cx_amount
|
||||
discount_total = discount_groupbuy + discount_vip + discount_manual + discount_gift_card + discount_rounding + discount_other
|
||||
confirmed_income = gross_amount - discount_total
|
||||
```
|
||||
|
||||
- `area_code ≠ 'all'` 时:现金流/卡消费/充值字段 = 0
|
||||
- `all` 行收入/优惠 = hallA~ktv 各行对应字段之和
|
||||
- `hall` 行 = hallA~ktv 各行之和(历史兼容)
|
||||
- 每个 (site_id, stat_date) 恰好 9 行
|
||||
|
||||
## 变更原因
|
||||
|
||||
解决财务看板在 `area≠all` 时优惠数据从全局 DWS 表取数导致区域级优惠占比严重失真的 bug(如 B区优惠占比 417.9%)。
|
||||
|
||||
## 兼容性影响
|
||||
|
||||
| 组件 | 影响 |
|
||||
|------|------|
|
||||
| ETL 任务 | 新增 DWS_FINANCE_AREA_DAILY 任务,依赖 DWD_LOAD_FROM_ODS |
|
||||
| 后端 API | board_service.py 改为从本表查询 overview/revenue 板块数据 |
|
||||
| 小程序 | 无直接影响(API 签名不变) |
|
||||
| dws_finance_daily_summary | 不改动,本表的 all 行现金流/充值/卡消费复用其数据 |
|
||||
|
||||
## 回滚策略
|
||||
|
||||
```sql
|
||||
DROP VIEW IF EXISTS dws.v_dws_finance_area_daily;
|
||||
DROP TABLE IF EXISTS dws.dws_finance_area_daily;
|
||||
```
|
||||
|
||||
回滚后后端需恢复到从 `dws_finance_daily_summary` 取数的旧逻辑。
|
||||
|
||||
## 验证 SQL
|
||||
|
||||
```sql
|
||||
-- 1. 验证表存在且有数据
|
||||
SELECT COUNT(*), COUNT(DISTINCT area_code), MIN(stat_date), MAX(stat_date)
|
||||
FROM dws.dws_finance_area_daily
|
||||
WHERE site_id = 1;
|
||||
|
||||
-- 2. 验证每天恰好 9 行
|
||||
SELECT stat_date, COUNT(*) AS row_count
|
||||
FROM dws.dws_finance_area_daily
|
||||
WHERE site_id = 1
|
||||
GROUP BY stat_date
|
||||
HAVING COUNT(*) != 9
|
||||
ORDER BY stat_date;
|
||||
|
||||
-- 3. 验证收入恒等式
|
||||
SELECT stat_date, area_code,
|
||||
gross_amount,
|
||||
(table_fee_amount + goods_amount + assistant_pd_amount + assistant_cx_amount) AS calc_gross,
|
||||
gross_amount - (table_fee_amount + goods_amount + assistant_pd_amount + assistant_cx_amount) AS diff
|
||||
FROM dws.dws_finance_area_daily
|
||||
WHERE site_id = 1
|
||||
AND gross_amount != (table_fee_amount + goods_amount + assistant_pd_amount + assistant_cx_amount);
|
||||
|
||||
-- 4. 验证优惠恒等式
|
||||
SELECT stat_date, area_code,
|
||||
discount_total,
|
||||
(discount_groupbuy + discount_vip + discount_manual + discount_gift_card + discount_rounding + discount_other) AS calc_disc,
|
||||
discount_total - (discount_groupbuy + discount_vip + discount_manual + discount_gift_card + discount_rounding + discount_other) AS diff
|
||||
FROM dws.dws_finance_area_daily
|
||||
WHERE site_id = 1
|
||||
AND discount_total != (discount_groupbuy + discount_vip + discount_manual + discount_gift_card + discount_rounding + discount_other);
|
||||
|
||||
-- 5. 验证非 all 行现金流为零
|
||||
SELECT stat_date, area_code, cash_inflow_total, cash_outflow_total
|
||||
FROM dws.dws_finance_area_daily
|
||||
WHERE site_id = 1
|
||||
AND area_code != 'all'
|
||||
AND (cash_inflow_total != 0 OR cash_outflow_total != 0);
|
||||
```
|
||||
|
||||
## 可回溯性
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| 可回溯 | ✅ 完全可回溯(delete-before-insert) |
|
||||
| 数据范围 | 2025-07-16 ~ 至今 |
|
||||
| 依赖表 | dwd_settlement_head, dim_table, dws_finance_daily_summary |
|
||||
| 回填脚本 | `scripts/ops/backfill_finance_area_daily.py` |
|
||||
@@ -0,0 +1,121 @@
|
||||
# dws_finance_board_cache 看板缓存层表
|
||||
|
||||
> 生成时间:2026-03-28
|
||||
> 关联 SPEC:board-finance-dws-area-refactor
|
||||
|
||||
## 表信息
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| Schema | dws |
|
||||
| 表名 | dws_finance_board_cache |
|
||||
| 主键 | id |
|
||||
| 唯一键 | (site_id, time_range, area_code) |
|
||||
| 数据来源 | dws_finance_area_daily(日粒度原子层) |
|
||||
| 更新频率 | 每天一次(营业日切点后) |
|
||||
| 幂等策略 | ON CONFLICT (site_id, time_range, area_code) DO UPDATE |
|
||||
| 说明 | 缓存已完成周期的 overview 聚合结果,避免重复 SUM 计算 |
|
||||
|
||||
## 字段说明
|
||||
|
||||
| 序号 | 字段名 | 类型 | 可空 | 说明 |
|
||||
|------|--------|------|------|------|
|
||||
| 1 | id | BIGSERIAL | NO | 自增主键 |
|
||||
| 2 | site_id | BIGINT | NO | 门店ID |
|
||||
| 3 | time_range | VARCHAR(20) | NO | 时间范围:lastMonth/lastWeek/lastQuarter/quarter3/half6 |
|
||||
| 4 | area_code | VARCHAR(20) | NO | 区域编码:all/hall/hallA/hallB/hallC/vip/snooker/mahjong/ktv |
|
||||
| 5 | start_date | DATE | NO | 当期起始日期 |
|
||||
| 6 | end_date | DATE | NO | 当期结束日期 |
|
||||
| 7 | prev_start_date | DATE | YES | 上期起始日期(环比用) |
|
||||
| 8 | prev_end_date | DATE | YES | 上期结束日期(环比用) |
|
||||
| 9 | occurrence | NUMERIC(14,2) | NO | 发生额(gross_amount 周期汇总) |
|
||||
| 10 | discount | NUMERIC(14,2) | NO | 优惠合计(discount_total 周期汇总) |
|
||||
| 11 | discount_rate | NUMERIC(8,4) | NO | 优惠占比 = discount / occurrence |
|
||||
| 12 | confirmed_revenue | NUMERIC(14,2) | NO | 确认收入 = occurrence - discount |
|
||||
| 13 | cash_in | NUMERIC(14,2) | NO | 现金流入合计(仅 area_code=all 有效) |
|
||||
| 14 | cash_out | NUMERIC(14,2) | NO | 现金流出合计(仅 area_code=all 有效) |
|
||||
| 15 | cash_balance | NUMERIC(14,2) | NO | 现金余额变动 = cash_in - cash_out |
|
||||
| 16 | balance_rate | NUMERIC(8,4) | NO | 余额变动率 = cash_balance / cash_in |
|
||||
| 17 | data_fingerprint | VARCHAR(64) | YES | 源数据 MD5 指纹,用于检测补录导致的数据变化 |
|
||||
| 18 | computed_at | TIMESTAMPTZ | NO | 缓存计算时间 |
|
||||
| 19 | created_at | TIMESTAMPTZ | NO | 创建时间 |
|
||||
| 20 | updated_at | TIMESTAMPTZ | NO | 更新时间 |
|
||||
|
||||
## 约束与索引
|
||||
|
||||
| 约束/索引 | 类型 | 列 |
|
||||
|-----------|------|-----|
|
||||
| dws_finance_board_cache_pkey | PRIMARY KEY | id |
|
||||
| dws_finance_board_cache_site_id_time_range_area_code_key | UNIQUE | (site_id, time_range, area_code) |
|
||||
|
||||
## RLS 视图
|
||||
|
||||
```sql
|
||||
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;
|
||||
```
|
||||
|
||||
## 缓存策略
|
||||
|
||||
- 已完成周期(缓存):lastMonth, lastWeek, lastQuarter, quarter3, half6
|
||||
- 当期周期(不缓存):month, week, quarter
|
||||
- 失效条件:`data_fingerprint` 变化(补录导致源数据变化)
|
||||
- 指纹算法:`MD5(sorted [(stat_date, gross_amount, discount_total), ...])`
|
||||
|
||||
## 变更原因
|
||||
|
||||
为已完成周期的聚合结果提供缓存,避免每次查询都从日粒度表 SUM 计算。通过数据指纹机制自动检测补录导致的数据变化并重算。
|
||||
|
||||
## 兼容性影响
|
||||
|
||||
| 组件 | 影响 |
|
||||
|------|------|
|
||||
| ETL 任务 | 新增 DWS_FINANCE_BOARD_CACHE 任务,依赖 DWS_FINANCE_AREA_DAILY |
|
||||
| 后端 API | board_service.py 已完成周期先查缓存,未命中从日粒度表 SUM |
|
||||
| 小程序 | 无直接影响(API 签名不变) |
|
||||
|
||||
## 回滚策略
|
||||
|
||||
```sql
|
||||
DROP VIEW IF EXISTS dws.v_dws_finance_board_cache;
|
||||
DROP TABLE IF EXISTS dws.dws_finance_board_cache;
|
||||
```
|
||||
|
||||
回滚后后端需移除缓存查询逻辑,改为每次从日粒度表 SUM。
|
||||
|
||||
## 验证 SQL
|
||||
|
||||
```sql
|
||||
-- 1. 验证表存在且有数据
|
||||
SELECT COUNT(*), COUNT(DISTINCT time_range), COUNT(DISTINCT area_code)
|
||||
FROM dws.dws_finance_board_cache
|
||||
WHERE site_id = 1;
|
||||
|
||||
-- 2. 验证唯一约束生效(应返回 0 行)
|
||||
SELECT site_id, time_range, area_code, COUNT(*)
|
||||
FROM dws.dws_finance_board_cache
|
||||
GROUP BY site_id, time_range, area_code
|
||||
HAVING COUNT(*) > 1;
|
||||
|
||||
-- 3. 验证 confirmed_revenue = occurrence - discount
|
||||
SELECT time_range, area_code,
|
||||
occurrence, discount, confirmed_revenue,
|
||||
(occurrence - discount) AS expected
|
||||
FROM dws.dws_finance_board_cache
|
||||
WHERE site_id = 1
|
||||
AND ABS(confirmed_revenue - (occurrence - discount)) > 0.01;
|
||||
|
||||
-- 4. 验证当期周期不在缓存中
|
||||
SELECT * FROM dws.dws_finance_board_cache
|
||||
WHERE time_range IN ('month', 'week', 'quarter');
|
||||
```
|
||||
|
||||
## 可回溯性
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| 可回溯 | ✅ 完全可回溯(upsert 幂等) |
|
||||
| 数据范围 | 取决于 dws_finance_area_daily 的数据范围 |
|
||||
| 依赖表 | dws_finance_area_daily |
|
||||
| 回填脚本 | `scripts/ops/backfill_finance_area_daily.py`(阶段 2 自动重算缓存) |
|
||||
Reference in New Issue
Block a user