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 排除规则
This commit is contained in:
Neo
2026-02-26 08:03:53 +08:00
parent fafc95e64c
commit b25308c3f4
224 changed files with 17660 additions and 32198 deletions

View File

@@ -3,8 +3,6 @@
本文档定义 `dwd` 模式下维度表的 SCD2Slowly Changing Dimension Type 2处理策略、
生效区间管理和版本控制规则。
> **状态**:骨架文档,各维度表的跟踪字段与变更触发条件待补充。
---
## 1. 概述
@@ -17,9 +15,18 @@ SCD2 通过保留维度记录的历史版本来追踪属性变化。当被跟踪
### 1.2 实现模块
- 处理器:`scd/scd2_handler.py``SCD2Handler`
- 核心方法:`upsert(table_name, natural_key, tracked_fields, record, effective_date)`
- 返回值:`INSERT`(新记录)、`UPDATE`(属性变更)、`UNCHANGED`(无变化)
- 处理器:`tasks/dwd/dwd_load_task.py``_merge_dim_scd2()` 方法
- 变更检测:`_is_row_changed()` — 比较所有非 SCD2 控制列,任一列值不同即视为变更
- 批量关闭:`_close_current_dim_bulk()` — 批量设置旧版本的 `scd2_end_time``scd2_is_current = 0`
- 批量插入:`_insert_dim_rows_bulk()` — 批量插入新版本行
### 1.3 变更检测逻辑
`_is_row_changed(current, incoming, dwd_cols)` 遍历目标表的所有列(排除 SCD2 控制列),逐列比较当前版本与新数据。比较时会进行类型归一化处理:
- 空值归一化:`None`、空字符串、`"null"` 视为等价
- 数值归一化:字符串形式的数字与 `Decimal`/`int` 比较前先转换
- 布尔归一化:`"true"`/`"1"`/`"yes"` 等与 `True` 视为等价
- 日期归一化:字符串形式的日期与 `datetime` 比较前先解析
---
@@ -38,103 +45,119 @@ SCD2 通过保留维度记录的历史版本来追踪属性变化。当被跟踪
- 主键:`(natural_key, scd2_start_time)` — 同一自然键的不同版本通过生效时间区分
- 唯一索引:`WHERE scd2_is_current = 1` — 保证每个自然键只有一条当前记录
- 排他约束GiST`tstzrange(scd2_start_time, scd2_end_time)` — 防止同一自然键的版本时间段重叠
---
## 3. 处理流程
```
收到维度记录
_merge_dim_scd2(cur, dwd_table, ods_table, dwd_cols, ods_cols, now)
按 natural_key 查找 valid_to IS NULL 的当前记录
├── 1. 从 ODS 取最新有效版本DISTINCT ON + is_delete IS DISTINCT FROM 1
├── 不存在 → INSERT 新记录is_current=1, valid_from=now
├── 2. 从 DWD 取当前版本scd2_is_current = 1
── 存在 → 比较 tracked_fields
├── 无变化 → UNCHANGED跳过
└── 有变化 → UPDATE 旧记录valid_to=now, is_current=0
INSERT 新记录valid_from=now, is_current=1
── 3. 按自然键逐条比较:
├── DWD 中不存在 → 收集为待插入INSERT
├── 存在但 _is_row_changed() 返回 True → 收集为待更新
├── 关闭旧版本scd2_end_time = now, scd2_is_current = 0
│ │ └── 插入新版本scd2_start_time = now, scd2_is_current = 1, version + 1
│ │
│ └── 存在且无变化 → 跳过UNCHANGED
├── 4. _close_current_dim_bulk() — 批量关闭旧版本
└── 5. _insert_dim_rows_bulk() — 批量插入新版本
```
---
## 4. 维度表 SCD2 配置
> 跟踪字段 = 表中除自然键和 SCD2 控制列(`scd2_start_time`/`scd2_end_time`/`scd2_is_current`/`scd2_version`)之外的所有列。任一跟踪字段值变化即触发新版本。
### 4.1 门店维度dim_site / dim_site_ex
<!-- 待补充:自然键、跟踪字段列表 -->
- Schema`dwd`
- ODS 来源:`ods.table_fee_transactions`(从台费流水中的 `siteProfile` 快照提取)
- 自然键:`site_id`
- 跟踪字段:*(待定义)*
- 变更触发场景:*(待补充)*
- dim_site 跟踪字段:`org_id``tenant_id``shop_name``site_label``full_address``address``longitude``latitude``tenant_site_region_id``business_tel``site_type``shop_status`
- dim_site_ex 跟踪字段:`avatar``address``longitude``latitude``tenant_site_region_id``auto_light``light_status``light_type``light_token``site_type``site_label``attendance_enabled``attendance_distance``customer_service_qrcode``customer_service_wechat``fixed_pay_qrcode``prod_env``shop_status``create_time``update_time`
- 变更触发场景:门店名称/地址/状态/经纬度等基础信息变更
### 4.2 台桌维度dim_table / dim_table_ex
<!-- 待补充:自然键、跟踪字段列表 -->
- Schema`dwd`
- ODS 来源:`ods.site_tables_master`
- 自然键:`table_id`
- 跟踪字段:*(待定义)*
- 变更触发场景:*(待补充)*
- dim_table 跟踪字段:`site_id``table_name``site_table_area_id``site_table_area_name``tenant_table_area_id``table_price``order_id`
- dim_table_ex 跟踪字段:`show_status``is_online_reservation``table_cloth_use_time``table_cloth_use_cycle``table_status``create_time``light_status``tablestatusname``sitename``applet_qr_code_url``audit_status``charge_free``delay_lights_time``is_rest_area``only_allow_groupon``order_delay_time``self_table``temporary_light_second``virtual_table`
- 变更触发场景:台桌名称/区域/价格/状态变更
### 4.3 助教维度dim_assistant / dim_assistant_ex
<!-- 待补充:自然键、跟踪字段列表 -->
- Schema`dwd`
- ODS 来源:`ods.assistant_accounts_master`
- 自然键:`assistant_id`
- 跟踪字段:*(待定义)*
- 变更触发场景:*(待补充)*
- dim_assistant 跟踪字段:`user_id``assistant_no``real_name``nickname``mobile``tenant_id``site_id``team_id``team_name``level``entry_time``resign_time``leave_status``assistant_status`
- dim_assistant_ex 跟踪字段:`gender``birth_date``avatar``introduce``video_introduction_url``height``weight``shop_name``group_id``group_name``person_org_id``staff_id``staff_profile_id``assistant_grade``sum_grade``get_grade_times``charge_way``allow_cx``is_guaranteed``salary_grant_enabled``entry_type``entry_sign_status``resign_sign_status``work_status``show_status``show_sort``online_status``is_delete``criticism_status``create_time``update_time``start_time``end_time``last_table_id``last_table_name``last_update_name``order_trade_no``ding_talk_synced``site_light_cfg_id``light_equipment_id``light_status``is_team_leader``serial_number``system_role_id``job_num``cx_unit_price``pd_unit_price`
- 变更触发场景:助教等级/团队/状态/入职离职/评分等变更
### 4.4 会员维度dim_member / dim_member_ex
<!-- 待补充:自然键、跟踪字段列表 -->
- Schema`dwd`
- ODS 来源:`ods.member_profiles`
- 自然键:`member_id`
- 跟踪字段:*(待定义)*
- 变更触发场景:*(待补充)*
- dim_member 跟踪字段:`system_member_id``tenant_id``register_site_id``mobile``nickname``member_card_grade_code``member_card_grade_name``create_time``update_time``pay_money_sum``recharge_money_sum``birthday`
- dim_member_ex 跟踪字段:`referrer_member_id``point``register_site_name``growth_value``user_status``status``person_tenant_org_id``person_tenant_org_name``register_source`
- 变更触发场景:会员昵称/手机号/卡等级/累计消费充值/状态等变更
### 4.5 会员卡账户维度dim_member_card_account / dim_member_card_account_ex
<!-- 待补充:自然键、跟踪字段列表 -->
- Schema`dwd`
- ODS 来源:`ods.member_stored_value_cards`
- 自然键:`member_card_id`
- 跟踪字段:*(待定义)*
- 变更触发场景:*(待补充)*
- dim_member_card_account 跟踪字段:`tenant_id``register_site_id``tenant_member_id``system_member_id``card_type_id``member_card_grade_code``member_card_grade_code_name``member_card_type_name``member_name``member_mobile``balance``start_time``end_time``last_consume_time``status``is_delete``principal_balance``member_grade`
- dim_member_card_account_ex 跟踪字段60+ 列,含各类折扣比例、抵扣开关等,详见 DDL
- 变更触发场景:卡余额/状态/折扣配置/有效期等变更
### 4.6 商品维度dim_tenant_goods / dim_tenant_goods_ex / dim_store_goods / dim_store_goods_ex
### 4.6 商品维度
<!-- 待补充:自然键、跟踪字段列表 -->
#### 租户商品dim_tenant_goods / dim_tenant_goods_ex
- Schema`dwd`
- 自然键:`tenant_goods_id` / `site_goods_id`
- 跟踪字段:*(待定义)*
- 变更触发场景:*(待补充)*
- ODS 来源:`ods.tenant_goods_master`
- 自然键:`tenant_goods_id`
- dim_tenant_goods 跟踪字段:`tenant_id``supplier_id``category_name``goods_category_id``goods_second_category_id``goods_name``goods_number``unit``market_price``goods_state``create_time``update_time``is_delete``not_sale`
#### 门店商品dim_store_goods / dim_store_goods_ex
- ODS 来源:`ods.store_goods_master`
- 自然键:`site_goods_id`
- dim_store_goods 跟踪字段:`tenant_id``site_id``tenant_goods_id``goods_name``goods_category_id``goods_second_category_id``category_level1_name``category_level2_name``batch_stock_qty``sale_qty``total_sales_qty``sale_price``created_at``updated_at``avg_monthly_sales``goods_state``enable_status``send_state``is_delete``commodity_code``not_sale`
### 4.7 商品分类维度dim_goods_category
<!-- 待补充:自然键、跟踪字段列表 -->
- Schema`dwd`
- ODS 来源:`ods.stock_goods_category_tree`
- 自然键:`category_id`
- 跟踪字段:*(待定义)*
- 变更触发场景:*(待补充)*
- 跟踪字段:`tenant_id``category_name``alias_name``parent_category_id``business_name``tenant_goods_business_id``category_level``is_leaf``open_salesman``sort_order``is_warehousing`
- 变更触发场景:分类名称/层级/排序/启用状态变更
### 4.8 团购套餐维度dim_groupbuy_package / dim_groupbuy_package_ex
<!-- 待补充:自然键、跟踪字段列表 -->
- Schema`dwd`
- ODS 来源:`ods.group_buy_packages`
- 自然键:`groupbuy_package_id`
- 跟踪字段:*(待定义)*
- 变更触发场景:*(待补充)*
- dim_groupbuy_package 跟踪字段:`tenant_id``site_id``package_name``package_template_id``selling_price``coupon_face_value``duration_seconds``start_time``end_time``table_area_name``is_enabled``is_delete``create_time``tenant_table_area_id_list``card_type_ids``sort``is_first_limit`
- 变更触发场景:套餐名称/价格/面值/有效期/启用状态变更
### 4.9 员工维度dim_staff / dim_staff_ex
- ODS 来源:`ods.staff_info_master`
- 自然键:`staff_id`
- dim_staff 跟踪字段:`staff_name``alias_name``mobile``gender``job``tenant_id``site_id``system_role_id``staff_identity``status``leave_status``entry_time``resign_time``is_delete`
- dim_staff_ex 跟踪字段:`avatar``job_num``account_status``rank_id``rank_name``new_rank_id``new_staff_identity``is_reserve``shop_name``site_label``tenant_org_id``system_user_id``cashier_point_id``cashier_point_name``group_id``group_name``staff_profile_id``auth_code``auth_code_create``ding_talk_synced``salary_grant_enabled``entry_type``entry_sign_status``resign_sign_status``criticism_status``create_time``user_roles`
- 变更触发场景:员工姓名/岗位/角色/状态/入职离职等变更
---
@@ -167,9 +190,10 @@ ORDER BY scd2_start_time;
## 6. 注意事项
- **时区**`scd2_start_time` / `scd2_end_time` 使用 `TIMESTAMPTZ`,统一以服务器时区存储
- **时区**`scd2_start_time` / `scd2_end_time` 使用 `TIMESTAMPTZ`,统一以 `Asia/Shanghai` 时区存储
- **并发安全**:当前实现在单次 ETL 运行内串行处理,未做行级锁;并发写入需额外保护
- **删除策略**:维度记录不做物理删除,仅通过关闭版本(`scd2_is_current = 0`)标记失效
- **ODS 来源过滤**:从 ODS 取数时统一使用 `DISTINCT ON (natural_key) ... WHERE is_delete IS DISTINCT FROM 1 ORDER BY natural_key, fetched_at DESC`,确保取最新有效版本
---