Files
Neo b25308c3f4 feat: P1-P3 全栈集成 — 数据库基础 + DWS 扩展 + 小程序鉴权 + 工程化体系
## P1 数据库基础
- zqyy_app: 创建 auth/biz schema、FDW 连接 etl_feiqiu
- etl_feiqiu: 创建 app schema RLS 视图、商品库存预警表
- 清理 assistant_abolish 残留数据

## P2 ETL/DWS 扩展
- 新增 DWS 助教订单贡献度表 (dws.assistant_order_contribution)
- 新增 assistant_order_contribution_task 任务及 RLS 视图
- member_consumption 增加充值字段、assistant_daily 增加处罚字段
- 更新 ODS/DWD/DWS 任务文档及业务规则文档
- 更新 consistency_checker、flow_runner、task_registry 等核心模块

## P3 小程序鉴权系统
- 新增 xcx_auth 路由/schema(微信登录 + JWT)
- 新增 wechat/role/matching/application 服务层
- zqyy_app 鉴权表迁移 + 角色权限种子数据
- auth/dependencies.py 支持小程序 JWT 鉴权

## 文档与审计
- 新增 DOCUMENTATION-MAP 文档导航
- 新增 7 份 BD_Manual 数据库变更文档
- 更新 DDL 基线快照(etl_feiqiu 6 schema + zqyy_app auth)
- 新增全栈集成审计记录、部署检查清单更新
- 新增 BACKLOG 路线图、FDW→Core 迁移计划

## Kiro 工程化
- 新增 5 个 Spec(P1/P2/P3/全栈集成/核心业务)
- 新增审计自动化脚本(agent_on_stop/build_audit_context/compliance_prescan)
- 新增 6 个 Hook(合规检查/会话日志/提交审计等)
- 新增 doc-map steering 文件

## 运维与测试
- 新增 ops 脚本:迁移验证/API 健康检查/ETL 监控/集成报告
- 新增属性测试:test_dws_contribution / test_auth_system
- 清理过期 export 报告文件
- 更新 .gitignore 排除规则
2026-02-26 08:03:53 +08:00

158 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 需求文档ETL DWS 层扩展 — 小程序数据支撑
## 简介
本 Spec 覆盖 P2 任务中 T4T11 的 ETL DWS 层扩展,为小程序提供三类核心数据支撑:
1. 助教订单流水四项统计(`dws_assistant_order_contribution`
2. 会员消费汇总扩展(充值窗口 + 次均消费)
3. 定档折算惩罚检测与计算
同时包含新表的 RLS 视图创建、FDW 映射同步,以及影子跑数验证。
> SPI 消费力指数T1T3已在独立 Spec `.kiro/specs/spi-spending-power-index/` 中完成,本文档不再重复。
## 术语表
- **AssistantOrderContributionTask**:助教订单流水统计 ETL 任务,粒度 `(site_id, assistant_id, stat_date)`
- **MemberConsumptionTask**:会员消费汇总 ETL 任务,粒度 `(site_id, member_id, stat_date)`
- **AssistantDailyTask**:助教日度业绩明细 ETL 任务,粒度 `(site_id, assistant_id, stat_date)`
- **dws_assistant_order_contribution**:助教订单流水四项统计结果表
- **dws_member_consumption_summary**:会员消费汇总表(已有,需扩展字段)
- **dws_assistant_daily_detail**:助教日度业绩明细表(已有,需扩展字段)
- **order_gross_revenue**:订单总流水 — 助教参与订单的全部流水(台费 + 酒水食品 + 助教服务费)
- **order_net_revenue**:订单净流水 — 订单总流水 - 该订单所有助教的服务分成总额
- **time_weighted_revenue**:时效贡献流水 — 按助教个人服务时长折算的订单金额贡献
- **time_weighted_net_revenue**:时效净贡献 — 时效贡献流水 - 该助教个人的服务分成
- **penalty_minutes**:定档折算惩罚分钟数 — 因违规被扣减的定档业绩时长
- **per_hour_contribution**:单人每小时贡献流水 — 台费/房费每小时实收单价 ÷ 本次基础课助教人数
- **RLS 视图**:行级安全视图,位于 ETL 库 `app` schema`site_id` 隔离数据
- **FDW 映射**:外部数据包装器映射,将 ETL 库表映射到业务库 `fdw_etl` schema
- **settle_type**结算类型1=台桌结账3=商城订单5=充值订单
- **BaseDwsTask**DWS 层任务基类,提供 delete-before-insert 幂等机制
- **delete-before-insert**:幂等更新策略,先按条件删除旧记录再批量插入新记录
## 需求
### 需求 1助教订单流水统计表创建T4
**用户故事:** 作为 ETL 开发者,我需要创建助教订单流水四项统计表,以便存储每名助教每日的订单流水贡献数据。
#### 验收标准
1. THE 开发者 SHALL 创建 `dws.dws_assistant_order_contribution` 表,主键为 `(site_id, assistant_id, stat_date)`
2. THE dws_assistant_order_contribution 表 SHALL 包含四项统计字段:`order_gross_revenue`(订单总流水)、`order_net_revenue`(订单净流水)、`time_weighted_revenue`(时效贡献流水)、`time_weighted_net_revenue`(时效净贡献),精度为 `NUMERIC(14,2)`
3. THE dws_assistant_order_contribution 表 SHALL 包含辅助字段:`order_count`(参与订单数)、`total_service_seconds`(总服务时长秒数)、`assistant_nickname`(助教昵称)
4. THE dws_assistant_order_contribution 表 SHALL 包含元数据字段:`tenant_id``created_at``updated_at`
5. THE 开发者 SHALL 编写迁移脚本 `db/etl_feiqiu/migrations/<日期>__create_dws_assistant_order_contribution.sql`,在测试库 `test_etl_feiqiu` 中执行建表
6. WHEN DDL 在测试库执行成功后THE 开发者 SHALL 运行 `gen_consolidated_ddl.py` 导出最新 DDL
### 需求 2助教订单流水四项统计计算T5
**用户故事:** 作为产品经理,我需要助教订单流水四项统计(订单总流水/订单净流水/时效贡献流水/时效净贡献),以便评估助教个人能力。
#### 验收标准
1. THE AssistantOrderContributionTask SHALL 从 `dwd.dwd_settlement_head``dwd.dwd_table_fee_log``dwd.dwd_assistant_service_log` 提取订单、台费和助教服务数据
2. WHEN 计算 order_gross_revenue 时THE AssistantOrderContributionTask SHALL 将助教参与订单的全部流水(台费 + 酒水食品 + 所有助教服务费)累加,每个参与助教获得相同的订单总流水值
3. WHEN 计算 order_net_revenue 时THE AssistantOrderContributionTask SHALL 从订单总流水中减去该订单所有助教的服务分成总额,每个参与助教获得相同的订单净流水值
4. WHEN 计算 time_weighted_revenue 时THE AssistantOrderContributionTask SHALL 按以下步骤折算个人贡献:
- 确定每张台桌的有效计费时长:取 MAX(该台桌所有助教服务时长之和, 台桌使用时长)
- 按助教在该台桌的服务时长占比分摊台费
- 助教个人服务费直接计入
- 酒水食品按助教个人服务总时长占所有助教服务总时长的比例均分
5. WHEN 计算 time_weighted_net_revenue 时THE AssistantOrderContributionTask SHALL 从该助教的时效贡献流水中减去该助教个人的服务分成
6. WHEN 助教为超休/打赏课类型时THE AssistantOrderContributionTask SHALL 将四项统计均设为该助教个人的服务流水和分成(不参与订单级分摊)
7. THE AssistantOrderContributionTask SHALL 以任务代码 `DWS_ASSISTANT_ORDER_CONTRIBUTION` 注册到 task_registry
8. THE AssistantOrderContributionTask SHALL 采用 delete-before-insert 策略按日期窗口幂等更新
### 需求 3会员消费汇总扩展T6
**用户故事:** 作为产品经理,我需要客户 30/60/90 天充值次数和金额、次均消费,以便在客户看板中展示。
#### 验收标准
1. THE 开发者 SHALL 在 `dws.dws_member_consumption_summary` 表中新增以下字段:`recharge_count_30d``recharge_count_60d``recharge_count_90d`充值次数INTEGER`recharge_amount_30d``recharge_amount_60d``recharge_amount_90d`充值金额NUMERIC(14,2))、`avg_ticket_amount`次均消费额度NUMERIC(14,2)
2. THE 开发者 SHALL 编写 ALTER TABLE 迁移脚本在测试库 `test_etl_feiqiu` 中执行字段扩展
3. THE 充值数据 SHALL 从 `dwd.dwd_recharge_order` 提取,按 `member_id` 和时间窗口聚合
4. THE avg_ticket_amount SHALL 按公式 `total_consume_amount / MAX(total_visit_count, 1)` 计算
### 需求 4会员消费汇总任务修改T7
**用户故事:** 作为 ETL 开发者,我需要修改 MemberConsumptionTask 以填充新增的充值窗口和次均消费字段。
#### 验收标准
1. THE MemberConsumptionTask SHALL 在 extract 阶段新增充值订单提取逻辑,从 `dwd.dwd_recharge_order` 按 30/60/90 天窗口聚合充值次数和金额
2. THE MemberConsumptionTask SHALL 在 transform 阶段将充值统计和次均消费填充到输出记录中
3. WHEN 会员无充值记录时THE MemberConsumptionTask SHALL 将充值次数设为 0、充值金额设为 0.00
4. WHEN 会员无消费记录时THE MemberConsumptionTask SHALL 将 avg_ticket_amount 设为 0.00
### 需求 5助教日度明细表扩展 — 定档折算惩罚字段T8
**用户故事:** 作为 ETL 开发者,我需要在助教日度明细表中新增定档折算惩罚相关字段,以便存储惩罚检测和计算结果。
#### 验收标准
1. THE 开发者 SHALL 在 `dws.dws_assistant_daily_detail` 表中新增以下字段:`penalty_minutes` (NUMERIC(10,2))、`penalty_reason` (TEXT)、`is_exempt` (BOOLEAN DEFAULT FALSE)、`per_hour_contribution` (NUMERIC(14,2))
2. THE 开发者 SHALL 编写 ALTER TABLE 迁移脚本在测试库 `test_etl_feiqiu` 中执行字段扩展
3. WHEN 助教当日无惩罚时THE penalty_minutes SHALL 为 0penalty_reason SHALL 为 NULL
### 需求 6定档折算惩罚检测与计算逻辑T9
**用户故事:** 作为产品经理,我需要定档折算惩罚数据,以便在绩效页面展示折算详情,防止助教利用低价订单冲档位。
#### 验收标准
1. THE AssistantDailyTask SHALL 检测规则 2 违规:在指定区域(大厅 A/B/C/S/TV 和麻将房 M1M7同一台桌同一时间段超过 2 名助教挂台(课程时间段有重叠即算)
2. WHEN 检测到违规时THE AssistantDailyTask SHALL 计算单人每小时贡献流水:台费/房费每小时实收单价 ÷ 本次基础课助教人数
3. WHEN per_hour_contribution >= 24 元时THE AssistantDailyTask SHALL 按满额计入定档业绩时长penalty_minutes = 0
4. WHEN per_hour_contribution < 24 元时THE AssistantDailyTask SHALL 按比例折算:`penalty_minutes = 实际服务分钟数 × (1 - per_hour_contribution / 24)`
5. WHEN 订单标记为 is_exempt = TRUE 时THE AssistantDailyTask SHALL 跳过惩罚计算penalty_minutes 设为 0
6. THE 定档折算惩罚 SHALL 仅影响定档业绩时长统计,不影响实际工资时长
7. THE AssistantDailyTask SHALL 每日自动计算惩罚,计算频率与现有日度任务一致
### 需求 7RLS 视图创建T10
**用户故事:** 作为 ETL 开发者,我需要为新表创建 RLS 视图,以便通过 FDW 安全地向业务库暴露数据。
#### 验收标准
1. THE 开发者 SHALL 在 ETL 库 `app` schema 中为 `dws_assistant_order_contribution` 创建 RLS 视图,按 `site_id` 过滤
2. THE 开发者 SHALL 更新已有 RLS 视图以包含 `dws_member_consumption_summary``dws_assistant_daily_detail` 的新增字段
3. THE RLS 视图 SHALL 使用 `current_setting('app.current_site_id')::INTEGER` 进行行级过滤
### 需求 8FDW 映射同步T10
**用户故事:** 作为后端开发者,我需要在业务库中通过 FDW 访问新建和扩展的 ETL 表,以便小程序后端读取数据。
#### 验收标准
1. THE 开发者 SHALL 在 `test_zqyy_app.fdw_etl` schema 中创建 `dws_assistant_order_contribution` 的外部表映射
2. THE 开发者 SHALL 更新 `dws_member_consumption_summary``dws_assistant_daily_detail` 的 FDW 映射以包含新增字段
3. THE FDW 映射 SHALL 通过 `app` schema 的 RLS 视图访问数据,而非直接访问 `dws` schema
### 需求 9影子跑数验证T11
**用户故事:** 作为 ETL 开发者,我需要通过影子跑数验证新增统计的正确性,以便确保数据质量。
#### 验收标准
1. THE 开发者 SHALL 编写验证脚本,对照 PRD 示例数据验算四项统计的计算结果
2. THE 验证脚本 SHALL 检查 `dws_assistant_order_contribution` 中四项统计数值的一致性order_gross_revenue 各助教相等、order_net_revenue 各助教相等、time_weighted_revenue 各助教之和加上误差容忍度等于订单总流水
3. THE 验证脚本 SHALL 检查 `dws_member_consumption_summary` 新增字段有值且充值金额与 `dwd_recharge_order` 源数据一致
4. THE 验证脚本 SHALL 检查定档折算惩罚字段在符合惩罚条件的记录上正确填充
### 需求 10算法正确性测试
**用户故事:** 作为 ETL 开发者我需要通过属性测试hypothesis验证四项统计和惩罚计算的正确性。
#### 验收标准
1. THE 属性测试 SHALL 验证:对于任意订单,所有参与助教的 order_gross_revenue 值相等
2. THE 属性测试 SHALL 验证:对于任意订单,所有参与助教的 order_net_revenue 值相等
3. THE 属性测试 SHALL 验证:对于任意订单,所有参与助教的 time_weighted_revenue 之和应在订单总流水的合理误差范围内±0.01 元)
4. THE 属性测试 SHALL 验证对于任意助教time_weighted_net_revenue = time_weighted_revenue - 该助教个人服务分成
5. THE 属性测试 SHALL 验证:对于任意 per_hour_contribution >= 24 的记录penalty_minutes 为 0
6. THE 属性测试 SHALL 验证:对于任意 per_hour_contribution < 24 且 per_hour_contribution >= 0 的记录penalty_minutes = 实际分钟数 × (1 - per_hour_contribution / 24)
7. THE 属性测试 SHALL 验证对于任意会员avg_ticket_amount = total_consume_amount / MAX(total_visit_count, 1)