init: 项目初始提交 - NeoZQYY Monorepo 完整代码
This commit is contained in:
1
.kiro/specs/bd-manual-docs-consolidation/.config.kiro
Normal file
1
.kiro/specs/bd-manual-docs-consolidation/.config.kiro
Normal file
@@ -0,0 +1 @@
|
||||
{"generationMode": "requirements-first"}
|
||||
311
.kiro/specs/bd-manual-docs-consolidation/design.md
Normal file
311
.kiro/specs/bd-manual-docs-consolidation/design.md
Normal file
@@ -0,0 +1,311 @@
|
||||
# 设计文档:数据库文档整理与补全
|
||||
|
||||
## 概述
|
||||
|
||||
本特性对 `docs/bd_manual/` 目录进行系统性整理和补全,涵盖四个核心工作流:
|
||||
|
||||
1. **目录结构规范化** — 统一各层目录布局,新增 `ETL_Admin/` 层和根目录 `README.md` 索引
|
||||
2. **DDL 对比同步** — 编写 Python 脚本对比四个 schema 的 DDL 文件与数据库实际状态,以数据库为准修正 DDL
|
||||
3. **ODS 表级文档补全** — 为 `billiards` schema 下所有 ODS 表生成 Markdown 表级文档
|
||||
4. **API→ODS 字段映射文档** — 建立 API JSON 响应到 ODS 表字段的映射关系文档
|
||||
|
||||
本特性以文档和 DDL 维护为主,不涉及业务代码逻辑变更。DDL 修正属于 `database/` 高风险路径,完成后需触发 `/audit`。
|
||||
|
||||
## 架构
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph 信息来源
|
||||
DB[(PostgreSQL 数据库)]
|
||||
DDL[database/schema_*.sql]
|
||||
API_REF[docs/api-reference/]
|
||||
PARSERS[models/parsers.py]
|
||||
COMMENTS[DDL COMMENT ON 注释]
|
||||
end
|
||||
|
||||
subgraph 对比脚本
|
||||
COMPARE[scripts/compare_ddl_db.py]
|
||||
end
|
||||
|
||||
subgraph 文档产出
|
||||
README[docs/bd_manual/README.md]
|
||||
ODS_DOCS[docs/bd_manual/ODS/main/*.md]
|
||||
ODS_MAP[docs/bd_manual/ODS/mappings/*.md]
|
||||
ODS_DICT[docs/dictionary/ods_tables_dictionary.md]
|
||||
ETL_DOCS[docs/bd_manual/ETL_Admin/main/*.md]
|
||||
CHANGES[docs/bd_manual/*/changes/*.md]
|
||||
DDL_FIX[database/schema_*.sql 修正]
|
||||
end
|
||||
|
||||
DB -->|information_schema 查询| COMPARE
|
||||
DDL -->|解析 CREATE TABLE| COMPARE
|
||||
COMPARE -->|差异报告| CHANGES
|
||||
COMPARE -->|修正| DDL_FIX
|
||||
|
||||
DB -->|表结构 + COMMENT| ODS_DOCS
|
||||
COMMENTS -->|字段说明| ODS_DOCS
|
||||
API_REF -->|端点信息| ODS_MAP
|
||||
PARSERS -->|转换逻辑| ODS_MAP
|
||||
DB -->|表概览| ODS_DICT
|
||||
DB -->|表结构| ETL_DOCS
|
||||
```
|
||||
|
||||
## 组件与接口
|
||||
|
||||
### 1. DDL 对比脚本 (`scripts/compare_ddl_db.py`)
|
||||
|
||||
一个独立的 Python 脚本,用于对比 DDL 文件与数据库实际状态。
|
||||
|
||||
**输入**:
|
||||
- DDL 文件路径(`database/schema_*.sql`)
|
||||
- 数据库连接(通过 `PG_DSN` 环境变量或 `--pg-dsn` 参数)
|
||||
|
||||
**输出**:
|
||||
- 控制台差异报告(表级、字段级、类型级)
|
||||
- 可选:`--fix` 模式直接修正 DDL 文件
|
||||
|
||||
**对比逻辑**:
|
||||
- 从 `information_schema.columns` 查询数据库实际表结构
|
||||
- 解析 DDL 文件中的 `CREATE TABLE` 语句提取表名和字段定义
|
||||
- 逐表逐字段对比:表是否存在、字段是否存在、字段类型是否一致、约束是否一致
|
||||
- 差异分类:`MISSING_TABLE`(DDL 缺表)、`EXTRA_TABLE`(DDL 多表)、`MISSING_COLUMN`、`EXTRA_COLUMN`、`TYPE_MISMATCH`、`NULLABLE_MISMATCH`
|
||||
|
||||
**接口**:
|
||||
```python
|
||||
def compare_schema(ddl_path: str, schema_name: str, pg_dsn: str) -> list[SchemaDiff]
|
||||
```
|
||||
|
||||
### 2. ODS 表级文档生成器
|
||||
|
||||
手动编写(非自动生成脚本),参考以下信息来源:
|
||||
- 数据库 `information_schema.columns` 获取字段名、类型、可空性
|
||||
- DDL 文件中的 `COMMENT ON` 注释获取字段说明、示例值、JSON 字段映射
|
||||
- 现有 DWD/DWS 表级文档格式作为模板
|
||||
|
||||
### 3. API→ODS 映射文档
|
||||
|
||||
手动编写,参考以下信息来源:
|
||||
- `docs/api-reference/endpoints/*.md` — API 端点路径、请求参数、响应字段
|
||||
- `docs/api-reference/samples/*.json` — JSON 响应样本
|
||||
- `models/parsers.py` — `TypeParser` 类中的类型转换方法
|
||||
- DDL 文件中的 `COMMENT ON` 注释中的 `【JSON字段】` 标注
|
||||
|
||||
### 4. 目录结构与索引
|
||||
|
||||
**新增目录**:
|
||||
- `docs/bd_manual/ETL_Admin/main/`
|
||||
- `docs/bd_manual/ETL_Admin/changes/`
|
||||
- `docs/bd_manual/ODS/mappings/`
|
||||
|
||||
**新增文件**:
|
||||
- `docs/bd_manual/README.md` — 根索引,列出目录结构和各层文档清单
|
||||
|
||||
## 数据模型
|
||||
|
||||
本特性不引入新的数据模型。涉及的现有 schema 如下:
|
||||
|
||||
| Schema | DDL 文件 | 用途 | 预估表数 |
|
||||
|--------|----------|------|----------|
|
||||
| `billiards_ods` | `database/schema_ODS_doc.sql` | 原始数据存储 | ~22 张 |
|
||||
| `billiards_dwd` | `database/schema_dwd_doc.sql` | 明细数据层 | ~22 张(含 Ex) |
|
||||
| `billiards_dws` | `database/schema_dws.sql` | 数据服务层 | ~30 张 |
|
||||
| `etl_admin` | `database/schema_etl_admin.sql` | ETL 管理元数据 | ~5 张 |
|
||||
|
||||
### 文档模板格式
|
||||
|
||||
**ODS 表级文档模板**(与 DWD/DWS 保持一致):
|
||||
|
||||
```markdown
|
||||
# {表名} {中文说明}
|
||||
|
||||
> 生成时间:YYYY-MM-DD
|
||||
|
||||
## 表信息
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| Schema | billiards |
|
||||
| 表名 | {表名} |
|
||||
| 主键 | {主键字段} |
|
||||
| 数据来源 | {API 端点 / JSON 文件} |
|
||||
| 说明 | {表说明} |
|
||||
|
||||
## 字段说明
|
||||
|
||||
| 序号 | 字段名 | 类型 | 可空 | 说明 |
|
||||
|------|--------|------|------|------|
|
||||
| 1 | ... | ... | ... | ... |
|
||||
|
||||
## 使用说明
|
||||
|
||||
{SQL 示例}
|
||||
|
||||
## 可回溯性
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| 可回溯 | ✅ 完全可回溯(保留 payload 原始 JSON) |
|
||||
| 数据来源 | {API 端点路径} |
|
||||
```
|
||||
|
||||
**API→ODS 映射文档模板**:
|
||||
|
||||
```markdown
|
||||
# {API端点名} → {ODS表名} 字段映射
|
||||
|
||||
> 生成时间:YYYY-MM-DD
|
||||
|
||||
## 端点信息
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| 接口路径 | {路径} |
|
||||
| 请求方法 | POST |
|
||||
| ODS 对应表 | {表名} |
|
||||
| JSON 数据路径 | {如 data.tenantMemberInfos} |
|
||||
|
||||
## 字段映射
|
||||
|
||||
| JSON 字段 | ODS 列名 | 类型转换 | 说明 |
|
||||
|-----------|----------|----------|------|
|
||||
| id | id | int→BIGINT | 主键 |
|
||||
| ... | ... | ... | ... |
|
||||
|
||||
## ETL 补充字段
|
||||
|
||||
| ODS 列名 | 生成逻辑 |
|
||||
|-----------|----------|
|
||||
| content_hash | 对业务字段计算 SHA256 |
|
||||
| source_file | 固定值:{文件名}.json |
|
||||
| source_endpoint | API 端点路径 |
|
||||
| fetched_at | 入库时间戳 |
|
||||
| payload | 完整原始 JSON 记录 |
|
||||
|
||||
## 类型转换规则
|
||||
|
||||
- 时间戳:通过 `TypeParser.parse_timestamp()` 转换,支持字符串和 Unix 毫秒时间戳
|
||||
- 金额:通过 `TypeParser.parse_decimal(value, scale=2)` 转换,ROUND_HALF_UP
|
||||
- 整数:通过 `TypeParser.parse_int()` 转换
|
||||
```
|
||||
|
||||
|
||||
## 正确性属性
|
||||
|
||||
*属性是系统在所有有效执行中都应保持为真的特征或行为——本质上是关于系统应该做什么的形式化陈述。属性是人类可读规格说明与机器可验证正确性保证之间的桥梁。*
|
||||
|
||||
### Property 1: 数据层目录结构一致性
|
||||
|
||||
*For any* 数据层目录(ODS、DWD、DWS、ETL_Admin),该目录下都应包含 `main/` 和 `changes/` 两个子目录。
|
||||
|
||||
**Validates: Requirements 1.2**
|
||||
|
||||
### Property 2: DDL 对比脚本差异检测完整性
|
||||
|
||||
*For any* schema 和对应的 DDL 文件,当数据库中存在 DDL 文件未定义的表或字段时,对比脚本应将其报告为 `MISSING_TABLE` 或 `MISSING_COLUMN`;当 DDL 文件中存在数据库没有的表或字段时,应报告为 `EXTRA_TABLE` 或 `EXTRA_COLUMN`;当字段类型不一致时,应报告为 `TYPE_MISMATCH`。
|
||||
|
||||
**Validates: Requirements 2.1, 2.2, 2.3, 2.4**
|
||||
|
||||
### Property 3: DDL 修正后零差异(不动点)
|
||||
|
||||
*For any* schema,在以数据库实际状态修正 DDL 文件后,再次运行对比脚本,差异列表应为空。
|
||||
|
||||
**Validates: Requirements 2.5**
|
||||
|
||||
### Property 4: ODS 表级文档覆盖率
|
||||
|
||||
*For any* `billiards` schema 中的 ODS 表,在 `docs/bd_manual/ODS/main/` 目录下都应存在一份对应的 Markdown 文档。
|
||||
|
||||
**Validates: Requirements 3.1**
|
||||
|
||||
### Property 5: ODS 表级文档格式完整性
|
||||
|
||||
*For any* ODS 表级文档,都应包含以下章节:表信息(含 Schema、表名、主键、数据来源、说明)、字段说明表格、使用说明(含 SQL 示例)、可回溯性信息,以及 ETL 元数据字段(content_hash、source_file、source_endpoint、fetched_at、payload)的说明。
|
||||
|
||||
**Validates: Requirements 3.2, 3.4, 3.5**
|
||||
|
||||
### Property 6: ODS 表级文档命名规范
|
||||
|
||||
*For any* ODS 表级文档文件,其文件名应匹配 `BD_manual_{表名}.md` 格式。
|
||||
|
||||
**Validates: Requirements 3.6**
|
||||
|
||||
### Property 7: 映射文档覆盖率
|
||||
|
||||
*For any* 有对应 ODS 表的 API 端点,在 `docs/bd_manual/ODS/mappings/` 目录下都应存在一份对应的映射文档。
|
||||
|
||||
**Validates: Requirements 4.1**
|
||||
|
||||
### Property 8: 映射文档内容完整性
|
||||
|
||||
*For any* 映射文档,都应包含以下信息:API 端点路径、ODS 表名、JSON 数据路径、字段映射表格,以及 ETL 补充字段(content_hash、source_file、source_endpoint、fetched_at、payload)的生成逻辑。
|
||||
|
||||
**Validates: Requirements 4.2, 4.4**
|
||||
|
||||
### Property 9: 映射文档命名规范
|
||||
|
||||
*For any* 映射文档文件,其文件名应匹配 `mapping_{API端点名}_{ODS表名}.md` 格式。
|
||||
|
||||
**Validates: Requirements 4.6**
|
||||
|
||||
### Property 10: ODS 数据字典覆盖率
|
||||
|
||||
*For any* `billiards` schema 中的 ODS 表,ODS 数据字典中都应有对应的条目,包含表名、中文说明、主键、数据来源信息。
|
||||
|
||||
**Validates: Requirements 5.2**
|
||||
|
||||
## 错误处理
|
||||
|
||||
### DDL 对比脚本
|
||||
|
||||
| 场景 | 处理方式 |
|
||||
|------|----------|
|
||||
| 数据库连接失败 | 输出错误信息并退出,返回非零退出码 |
|
||||
| DDL 文件不存在 | 输出错误信息并跳过该 schema |
|
||||
| DDL 文件解析失败 | 输出解析错误位置和原因,尽可能继续解析其余部分 |
|
||||
| schema 在数据库中不存在 | 输出警告并跳过 |
|
||||
|
||||
### 文档生成
|
||||
|
||||
| 场景 | 处理方式 |
|
||||
|------|----------|
|
||||
| 表无 COMMENT 注释 | 字段说明列填写"(待补充)" |
|
||||
| API 端点文档缺失 | 映射文档中标注"端点文档待补充",仅基于 DDL COMMENT 生成 |
|
||||
| 字段类型无法识别 | 保留数据库原始类型字符串 |
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
|
||||
针对 DDL 对比脚本的核心逻辑编写单元测试(`tests/unit/test_compare_ddl.py`):
|
||||
|
||||
- 测试 DDL 解析器能正确提取表名、字段名、字段类型、约束
|
||||
- 测试差异检测逻辑能识别各类差异(缺失表、多余表、字段差异、类型差异)
|
||||
- 测试边界情况:空 DDL 文件、无表的 schema、COMMENT 中含特殊字符
|
||||
|
||||
### 属性测试
|
||||
|
||||
使用 `hypothesis` 库(Python 属性测试框架)。
|
||||
|
||||
- **Property 2 测试**:生成随机的"DDL 表定义"和"数据库表定义",注入已知差异,验证对比函数能检测到所有差异
|
||||
- **Feature: bd-manual-docs-consolidation, Property 2: DDL 对比脚本差异检测完整性**
|
||||
- 最少 100 次迭代
|
||||
|
||||
- **Property 3 测试**:生成随机的数据库表定义,用其生成 DDL,再运行对比,验证差异为零
|
||||
- **Feature: bd-manual-docs-consolidation, Property 3: DDL 修正后零差异(不动点)**
|
||||
- 最少 100 次迭代
|
||||
|
||||
### 集成验证
|
||||
|
||||
文档覆盖率和格式验证通过 Python 脚本实现(`scripts/validate_bd_manual.py`),可在 CI 中运行:
|
||||
|
||||
- 验证 Property 1(目录结构)、Property 4-10(文档覆盖率、格式、命名)
|
||||
- 输入:文件系统 + 数据库 `information_schema` 查询
|
||||
- 输出:通过/失败报告,列出缺失或不合规的文档
|
||||
|
||||
### 测试配置
|
||||
|
||||
- 属性测试库:`hypothesis`(需添加到开发依赖)
|
||||
- 单元测试:`pytest tests/unit/test_compare_ddl.py`
|
||||
- 集成验证:`python scripts/validate_bd_manual.py --pg-dsn "$PG_DSN"`
|
||||
- 每个属性测试最少 100 次迭代
|
||||
- 每个测试需注释引用对应的设计属性编号
|
||||
80
.kiro/specs/bd-manual-docs-consolidation/requirements.md
Normal file
80
.kiro/specs/bd-manual-docs-consolidation/requirements.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# 需求文档
|
||||
|
||||
## 简介
|
||||
|
||||
整理和补全飞球 ETL 系统的数据库文档体系(`docs/bd_manual/`),包括目录结构规范化、DDL 与数据库实际状态的对比同步、ODS 层表级文档补全、以及 API JSON → ODS 字段映射文档的建立。本特性不涉及代码逻辑变更,仅涉及文档和 DDL 文件的维护。
|
||||
|
||||
## 术语表
|
||||
|
||||
- **BD_Manual**: 数据库手册目录(`docs/bd_manual/`),存放各层表级文档、变更记录等
|
||||
- **ODS**: 操作数据存储层(Operational Data Store),`billiards` schema,保留 API 原始数据
|
||||
- **DWD**: 明细数据层(Data Warehouse Detail),`billiards_dwd` schema,清洗后的维度和事实表
|
||||
- **DWS**: 数据服务层(Data Warehouse Service),`billiards_dws` schema,汇总宽表和配置表
|
||||
- **DDL**: 数据定义语言文件(`database/schema_*.sql`),定义表结构
|
||||
- **表级文档**: 以 Markdown 格式编写的单表说明文件,包含表信息、字段说明、使用示例等
|
||||
- **字段映射文档**: 记录 API JSON 响应字段到 ODS 表字段的对应关系和转换逻辑
|
||||
- **SCD2**: 缓慢变化维度类型 2,用于 DWD 维度表的历史版本管理
|
||||
- **ETL_Admin**: ETL 管理 schema(`etl_admin`),存放调度、游标、运行记录等元数据
|
||||
|
||||
## 需求
|
||||
|
||||
### 需求 1:规范化 BD_Manual 目录结构
|
||||
|
||||
**用户故事:** 作为数据开发人员,我希望 BD_Manual 目录结构统一规范,以便快速定位各层各类型的数据库文档。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE BD_Manual SHALL 包含以下顶层子目录:`ODS/`、`DWD/`、`DWS/`、`ETL_Admin/`
|
||||
2. WHEN 某一数据层目录被访问时,THE BD_Manual SHALL 在该层目录下提供 `main/`(表级文档)和 `changes/`(变更记录)两个子目录
|
||||
3. THE DWD 目录 SHALL 额外保留 `Ex/` 子目录用于存放扩展表文档
|
||||
4. THE BD_Manual SHALL 在根目录提供一个 `README.md` 索引文件,列出目录结构说明和各层文档清单
|
||||
5. WHEN ETL_Admin schema 存在表时,THE BD_Manual SHALL 在 `ETL_Admin/main/` 下为每张表提供表级文档
|
||||
|
||||
### 需求 2:DDL 文件与数据库实际状态对比同步
|
||||
|
||||
**用户故事:** 作为数据开发人员,我希望 DDL 文件与数据库实际表结构保持一致,以便 DDL 文件可作为可信的 schema 参考。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 对比 ODS 层 DDL 文件(`database/schema_ODS_doc.sql`)与数据库 `billiards_ods` schema 实际表结构时,THE 对比脚本 SHALL 输出所有差异项(缺失表、多余表、字段差异、类型差异、约束差异)
|
||||
2. WHEN 对比 DWD 层 DDL 文件(`database/schema_dwd_doc.sql`)与数据库 `billiards_dwd` schema 实际表结构时,THE 对比脚本 SHALL 输出所有差异项
|
||||
3. WHEN 对比 DWS 层 DDL 文件(`database/schema_dws.sql`)与数据库 `billiards_dws` schema 实际表结构时,THE 对比脚本 SHALL 输出所有差异项
|
||||
4. WHEN 对比 ETL_Admin 层 DDL 文件(`database/schema_etl_admin.sql`)与数据库 `etl_admin` schema 实际表结构时,THE 对比脚本 SHALL 输出所有差异项
|
||||
5. WHEN 发现差异时,THE DDL 文件 SHALL 以数据库实际状态为准进行修正
|
||||
6. WHEN DDL 文件被修正后,THE 变更记录 SHALL 在对应层的 `changes/` 目录下生成一份差异说明文档
|
||||
|
||||
### 需求 3:补全 ODS 层表级文档
|
||||
|
||||
**用户故事:** 作为数据开发人员,我希望 ODS 层每张表都有完整的表级文档,以便理解原始数据结构和来源。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE ODS 表级文档 SHALL 为 `billiards_ods` schema 中的每张 ODS 表生成一份 Markdown 文档,存放于 `docs/bd_manual/ODS/main/`
|
||||
2. THE ODS 表级文档 SHALL 遵循与 DWD/DWS 表级文档一致的格式,包含:表信息表格、字段说明表格、使用说明(含 SQL 示例)、可回溯性信息
|
||||
3. WHEN ODS 表的字段含有 COMMENT 注释时,THE 表级文档 SHALL 将 COMMENT 中的说明、示例、JSON 字段映射信息提取并填入字段说明
|
||||
4. THE ODS 表级文档的表信息 SHALL 包含 Schema、表名、主键、数据来源(API 端点或文件)、说明
|
||||
5. THE ODS 表级文档 SHALL 包含 ETL 元数据字段(`content_hash`、`source_file`、`source_endpoint`、`fetched_at`、`payload`)的统一说明
|
||||
6. THE ODS 表级文档的文件命名 SHALL 遵循 `BD_manual_{表名}.md` 格式
|
||||
|
||||
### 需求 4:建立 API JSON → ODS 字段映射文档
|
||||
|
||||
**用户故事:** 作为数据开发人员,我希望有一份清晰的 API 响应字段到 ODS 表字段的映射文档,以便理解数据从 API 到 ODS 的转换逻辑。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE 映射文档 SHALL 为每个 API 端点与其对应的 ODS 表建立一份映射文件,存放于 `docs/bd_manual/ODS/mappings/`
|
||||
2. THE 映射文档 SHALL 包含以下信息:API 端点路径、对应 ODS 表名、JSON 响应路径(如 `data.tenantMemberInfos`)、每个字段的 JSON 路径到 ODS 列名的映射
|
||||
3. WHEN 字段存在类型转换或值处理逻辑时,THE 映射文档 SHALL 记录转换规则(如时间格式转换、枚举值映射、金额精度处理)
|
||||
4. THE 映射文档 SHALL 标注 ETL 补充字段(`content_hash`、`source_file`、`source_endpoint`、`fetched_at`、`payload`)的生成逻辑
|
||||
5. THE 映射文档 SHALL 参考 `models/parsers.py` 中的解析逻辑和 `docs/api-reference/` 中的端点文档作为信息来源
|
||||
6. THE 映射文档的文件命名 SHALL 遵循 `mapping_{API端点名}_{ODS表名}.md` 格式
|
||||
|
||||
### 需求 5:建立 ODS 数据字典
|
||||
|
||||
**用户故事:** 作为数据开发人员,我希望有一份 ODS 层的数据字典汇总文档,以便快速查阅所有 ODS 表的概览信息。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE ODS 数据字典 SHALL 创建于 `docs/dictionary/ods_tables_dictionary.md`
|
||||
2. THE ODS 数据字典 SHALL 列出所有 ODS 表的概览信息,包含:表名、中文说明、主键、记录数、数据来源
|
||||
3. THE ODS 数据字典 SHALL 遵循与现有 DWD/DWS 数据字典一致的格式
|
||||
111
.kiro/specs/bd-manual-docs-consolidation/tasks.md
Normal file
111
.kiro/specs/bd-manual-docs-consolidation/tasks.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# 实施计划:数据库文档整理与补全
|
||||
|
||||
## 概述
|
||||
|
||||
按照"目录结构 → DDL 对比脚本 → DDL 同步 → ODS 文档 → 映射文档 → 数据字典 → 索引"的顺序,逐步完成文档体系的整理和补全。DDL 对比脚本先编写并测试,再用它驱动实际的 DDL 同步工作。
|
||||
|
||||
## 任务
|
||||
|
||||
- [x] 1. 规范化 BD_Manual 目录结构
|
||||
- 创建 `docs/bd_manual/ETL_Admin/main/` 和 `docs/bd_manual/ETL_Admin/changes/` 目录
|
||||
- 创建 `docs/bd_manual/ODS/mappings/` 目录
|
||||
- 确认 ODS/DWD/DWS 各层均有 `main/` 和 `changes/` 子目录
|
||||
- _Requirements: 1.1, 1.2, 1.3_
|
||||
|
||||
- [ ] 2. 编写 DDL 对比脚本
|
||||
- [x] 2.1 实现 DDL 解析器和对比核心逻辑 (`scripts/compare_ddl_db.py`)
|
||||
- 解析 `CREATE TABLE` 语句提取表名、字段名、字段类型、约束、主键
|
||||
- 查询 `information_schema.columns` 获取数据库实际表结构
|
||||
- 实现逐表逐字段对比,输出差异分类(MISSING_TABLE、EXTRA_TABLE、MISSING_COLUMN、EXTRA_COLUMN、TYPE_MISMATCH、NULLABLE_MISMATCH)
|
||||
- 支持 `--pg-dsn`、`--schema`、`--ddl-path` 参数
|
||||
- _Requirements: 2.1, 2.2, 2.3, 2.4_
|
||||
|
||||
- [x] 2.2 编写 DDL 解析器单元测试 (`tests/unit/test_compare_ddl.py`)
|
||||
- 测试 DDL 解析器正确提取表名、字段、类型、约束
|
||||
- 测试差异检测逻辑识别各类差异
|
||||
- 测试边界情况:空文件、COMMENT 含特殊字符
|
||||
- _Requirements: 2.1_
|
||||
|
||||
- [x] 2.3 编写 DDL 对比属性测试
|
||||
- **Property 2: DDL 对比脚本差异检测完整性**
|
||||
- **Validates: Requirements 2.1, 2.2, 2.3, 2.4**
|
||||
|
||||
- [x] 2.4 编写 DDL 修正不动点属性测试
|
||||
- **Property 3: DDL 修正后零差异(不动点)**
|
||||
- **Validates: Requirements 2.5**
|
||||
|
||||
- [x] 3. 检查点 — 确认对比脚本可用
|
||||
- 确保所有测试通过,如有问题请向用户确认。
|
||||
|
||||
- [x] 4. 执行 DDL 对比并同步
|
||||
- [x] 4.1 运行对比脚本对比四个 schema(ODS、DWD、DWS、ETL_Admin)
|
||||
- 执行 `scripts/compare_ddl_db.py` 对比每个 schema
|
||||
- 记录所有差异项
|
||||
- _Requirements: 2.1, 2.2, 2.3, 2.4_
|
||||
|
||||
- [x] 4.2 修正 DDL 文件以匹配数据库实际状态
|
||||
- 以数据库为准修正 `database/schema_ODS_doc.sql`、`database/schema_dwd_doc.sql`、`database/schema_dws.sql`、`database/schema_etl_admin.sql`
|
||||
- _Requirements: 2.5_
|
||||
|
||||
- [x] 4.3 生成 DDL 变更记录
|
||||
- 在对应层的 `changes/` 目录下生成差异说明文档(日期前缀命名)
|
||||
- 包含变更说明、兼容性影响、回滚策略、验证 SQL(至少 3 条)
|
||||
- _Requirements: 2.6_
|
||||
|
||||
- [x] 5. 检查点 — 确认 DDL 同步完成
|
||||
- 确保所有测试通过,如有问题请向用户确认。
|
||||
|
||||
- [x] 6. 补全 ODS 层表级文档
|
||||
- [x] 6.1 为每张 ODS 表编写表级文档 (`docs/bd_manual/ODS/main/BD_manual_{表名}.md`)
|
||||
- 从数据库 `information_schema.columns` 获取字段信息
|
||||
- 从 DDL `COMMENT ON` 注释提取字段说明、示例值、JSON 字段映射
|
||||
- 遵循 DWD/DWS 文档格式:表信息、字段说明、使用说明(含 SQL)、可回溯性
|
||||
- 包含 ETL 元数据字段统一说明
|
||||
- _Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 3.6_
|
||||
|
||||
- [x] 7. 建立 API→ODS 字段映射文档
|
||||
- [x] 7.1 为每个 API 端点编写映射文档 (`docs/bd_manual/ODS/mappings/mapping_{端点名}_{表名}.md`)
|
||||
- 参考 `docs/api-reference/endpoints/*.md` 获取端点信息和响应字段
|
||||
- 参考 DDL `COMMENT ON` 中的 `【JSON字段】` 标注获取映射关系
|
||||
- 参考 `models/parsers.py` 中 `TypeParser` 的转换方法记录类型转换规则
|
||||
- 包含 ETL 补充字段生成逻辑说明
|
||||
- _Requirements: 4.1, 4.2, 4.3, 4.4, 4.5, 4.6_
|
||||
|
||||
- [x] 8. 建立 ODS 数据字典和 ETL_Admin 文档
|
||||
- [x] 8.1 创建 ODS 数据字典 (`docs/dictionary/ods_tables_dictionary.md`)
|
||||
- 列出所有 ODS 表概览:表名、中文说明、主键、记录数、数据来源
|
||||
- 遵循现有 DWD/DWS 数据字典格式
|
||||
- _Requirements: 5.1, 5.2, 5.3_
|
||||
|
||||
- [x] 8.2 为 ETL_Admin 表编写表级文档 (`docs/bd_manual/ETL_Admin/main/BD_manual_{表名}.md`)
|
||||
- 从数据库获取 `etl_admin` schema 表结构
|
||||
- 遵循统一文档格式
|
||||
- _Requirements: 1.5_
|
||||
|
||||
- [x] 9. 编写 BD_Manual 根目录 README.md 索引
|
||||
- 创建 `docs/bd_manual/README.md`
|
||||
- 列出目录结构说明、各层文档清单、文档命名规范
|
||||
- _Requirements: 1.4_
|
||||
|
||||
- [x] 10. 编写文档验证脚本
|
||||
- [x] 10.1 实现文档覆盖率和格式验证脚本 (`scripts/validate_bd_manual.py`)
|
||||
- 验证目录结构一致性(Property 1)
|
||||
- 验证 ODS 文档覆盖率和命名规范(Property 4, 6)
|
||||
- 验证 ODS 文档格式完整性(Property 5)
|
||||
- 验证映射文档覆盖率和命名规范(Property 7, 9)
|
||||
- 验证映射文档内容完整性(Property 8)
|
||||
- 验证数据字典覆盖率(Property 10)
|
||||
- 支持 `--pg-dsn` 参数连接数据库获取表清单
|
||||
- _Requirements: 1.2, 3.1, 3.2, 3.6, 4.1, 4.2, 4.6, 5.2_
|
||||
|
||||
- [x] 11. 最终检查点 — 确认所有文档完整
|
||||
- 运行 `scripts/validate_bd_manual.py` 确认所有验证通过
|
||||
- 确保所有测试通过,如有问题请向用户确认。
|
||||
|
||||
## 备注
|
||||
|
||||
- 标记 `*` 的子任务为可选,可跳过以加速 MVP
|
||||
- 每个任务引用了具体的需求编号以便追溯
|
||||
- DDL 修正涉及 `database/` 高风险路径,完成后需触发 `/audit`
|
||||
- 属性测试验证对比脚本的通用正确性,集成验证脚本验证文档体系的完整性
|
||||
- ODS 表级文档和映射文档为手动编写(非自动生成),需逐表参考数据库和 API 文档
|
||||
1
.kiro/specs/docs-optimization/.config.kiro
Normal file
1
.kiro/specs/docs-optimization/.config.kiro
Normal file
@@ -0,0 +1 @@
|
||||
{"generationMode": "requirements-first"}
|
||||
229
.kiro/specs/docs-optimization/design.md
Normal file
229
.kiro/specs/docs-optimization/design.md
Normal file
@@ -0,0 +1,229 @@
|
||||
# 设计文档:文档体系整理与优化
|
||||
|
||||
## 概述
|
||||
|
||||
本设计针对飞球 ETL 系统的 `docs/` 目录进行结构性优化,包含三个核心工作流:
|
||||
|
||||
1. **文档覆盖度补充**:新增 `architecture/`、`business-rules/`、`operations/` 三个缺失目录及骨架文档,新增项目级 `CHANGELOG.md`,更新文档总索引
|
||||
2. **审计一览表生成**:编写 Python 脚本解析 `docs/audit/changes/` 下的审计源记录,生成结构化的 `audit_dashboard.md` 汇总视图
|
||||
3. **业务规则文档迁移**:将 `index_algorithm_cn.md` 从 `docs/database/DWS/` 迁移至 `docs/business-rules/`,原位置保留重定向说明
|
||||
|
||||
## 架构
|
||||
|
||||
### 文档目录结构(目标状态)
|
||||
|
||||
```
|
||||
docs/
|
||||
├── README.md ← 文档总索引(更新)
|
||||
├── CHANGELOG.md ← 新增:项目级变更日志
|
||||
├── architecture/ ← 新增:架构设计文档
|
||||
│ ├── README.md ← 目录索引
|
||||
│ ├── system_overview.md ← 系统整体架构
|
||||
│ └── data_flow.md ← 数据流向详解
|
||||
├── business-rules/ ← 新增:业务规则文档
|
||||
│ ├── README.md ← 目录索引
|
||||
│ ├── index_algorithm_cn.md ← 迁移自 database/DWS/
|
||||
│ ├── dws_metrics.md ← DWS 口径定义(骨架)
|
||||
│ └── scd2_rules.md ← SCD2 处理规则(骨架)
|
||||
├── operations/ ← 新增:运维文档
|
||||
│ ├── README.md ← 目录索引
|
||||
│ ├── environment_setup.md ← 环境搭建指南
|
||||
│ ├── scheduling.md ← 调度配置说明
|
||||
│ └── troubleshooting.md ← 故障排查手册
|
||||
├── audit/
|
||||
│ ├── audit_dashboard.md ← 新增:审计一览表
|
||||
│ ├── changes/ ← 审计源记录(不变)
|
||||
│ └── ...
|
||||
├── api-reference/ ← 不变
|
||||
├── database/ ← 不变(移除 index_algorithm_cn.md)
|
||||
├── etl_tasks/ ← 不变
|
||||
├── reports/ ← 不变
|
||||
└── requirements/ ← 不变
|
||||
```
|
||||
|
||||
### 审计一览表生成流程
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A["docs/audit/changes/*.md"] -->|Python 脚本解析| B["结构化数据列表"]
|
||||
B -->|按时间倒序排列| C["时间线视图"]
|
||||
B -->|按模块分类| D["模块索引视图"]
|
||||
C --> E["audit_dashboard.md"]
|
||||
D --> E
|
||||
```
|
||||
|
||||
## 组件与接口
|
||||
|
||||
### 组件 1:审计一览表生成脚本
|
||||
|
||||
- 路径:`scripts/gen_audit_dashboard.py`
|
||||
- 职责:扫描 `docs/audit/changes/` 目录,解析每个 Markdown 文件,提取结构化信息,生成 `docs/audit/audit_dashboard.md`
|
||||
- 入口:`python scripts/gen_audit_dashboard.py`
|
||||
|
||||
#### 解析逻辑
|
||||
|
||||
脚本需要从审计源记录中提取以下字段:
|
||||
|
||||
| 字段 | 提取方式 |
|
||||
|------|----------|
|
||||
| 日期 | 从文件名前缀 `YYYY-MM-DD` 提取 |
|
||||
| 标题/需求摘要 | 从 Markdown 一级标题 `# ...` 提取 |
|
||||
| slug | 从文件名 `__` 后的部分提取 |
|
||||
| 修改文件列表 | 从"修改文件清单"或"文件清单"章节的表格/列表中提取 |
|
||||
| 影响模块 | 根据修改文件路径推断所属模块(api/、tasks/、docs/ 等) |
|
||||
| 变更类型 | 从文件内容中提取(bugfix/新增/修改/删除/文档) |
|
||||
| 风险等级 | 从"风险点"章节推断(高/中/低/极低) |
|
||||
|
||||
#### 模块分类规则
|
||||
|
||||
根据修改文件路径前缀映射到功能模块:
|
||||
|
||||
```python
|
||||
MODULE_MAP = {
|
||||
"api/": "API 层",
|
||||
"tasks/ods": "ODS 层",
|
||||
"tasks/dwd": "DWD 层",
|
||||
"tasks/dws": "DWS 层",
|
||||
"tasks/index": "指数算法",
|
||||
"loaders/": "数据装载",
|
||||
"database/": "数据库",
|
||||
"orchestration/": "调度",
|
||||
"config/": "配置",
|
||||
"cli/": "CLI",
|
||||
"models/": "模型",
|
||||
"scd/": "SCD2",
|
||||
"docs/": "文档",
|
||||
"scripts/": "脚本工具",
|
||||
"tests/": "测试",
|
||||
"quality/": "质量校验",
|
||||
"gui/": "GUI",
|
||||
"utils/": "工具库",
|
||||
}
|
||||
```
|
||||
|
||||
### 组件 2:静态文档文件
|
||||
|
||||
纯 Markdown 文件,无代码逻辑。包括:
|
||||
- 架构文档(`docs/architecture/`)
|
||||
- 业务规则文档(`docs/business-rules/`)
|
||||
- 运维文档(`docs/operations/`)
|
||||
- 变更日志(`docs/CHANGELOG.md`)
|
||||
- 更新后的文档总索引(`docs/README.md`)
|
||||
|
||||
### 组件 3:文件迁移与重定向
|
||||
|
||||
- 将 `docs/database/DWS/index_algorithm_cn.md` 内容迁移至 `docs/business-rules/index_algorithm_cn.md`
|
||||
- 在原位置 `docs/database/DWS/index_algorithm_cn.md` 替换为重定向说明
|
||||
|
||||
## 数据模型
|
||||
|
||||
### 审计记录解析结构
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class AuditEntry:
|
||||
"""从单个审计源记录文件解析出的结构化数据"""
|
||||
date: str # YYYY-MM-DD,从文件名提取
|
||||
slug: str # 文件名中 __ 后的标识符
|
||||
title: str # Markdown 一级标题
|
||||
filename: str # 源文件名(不含路径)
|
||||
changed_files: list[str] # 修改的文件路径列表
|
||||
modules: set[str] # 影响的功能模块集合
|
||||
risk_level: str # 风险等级:高/中/低/极低
|
||||
change_type: str # 变更类型:bugfix/功能/文档/重构/清理
|
||||
```
|
||||
|
||||
### 审计一览表输出格式
|
||||
|
||||
`audit_dashboard.md` 包含两个视图:
|
||||
|
||||
1. **时间线视图**(按日期倒序):
|
||||
|
||||
```markdown
|
||||
| 日期 | 需求摘要 | 变更类型 | 影响模块 | 风险 | 详情 |
|
||||
|------|----------|----------|----------|------|------|
|
||||
| 2026-02-15 | docs/database 合并 | 重构 | 文档, 脚本工具 | 极低 | [链接](changes/...) |
|
||||
```
|
||||
|
||||
2. **模块索引视图**(按模块分组):
|
||||
|
||||
```markdown
|
||||
### API 层
|
||||
| 日期 | 需求摘要 | 变更类型 | 风险 | 详情 |
|
||||
...
|
||||
|
||||
### DWS 层
|
||||
| 日期 | 需求摘要 | 变更类型 | 风险 | 详情 |
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
## 正确性属性
|
||||
|
||||
*正确性属性是一种在系统所有合法执行路径上都应成立的特征或行为——本质上是对"系统应该做什么"的形式化陈述。属性是连接人类可读规格说明与机器可验证正确性保证之间的桥梁。*
|
||||
|
||||
本特性中,大部分需求涉及静态文档文件的创建和目录组织,属于例子级别的验证(文件是否存在、内容是否包含特定条目)。可提取为通用属性的集中在审计一览表生成脚本的解析、分类和排序逻辑。
|
||||
|
||||
### Property 1:审计记录解析-渲染完整性
|
||||
|
||||
*For any* 格式合规的审计源记录 Markdown 文件(包含一级标题、日期行、修改文件清单章节),解析后生成的表格行应包含:日期、需求摘要、变更类型、影响模块和源文件链接。
|
||||
|
||||
**Validates: Requirements 2.1, 2.2**
|
||||
|
||||
### Property 2:文件路径模块分类正确性
|
||||
|
||||
*For any* 文件路径字符串,模块分类函数的返回值应属于预定义的模块名称集合(API 层、ODS 层、DWD 层、DWS 层、指数算法、数据装载、数据库、调度、配置、CLI、模型、SCD2、文档、脚本工具、测试、质量校验、GUI、工具库、其他)。
|
||||
|
||||
**Validates: Requirements 2.3**
|
||||
|
||||
### Property 3:审计条目时间倒序排列
|
||||
|
||||
*For any* 一组审计条目列表,经过排序函数处理后,输出列表中每个条目的日期应大于等于其后续条目的日期(严格非递增序)。
|
||||
|
||||
**Validates: Requirements 2.4**
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 审计记录解析容错
|
||||
|
||||
| 场景 | 处理方式 |
|
||||
|------|----------|
|
||||
| 审计文件缺少一级标题 | 使用文件名 slug 作为标题替代 |
|
||||
| 审计文件缺少"修改文件清单"章节 | `changed_files` 返回空列表,`modules` 标记为 `{"其他"}` |
|
||||
| 审计文件名不符合 `YYYY-MM-DD__slug.md` 格式 | 跳过该文件,输出警告日志 |
|
||||
| 审计文件编码非 UTF-8 | 尝试 UTF-8 解码,失败则跳过并警告 |
|
||||
| `docs/audit/changes/` 目录为空 | 生成空的 dashboard 文件,包含"暂无审计记录"提示 |
|
||||
|
||||
### 文件迁移容错
|
||||
|
||||
| 场景 | 处理方式 |
|
||||
|------|----------|
|
||||
| `index_algorithm_cn.md` 源文件不存在 | 脚本报错退出,提示文件路径 |
|
||||
| 目标目录 `docs/business-rules/` 已存在同名文件 | 提示用户确认是否覆盖 |
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 测试框架
|
||||
|
||||
- 单元测试:`pytest`
|
||||
- 属性测试:`hypothesis`(Python 属性测试库)
|
||||
- 测试目录:`tests/unit/test_gen_audit_dashboard.py`
|
||||
|
||||
### 属性测试
|
||||
|
||||
每个正确性属性对应一个 `hypothesis` 属性测试,最少运行 100 次迭代:
|
||||
|
||||
- **Property 1**:生成随机的审计 Markdown 内容(包含标题、日期、文件清单),验证解析+渲染后的表格行包含所有必要字段
|
||||
- Tag: `Feature: docs-optimization, Property 1: 审计记录解析-渲染完整性`
|
||||
- **Property 2**:生成随机的文件路径字符串,验证分类结果属于预定义模块集合
|
||||
- Tag: `Feature: docs-optimization, Property 2: 文件路径模块分类正确性`
|
||||
- **Property 3**:生成随机的日期列表构造审计条目,验证排序后严格非递增
|
||||
- Tag: `Feature: docs-optimization, Property 3: 审计条目时间倒序排列`
|
||||
|
||||
### 单元测试
|
||||
|
||||
- 解析真实审计记录文件的具体例子(使用项目中已有的审计文件作为测试输入)
|
||||
- 边界情况:空目录、格式异常文件、缺少章节的文件
|
||||
- 文件存在性检查:验证所有新增目录和文件已创建
|
||||
- 文档总索引完整性:验证 `docs/README.md` 包含所有一级目录条目
|
||||
- 重定向文件验证:验证原 `index_algorithm_cn.md` 位置包含重定向说明
|
||||
56
.kiro/specs/docs-optimization/requirements.md
Normal file
56
.kiro/specs/docs-optimization/requirements.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# 需求文档:文档体系整理与优化
|
||||
|
||||
## 简介
|
||||
|
||||
对飞球 ETL 系统(etl-billiards)的 `docs/` 目录进行文档体系整理与优化,涵盖三个核心诉求:文档覆盖度评估与缺失类别补充、审计一览表生成、业务规则文档独立目录建设。目标是让项目文档从宏观架构到微观实现形成完整闭环,同时提供可快速检索的审计变更视图。
|
||||
|
||||
## 术语表
|
||||
|
||||
- **文档总索引(Docs_Index)**:`docs/README.md`,项目文档的统一入口与导航页
|
||||
- **审计一览表(Audit_Dashboard)**:基于 `docs/audit/changes/` 源数据生成的汇总视图文件
|
||||
- **审计源记录(Audit_Record)**:`docs/audit/changes/` 目录下的单个审计 Markdown 文件
|
||||
- **业务规则文档目录(Business_Rules_Dir)**:`docs/business-rules/`,存放指数算法、DWS 口径定义、SCD2 规则等业务逻辑文档
|
||||
- **架构设计文档目录(Architecture_Dir)**:`docs/architecture/`,存放系统整体架构、数据流、模块交互等设计文档
|
||||
- **运维文档目录(Operations_Dir)**:`docs/operations/`,存放环境搭建、调度配置、故障排查等运维指南
|
||||
- **变更日志(Changelog)**:`docs/CHANGELOG.md`,项目级版本变更历史记录
|
||||
- **指数算法文档(Index_Algorithm_Doc)**:当前位于 `docs/database/DWS/index_algorithm_cn.md` 的指数算法说明文件
|
||||
|
||||
## 需求
|
||||
|
||||
### 需求 1:文档覆盖度评估与缺失类别补充
|
||||
|
||||
**用户故事:** 作为项目开发者,我希望文档体系涵盖从宏观架构到微观实现的完整说明,以便新成员快速上手、现有成员高效查阅。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Docs_Index SHALL 包含指向所有一级文档目录的链接和简要说明
|
||||
2. WHEN 新增文档目录时,THE Docs_Index SHALL 同步更新对应的目录条目和说明
|
||||
3. THE Architecture_Dir SHALL 包含系统整体架构文档,涵盖数据流向图(ODS→DWD→DWS)、模块交互关系和技术栈说明
|
||||
4. THE Business_Rules_Dir SHALL 包含独立的业务规则与算法文档目录,与数据库表结构文档分离
|
||||
5. THE Operations_Dir SHALL 包含环境搭建指南、调度配置说明和常见故障排查手册
|
||||
6. THE Changelog SHALL 记录项目级版本变更历史,包含日期、变更摘要和影响范围
|
||||
|
||||
### 需求 2:审计一览表生成
|
||||
|
||||
**用户故事:** 作为项目管理者,我希望基于审计源记录生成一个汇总视图,以便一眼了解项目的修改痕迹并按功能模块检索。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Audit_Dashboard SHALL 从 Audit_Record 文件中提取日期、需求摘要、修改内容和影响范围信息
|
||||
2. THE Audit_Dashboard SHALL 以表格形式展示每条审计记录的时间日期、用户需求摘要、修改/新增/删除的内容概要和对项目的影响
|
||||
3. THE Audit_Dashboard SHALL 提供按功能模块分类的索引(如 API 层、ODS 层、DWD 层、DWS 层、文档、基础设施)
|
||||
4. THE Audit_Dashboard SHALL 提供按时间倒序排列的完整变更列表
|
||||
5. WHEN 新的 Audit_Record 被添加到 `docs/audit/changes/` 时,THE Audit_Dashboard SHALL 通过手动重新生成的方式保持同步
|
||||
6. THE Audit_Dashboard SHALL 存放于 `docs/audit/` 目录下,文件名为 `audit_dashboard.md`
|
||||
|
||||
### 需求 3:业务规则文档独立目录
|
||||
|
||||
**用户故事:** 作为项目开发者,我希望业务规则和算法文档有独立的存放目录,以便与数据库表结构文档清晰分离,方便查阅和维护。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Business_Rules_Dir SHALL 作为独立目录存在于 `docs/business-rules/` 路径下
|
||||
2. WHEN Index_Algorithm_Doc 从 `docs/database/DWS/` 迁移至 Business_Rules_Dir 时,THE 原路径 SHALL 保留一个指向新位置的重定向说明
|
||||
3. THE Business_Rules_Dir SHALL 包含目录级 README 文件,列出所有业务规则文档的索引
|
||||
4. THE Business_Rules_Dir SHALL 按业务域组织文档(如指数算法、DWS 口径定义、SCD2 规则、薪酬计算规则)
|
||||
5. THE Docs_Index SHALL 包含 Business_Rules_Dir 的条目和说明
|
||||
100
.kiro/specs/docs-optimization/tasks.md
Normal file
100
.kiro/specs/docs-optimization/tasks.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# 实施计划:文档体系整理与优化
|
||||
|
||||
## 概述
|
||||
|
||||
基于设计文档,将实施分为四个阶段:新增文档目录与骨架文件、业务规则文档迁移、审计一览表生成脚本开发、文档总索引更新。所有任务聚焦于文件创建/修改和 Python 脚本编写。
|
||||
|
||||
## 任务
|
||||
|
||||
- [x] 1. 新增文档目录与骨架文件
|
||||
- [x] 1.1 创建 `docs/architecture/` 目录及文档
|
||||
- 创建 `docs/architecture/README.md`(目录索引)
|
||||
- 创建 `docs/architecture/system_overview.md`(系统整体架构:数据流向图、模块交互、技术栈)
|
||||
- 创建 `docs/architecture/data_flow.md`(ODS→DWD→DWS 数据流向详解)
|
||||
- 从根 `README.md` 和 `.kiro/steering/` 中提取架构信息填充内容
|
||||
- _Requirements: 1.3_
|
||||
|
||||
- [x] 1.2 创建 `docs/operations/` 目录及文档
|
||||
- 创建 `docs/operations/README.md`(目录索引)
|
||||
- 创建 `docs/operations/environment_setup.md`(环境搭建指南:Python、PostgreSQL、依赖安装)
|
||||
- 创建 `docs/operations/scheduling.md`(调度配置说明:CLI 参数、定时任务、管道模式)
|
||||
- 创建 `docs/operations/troubleshooting.md`(故障排查手册:常见错误与解决方案)
|
||||
- _Requirements: 1.5_
|
||||
|
||||
- [x] 1.3 创建 `docs/CHANGELOG.md`
|
||||
- 基于 `docs/audit/changes/` 中的审计记录,整理项目级版本变更历史
|
||||
- 包含日期、变更摘要和影响范围
|
||||
- _Requirements: 1.6_
|
||||
|
||||
- [x] 2. 业务规则文档迁移与目录建设
|
||||
- [x] 2.1 创建 `docs/business-rules/` 目录并迁移指数算法文档
|
||||
- 创建 `docs/business-rules/README.md`(目录索引,按业务域列出文档)
|
||||
- 将 `docs/database/DWS/index_algorithm_cn.md` 内容复制到 `docs/business-rules/index_algorithm_cn.md`
|
||||
- 将原 `docs/database/DWS/index_algorithm_cn.md` 替换为重定向说明
|
||||
- _Requirements: 3.1, 3.2, 3.3, 3.4_
|
||||
|
||||
- [x] 2.2 创建业务规则骨架文档
|
||||
- 创建 `docs/business-rules/dws_metrics.md`(DWS 口径定义骨架)
|
||||
- 创建 `docs/business-rules/scd2_rules.md`(SCD2 处理规则骨架)
|
||||
- _Requirements: 3.4_
|
||||
|
||||
- [x] 3. 检查点 — 确认文档目录结构正确
|
||||
- 确认所有新增目录和文件已创建,如有问题请提出。
|
||||
|
||||
- [x] 4. 审计一览表生成脚本
|
||||
- [x] 4.1 实现审计记录解析模块
|
||||
- 在 `scripts/gen_audit_dashboard.py` 中实现 `AuditEntry` 数据类
|
||||
- 实现 `parse_audit_file(filepath)` 函数:从文件名提取日期/slug,从内容提取标题/修改文件/风险等级
|
||||
- 实现 `classify_module(filepath)` 函数:根据 MODULE_MAP 将文件路径映射到功能模块
|
||||
- 实现 `scan_audit_dir(dirpath)` 函数:扫描目录并返回 AuditEntry 列表
|
||||
- _Requirements: 2.1, 2.3_
|
||||
|
||||
- [x] 4.2 编写属性测试:审计记录解析-渲染完整性
|
||||
- **Property 1: 审计记录解析-渲染完整性**
|
||||
- 使用 hypothesis 生成随机审计 Markdown 内容,验证解析+渲染后表格行包含所有必要字段
|
||||
- **Validates: Requirements 2.1, 2.2**
|
||||
|
||||
- [x] 4.3 编写属性测试:文件路径模块分类正确性
|
||||
- **Property 2: 文件路径模块分类正确性**
|
||||
- 使用 hypothesis 生成随机文件路径,验证分类结果属于预定义模块集合
|
||||
- **Validates: Requirements 2.3**
|
||||
|
||||
- [x] 4.4 实现审计一览表渲染模块
|
||||
- 实现 `render_timeline_table(entries)` 函数:按时间倒序生成 Markdown 表格
|
||||
- 实现 `render_module_index(entries)` 函数:按模块分组生成 Markdown 章节
|
||||
- 实现 `render_dashboard(entries)` 函数:组合时间线和模块索引生成完整 dashboard
|
||||
- _Requirements: 2.2, 2.3, 2.4_
|
||||
|
||||
- [x] 4.5 编写属性测试:审计条目时间倒序排列
|
||||
- **Property 3: 审计条目时间倒序排列**
|
||||
- 使用 hypothesis 生成随机日期列表,验证排序后严格非递增
|
||||
- **Validates: Requirements 2.4**
|
||||
|
||||
- [x] 4.6 编写单元测试
|
||||
- 使用真实审计文件作为测试输入验证解析正确性
|
||||
- 测试边界情况:空目录、格式异常文件、缺少章节的文件
|
||||
- _Requirements: 2.1, 2.3_
|
||||
|
||||
- [x] 4.7 实现主入口并生成 audit_dashboard.md
|
||||
- 实现 `main()` 函数:扫描 → 解析 → 渲染 → 写入 `docs/audit/audit_dashboard.md`
|
||||
- 运行脚本生成实际的 audit_dashboard.md 文件
|
||||
- _Requirements: 2.5, 2.6_
|
||||
|
||||
- [x] 5. 更新文档总索引
|
||||
- [x] 5.1 更新 `docs/README.md`
|
||||
- 添加 `architecture/`、`business-rules/`、`operations/` 三个新目录的条目和说明
|
||||
- 添加 `CHANGELOG.md` 条目
|
||||
- 添加 `audit/audit_dashboard.md` 条目
|
||||
- 移除过时条目(如 `data_exports/`、`templates/`、`test-json-doc/` 如果不存在)
|
||||
- 确保所有一级目录都有对应链接
|
||||
- _Requirements: 1.1, 1.2, 3.5_
|
||||
|
||||
- [x] 6. 最终检查点 — 确认所有文件完整
|
||||
- 确认所有测试通过,所有文档文件已创建,审计一览表已生成,如有问题请提出。
|
||||
|
||||
## 备注
|
||||
|
||||
- 标记 `*` 的任务为可选测试任务,可跳过以加速 MVP
|
||||
- 每个任务引用了具体的需求编号以便追溯
|
||||
- 检查点用于增量验证
|
||||
- 属性测试验证通用正确性属性,单元测试验证具体例子和边界情况
|
||||
1
.kiro/specs/etl-task-documentation/.config.kiro
Normal file
1
.kiro/specs/etl-task-documentation/.config.kiro
Normal file
@@ -0,0 +1 @@
|
||||
{"generationMode": "requirements-first"}
|
||||
285
.kiro/specs/etl-task-documentation/design.md
Normal file
285
.kiro/specs/etl-task-documentation/design.md
Normal file
@@ -0,0 +1,285 @@
|
||||
# 设计文档:ETL 任务说明文档
|
||||
|
||||
## 概述
|
||||
|
||||
本设计描述如何为飞球 ETL 系统生成一套完整的任务说明文档,放置于 `docs/etl_tasks/` 目录下。文档以 Markdown 格式编写,按数据层(ODS / DWD / DWS / INDEX / Utility)分文件组织,并提供一个总览 README 作为入口。
|
||||
|
||||
文档的目标读者是开发者和运维人员,需要覆盖:
|
||||
- 每个任务的代码标识、Python 类、数据来源与目标
|
||||
- Extract / Transform / Load 各阶段的处理逻辑
|
||||
- CLI 参数与管道执行方式
|
||||
- BaseTask 公共机制
|
||||
|
||||
## 架构
|
||||
|
||||
文档为纯静态 Markdown 文件,不涉及运行时代码变更。整体结构如下:
|
||||
|
||||
```
|
||||
docs/etl_tasks/
|
||||
├── README.md # 总览:任务清单 + 跳转链接 + 执行方式
|
||||
├── ods_tasks.md # ODS 层任务详解
|
||||
├── dwd_tasks.md # DWD 层任务详解
|
||||
├── dws_tasks.md # DWS 层任务详解
|
||||
├── index_tasks.md # INDEX 层任务详解
|
||||
├── utility_tasks.md # 工具类任务详解
|
||||
└── base_task_mechanism.md # BaseTask 公共机制与执行参数
|
||||
```
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
README["README.md<br/>总览入口"] --> ODS["ods_tasks.md"]
|
||||
README --> DWD["dwd_tasks.md"]
|
||||
README --> DWS["dws_tasks.md"]
|
||||
README --> IDX["index_tasks.md"]
|
||||
README --> UTL["utility_tasks.md"]
|
||||
README --> BASE["base_task_mechanism.md"]
|
||||
```
|
||||
|
||||
## 组件与接口
|
||||
|
||||
本 spec 不涉及代码组件。产出物为 7 个 Markdown 文件,各文件的内容范围如下:
|
||||
|
||||
### README.md(总览)
|
||||
|
||||
| 章节 | 内容 |
|
||||
|------|------|
|
||||
| 系统简介 | 飞球 ETL 系统概述、数据流向(API → ODS → DWD → DWS) |
|
||||
| 任务清单 | 按层分组的表格:任务代码、Python 类、简要说明、跳转链接 |
|
||||
| 管道类型 | 7 种管道(api_ods / api_ods_dwd / api_full / ods_dwd / dwd_dws / dwd_dws_index / dwd_index)的层组合 |
|
||||
| 处理模式 | increment_only / verify_only / increment_verify 的区别 |
|
||||
| 数据源模式 | online / offline / hybrid 的区别 |
|
||||
| CLI 参数速查 | 所有 CLI 参数的表格(参数名、类型、默认值、说明) |
|
||||
| 常见命令示例 | 典型使用场景的命令行示例 |
|
||||
|
||||
### ods_tasks.md(ODS 层)
|
||||
|
||||
每个 ODS 任务一个小节,包含:
|
||||
- 任务代码与 Python 类
|
||||
- API 端点与请求参数
|
||||
- 字段解析逻辑(transform 阶段)
|
||||
- 目标 ODS 表与写入策略
|
||||
- 特殊说明(如分页、去重、content_hash 等)
|
||||
|
||||
需区分两种 ODS 任务模式:
|
||||
1. 独立任务类(如 OrdersTask、MembersTask):继承 BaseTask,有独立的 E/T/L 实现
|
||||
2. 通用 ODS 任务(由 `ods_tasks.py` 中 OdsTaskSpec + BaseOdsTask 动态生成):通过声明式配置定义端点、列映射等
|
||||
|
||||
已注册的 ODS 任务(14 个独立 + N 个通用):
|
||||
|
||||
| 任务代码 | Python 类 | API 端点 | 目标表 |
|
||||
|----------|-----------|----------|--------|
|
||||
| ORDERS | OrdersTask | /Site/GetAllOrderSettleList | billiards_ods.fact_order |
|
||||
| PAYMENTS | PaymentsTask | 支付相关端点 | billiards_ods.fact_payment |
|
||||
| MEMBERS | MembersTask | /MemberProfile/GetTenantMemberList | billiards_ods.dim_member |
|
||||
| PRODUCTS | ProductsTask | 商品相关端点 | billiards_ods 商品表 |
|
||||
| TABLES | TablesTask | 台桌相关端点 | billiards_ods 台桌表 |
|
||||
| ASSISTANTS | AssistantsTask | 助教相关端点 | billiards_ods 助教表 |
|
||||
| PACKAGES_DEF | PackagesDefTask | 套餐相关端点 | billiards_ods 套餐表 |
|
||||
| REFUNDS | RefundsTask | 退款相关端点 | billiards_ods 退款表 |
|
||||
| COUPON_USAGE | CouponUsageTask | 优惠券相关端点 | billiards_ods 优惠券表 |
|
||||
| INVENTORY_CHANGE | InventoryChangeTask | 库存变动端点 | billiards_ods 库存表 |
|
||||
| TOPUPS | TopupsTask | 充值相关端点 | billiards_ods 充值表 |
|
||||
| TABLE_DISCOUNT | TableDiscountTask | 台费折扣端点 | billiards_ods 折扣表 |
|
||||
| ASSISTANT_ABOLISH | AssistantAbolishTask | 助教取消端点 | billiards_ods 取消表 |
|
||||
| LEDGER | LedgerTask | 台账端点 | billiards_ods 台账表 |
|
||||
|
||||
通用 ODS 任务由 `ODS_TASK_CLASSES` 字典动态注册,每个任务通过 `OdsTaskSpec` 声明:
|
||||
- `endpoint`:API 端点路径
|
||||
- `table`:目标 ODS 表名
|
||||
- `columns`:列定义列表(ColumnSpec)
|
||||
- `page_size`、`data_path`、`list_key`:分页参数
|
||||
- `pk_columns`:主键列
|
||||
- `snapshot_mode`:快照模式(content_hash 去重)
|
||||
|
||||
### dwd_tasks.md(DWD 层)
|
||||
|
||||
DWD 层有 5 个已注册任务:
|
||||
|
||||
| 任务代码 | Python 类 | 说明 |
|
||||
|----------|-----------|------|
|
||||
| DWD_LOAD_FROM_ODS | DwdLoadTask | 核心装载任务:遍历 TABLE_MAP,维度走 SCD2,事实走增量 |
|
||||
| TICKET_DWD | TicketDwdTask | 结账小票明细 → fact_order / fact_order_goods / fact_table_usage / fact_assistant_service |
|
||||
| PAYMENTS_DWD | PaymentsDwdTask | ODS 支付记录 → fact_payment |
|
||||
| MEMBERS_DWD | MembersDwdTask | ODS 会员记录 → dim_member |
|
||||
| DWD_QUALITY_CHECK | DwdQualityTask | ODS 与 DWD 行数/金额核对,输出 JSON 报表 |
|
||||
|
||||
核心任务 DWD_LOAD_FROM_ODS 的处理逻辑:
|
||||
- TABLE_MAP 定义了 40+ 对 DWD→ODS 表映射
|
||||
- 维度表(dim_*):检测 SCD2 列是否存在,有则执行 SCD2 合并(关闭旧版+插入新版),无则执行 Type1 Upsert
|
||||
- 事实表(dwd_*、fact_*):按 fetched_at 水位线增量插入,支持 upsert 或 insert-only
|
||||
- FACT_MAPPINGS 定义了列名映射(ODS 驼峰命名 → DWD 下划线命名)
|
||||
- 每张表独立事务,单表失败不影响后续表
|
||||
|
||||
SCD2 处理流程:
|
||||
1. 从 ODS 取最新快照(DISTINCT ON 按业务主键 + fetched_at DESC)
|
||||
2. 与 DWD 当前版本(scd2_is_current=1)逐列对比
|
||||
3. 有变更:关闭旧版(scd2_end_time=now, scd2_is_current=0)+ 插入新版(version+1)
|
||||
4. 无变更:跳过
|
||||
|
||||
### dws_tasks.md(DWS 层)
|
||||
|
||||
DWS 层有 15 个已注册任务,按业务域分组:
|
||||
|
||||
**助教业绩域:**
|
||||
|
||||
| 任务代码 | Python 类 | 目标表 | 粒度 |
|
||||
|----------|-----------|--------|------|
|
||||
| DWS_ASSISTANT_DAILY | AssistantDailyTask | dws_assistant_daily_detail | 日期+助教 |
|
||||
| DWS_ASSISTANT_MONTHLY | AssistantMonthlyTask | dws_assistant_monthly_summary | 月份+助教 |
|
||||
| DWS_ASSISTANT_CUSTOMER | AssistantCustomerTask | dws_assistant_customer_stats | 日期+助教+会员 |
|
||||
| DWS_ASSISTANT_SALARY | AssistantSalaryTask | dws_assistant_salary_calc | 月份+助教 |
|
||||
| DWS_ASSISTANT_FINANCE | AssistantFinanceTask | dws_assistant_finance_analysis | 日期+助教 |
|
||||
|
||||
**会员分析域:**
|
||||
|
||||
| 任务代码 | Python 类 | 目标表 | 粒度 |
|
||||
|----------|-----------|--------|------|
|
||||
| DWS_MEMBER_CONSUMPTION | MemberConsumptionTask | dws_member_consumption_summary | 日期+会员 |
|
||||
| DWS_MEMBER_VISIT | MemberVisitTask | dws_member_visit_detail | 日期+会员+结账单 |
|
||||
|
||||
**财务统计域:**
|
||||
|
||||
| 任务代码 | Python 类 | 目标表 | 粒度 |
|
||||
|----------|-----------|--------|------|
|
||||
| DWS_FINANCE_DAILY | FinanceDailyTask | dws_finance_daily_summary | 日期 |
|
||||
| DWS_FINANCE_RECHARGE | FinanceRechargeTask | dws_finance_recharge_summary | 日期 |
|
||||
| DWS_FINANCE_INCOME_STRUCTURE | FinanceIncomeStructureTask | dws_finance_income_structure | 日期+收入类型 |
|
||||
| DWS_FINANCE_DISCOUNT_DETAIL | FinanceDiscountDetailTask | dws_finance_discount_detail | 日期+折扣类型 |
|
||||
|
||||
**运维任务:**
|
||||
|
||||
| 任务代码 | Python 类 | 说明 |
|
||||
|----------|-----------|------|
|
||||
| DWS_BUILD_ORDER_SUMMARY | DwsBuildOrderSummaryTask | 构建订单汇总中间表 |
|
||||
| DWS_RETENTION_CLEANUP | DwsRetentionCleanupTask | 按时间分层清理历史数据 |
|
||||
| DWS_MV_REFRESH_FINANCE_DAILY | DwsMvRefreshFinanceDailyTask | 刷新财务日报物化视图 |
|
||||
| DWS_MV_REFRESH_ASSISTANT_DAILY | DwsMvRefreshAssistantDailyTask | 刷新助教日报物化视图 |
|
||||
|
||||
所有 DWS 任务继承 BaseDwsTask,共享以下机制:
|
||||
- 时间分层范围计算(TimeLayer: LAST_2_DAYS / LAST_1_MONTH / LAST_3_MONTHS / LAST_6_MONTHS / ALL)
|
||||
- 配置缓存(ConfigCache):业绩档位、等级价格、奖金规则、区域分类、技能类型
|
||||
- delete-before-insert 更新策略(按日期范围先删后插,保证幂等)
|
||||
- bulk_insert / upsert 写入方法
|
||||
|
||||
### index_tasks.md(INDEX 层)
|
||||
|
||||
INDEX 层有 4 个已注册任务:
|
||||
|
||||
| 任务代码 | Python 类 | 目标表 | 指数类型 |
|
||||
|----------|-----------|--------|----------|
|
||||
| DWS_WINBACK_INDEX | WinbackIndexTask | dws_member_winback_index | WBI(回流指数) |
|
||||
| DWS_NEWCONV_INDEX | NewconvIndexTask | dws_member_newconv_index | NCI(新客转化指数) |
|
||||
| DWS_RELATION_INDEX | RelationIndexTask | dws_relation_index | RS(关系指数) |
|
||||
| DWS_ML_MANUAL_IMPORT | MlManualImportTask | dws_ml_manual_ledger | ML(手动台账导入) |
|
||||
|
||||
所有指数任务继承 BaseIndexTask,共享:
|
||||
- 参数从 `billiards_dws.cfg_index_parameters` 表加载
|
||||
- 百分位历史记录(PercentileHistory)
|
||||
- 标准化的指数计算流程
|
||||
|
||||
### utility_tasks.md(工具类)
|
||||
|
||||
| 任务代码 | Python 类 | 用途 |
|
||||
|----------|-----------|------|
|
||||
| INIT_ODS_SCHEMA | InitOdsSchemaTask | 执行 ODS + etl_admin DDL,创建必要目录 |
|
||||
| INIT_DWD_SCHEMA | InitDwdSchemaTask | 执行 DWD DDL |
|
||||
| INIT_DWS_SCHEMA | InitDwsSchemaTask | 执行 DWS DDL |
|
||||
| MANUAL_INGEST | ManualIngestTask | 从本地 JSON 文件手动入库到 ODS |
|
||||
| ODS_JSON_ARCHIVE | OdsJsonArchiveTask | 归档 ODS JSON 文件 |
|
||||
| CHECK_CUTOFF | CheckCutoffTask | 检查数据截止时间 |
|
||||
| SEED_DWS_CONFIG | SeedDwsConfigTask | 初始化 DWS 配置种子数据 |
|
||||
| DATA_INTEGRITY_CHECK | DataIntegrityTask | 数据完整性校验 |
|
||||
|
||||
### base_task_mechanism.md(公共机制)
|
||||
|
||||
覆盖内容:
|
||||
- BaseTask 模板方法流程(execute → build_context → [分段] → extract → transform → load → commit)
|
||||
- TaskContext 字段说明
|
||||
- 时间窗口计算逻辑(优先级:手动覆盖 > 游标 > 闲忙时段默认值)
|
||||
- 窗口分段(build_window_segments)
|
||||
- TaskRegistry 注册方式与元数据(TaskMeta: task_class, requires_db_config, layer, task_type)
|
||||
- PipelineRunner 管道执行流程
|
||||
- 校验框架(Verifier)概述
|
||||
|
||||
## 数据模型
|
||||
|
||||
本 spec 不涉及数据模型变更。文档中引用的数据模型均为现有系统中的表结构,包括:
|
||||
|
||||
**ODS 层表**(billiards_ods schema):
|
||||
- settlement_records, table_fee_transactions, assistant_service_records, member_profiles, payment_transactions, refund_transactions 等 20+ 表
|
||||
|
||||
**DWD 层表**(billiards_dwd schema):
|
||||
- 维度表:dim_site, dim_table, dim_assistant, dim_member, dim_member_card_account, dim_tenant_goods, dim_store_goods, dim_goods_category, dim_groupbuy_package(各含 _ex 扩展表)
|
||||
- 事实表:dwd_settlement_head, dwd_table_fee_log, dwd_table_fee_adjust, dwd_store_goods_sale, dwd_assistant_service_log, dwd_assistant_trash_event, dwd_member_balance_change, dwd_groupbuy_redemption, dwd_platform_coupon_redemption, dwd_recharge_order, dwd_payment, dwd_refund(各含 _ex 扩展表)
|
||||
|
||||
**DWS 层表**(billiards_dws schema):
|
||||
- 助教域:dws_assistant_daily_detail, dws_assistant_monthly_summary, dws_assistant_customer_stats, dws_assistant_salary_calc, dws_assistant_finance_analysis
|
||||
- 会员域:dws_member_consumption_summary, dws_member_visit_detail
|
||||
- 财务域:dws_finance_daily_summary, dws_finance_recharge_summary, dws_finance_income_structure, dws_finance_discount_detail
|
||||
- 指数域:dws_member_winback_index, dws_member_newconv_index, dws_relation_index, dws_ml_manual_ledger
|
||||
- 配置表:cfg_index_parameters, cfg_skill_type, cfg_performance_tier, cfg_level_price, cfg_bonus_rule, cfg_area_category
|
||||
|
||||
|
||||
## 正确性属性
|
||||
|
||||
*正确性属性是一种在系统所有有效执行中都应成立的特征或行为——本质上是关于系统应该做什么的形式化陈述。属性是人类可读规范与机器可验证正确性保证之间的桥梁。*
|
||||
|
||||
由于本 spec 的产出物是文档(Markdown 文件),而非运行时代码,正确性属性主要关注文档的完整性和一致性——即文档是否覆盖了所有已注册任务。
|
||||
|
||||
Property 1: ODS 任务文档覆盖完整性
|
||||
*对于所有*在 `task_registry.py` 中注册且 layer="ODS" 的任务代码,`ods_tasks.md` 中应包含该任务代码的说明章节,并列出其目标表。
|
||||
**Validates: Requirements 2.1, 2.4**
|
||||
|
||||
Property 2: DWD 任务文档覆盖完整性
|
||||
*对于所有*在 `task_registry.py` 中注册且 layer="DWD" 的任务代码,`dwd_tasks.md` 中应包含该任务代码的说明章节,并列出其源表和目标表。
|
||||
**Validates: Requirements 3.1**
|
||||
|
||||
Property 3: DWS 任务文档覆盖完整性
|
||||
*对于所有*在 `task_registry.py` 中注册且 layer="DWS" 的任务代码,`dws_tasks.md` 中应包含该任务代码的说明章节,并标注其更新策略。
|
||||
**Validates: Requirements 4.1, 4.4**
|
||||
|
||||
Property 4: INDEX 任务文档覆盖完整性
|
||||
*对于所有*在 `task_registry.py` 中注册且 layer="INDEX" 的任务代码,`index_tasks.md` 中应包含该任务代码的说明章节。
|
||||
**Validates: Requirements 5.1**
|
||||
|
||||
Property 5: Utility 任务文档覆盖完整性
|
||||
*对于所有*在 `task_registry.py` 中注册且 task_type="utility" 的任务代码,`utility_tasks.md` 中应包含该任务代码的说明章节。
|
||||
**Validates: Requirements 6.1**
|
||||
|
||||
Property 6: CLI 参数文档覆盖完整性
|
||||
*对于所有*在 `cli/main.py` 的 `parse_args()` 中定义的 CLI 参数,`README.md` 或 `base_task_mechanism.md` 中应包含该参数的说明。
|
||||
**Validates: Requirements 7.1**
|
||||
|
||||
Property 7: 管道类型文档覆盖完整性
|
||||
*对于所有*在 `PipelineRunner.PIPELINE_LAYERS` 中定义的管道类型,`README.md` 中应包含该管道类型的层组合说明。
|
||||
**Validates: Requirements 7.2**
|
||||
|
||||
## 错误处理
|
||||
|
||||
本 spec 为文档生成任务,不涉及运行时错误处理。文档编写过程中需注意:
|
||||
|
||||
1. 若源代码中的任务类或注册信息发生变更,文档可能过时——应在 README.md 中注明"最后更新日期"和"基于代码版本"
|
||||
2. 若某个任务的 API 端点或参数无法从代码中直接读取(如动态配置),应在文档中标注"参见配置文件"
|
||||
|
||||
## 测试策略
|
||||
|
||||
**单元测试(示例验证):**
|
||||
- 验证所有 7 个 Markdown 文件存在于 `docs/etl_tasks/` 目录下
|
||||
- 验证 README.md 包含指向其他 6 个文件的链接
|
||||
- 验证每个分层文件中包含对应层的所有已注册任务代码
|
||||
|
||||
**属性测试(覆盖完整性验证):**
|
||||
- 使用 pytest 编写脚本,从 `task_registry.py` 动态读取已注册任务列表
|
||||
- 解析对应的 Markdown 文件,检查每个任务代码是否出现在文档中
|
||||
- 从 `cli/main.py` 解析 CLI 参数列表,检查文档中是否覆盖
|
||||
- 属性测试库:pytest(本项目已使用),配合 parametrize 实现参数化验证
|
||||
- 每个属性测试标注对应的设计属性编号
|
||||
|
||||
**测试标注格式:**
|
||||
```python
|
||||
# Feature: etl-task-documentation, Property 1: ODS 任务文档覆盖完整性
|
||||
def test_ods_task_coverage():
|
||||
...
|
||||
```
|
||||
|
||||
由于本 spec 的产出物是静态文档,属性测试的核心价值在于确保文档与代码的一致性,防止文档遗漏任务。测试应在文档生成后运行一次即可,无需持续集成。
|
||||
119
.kiro/specs/etl-task-documentation/requirements.md
Normal file
119
.kiro/specs/etl-task-documentation/requirements.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# 需求文档:ETL 任务说明文档
|
||||
|
||||
## 简介
|
||||
|
||||
为飞球 ETL 系统(etl-billiards)生成一份完整的任务说明文档,覆盖 ODS、DWD、DWS、INDEX 四层所有已注册任务的逻辑、执行方式、参数含义及处理流程。文档面向开发者和运维人员,放置于 `docs/etl_tasks/` 目录下。
|
||||
|
||||
## 术语表
|
||||
|
||||
- **ETL_System**:飞球 ETL 系统,负责从上游 API 抽取数据并经 ODS → DWD → DWS 三层处理
|
||||
- **Task_Document**:本次生成的 ETL 任务说明文档
|
||||
- **ODS**:操作数据存储层(Operational Data Store),保留 API 原始 payload
|
||||
- **DWD**:明细数据层(Data Warehouse Detail),清洗后的维度表和事实表
|
||||
- **DWS**:数据服务层(Data Warehouse Service),汇总统计表
|
||||
- **INDEX**:指数算法层,基于 DWS 数据计算自定义业务指数
|
||||
- **BaseTask**:所有 ETL 任务的基类,提供 Extract → Transform → Load 模板方法
|
||||
- **TaskRegistry**:任务注册表,维护任务代码与任务类的映射关系
|
||||
- **TaskContext**:运行期上下文,包含 store_id、时间窗口等信息
|
||||
- **Pipeline**:管道,定义多层任务的执行顺序(如 api_ods、api_full、dwd_dws 等)
|
||||
- **Loader**:加载器,负责将转换后的数据写入目标表(upsert/insert)
|
||||
|
||||
## 需求
|
||||
|
||||
### 需求 1:文档结构与组织
|
||||
|
||||
**用户故事:** 作为开发者,我希望文档按数据层分章节组织,以便快速定位特定层的任务说明。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Task_Document SHALL 包含一个总览文件(`README.md`),列出所有层及其任务清单,并提供跳转链接
|
||||
2. THE Task_Document SHALL 按 ODS、DWD、DWS、INDEX、Utility 五个分类分别生成独立的 Markdown 文件
|
||||
3. THE Task_Document SHALL 放置于 `docs/etl_tasks/` 目录下
|
||||
4. WHEN 新增或删除任务时,THE Task_Document SHALL 通过总览文件的任务清单反映当前已注册任务的完整列表
|
||||
|
||||
### 需求 2:ODS 层任务说明
|
||||
|
||||
**用户故事:** 作为开发者,我希望了解每个 ODS 任务的 API 端点、参数、解析逻辑和目标表,以便排查数据抓取问题。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Task_Document SHALL 为每个 ODS 任务列出任务代码、对应的 Python 类、源 API 端点
|
||||
2. THE Task_Document SHALL 说明每个 ODS 任务的 extract 阶段调用的 API 参数及其含义
|
||||
3. THE Task_Document SHALL 说明每个 ODS 任务的 transform 阶段的字段解析和类型转换逻辑
|
||||
4. THE Task_Document SHALL 说明每个 ODS 任务的 load 阶段的目标表名和写入策略(upsert/insert)
|
||||
5. THE Task_Document SHALL 区分"独立 ODS 任务"(如 OrdersTask)和"通用 ODS 任务"(由 ODS_TASK_CLASSES 动态生成)两种模式
|
||||
6. THE Task_Document SHALL 说明通用 ODS 任务的 OdsTaskSpec 配置结构(端点、表名、列映射、分页参数等)
|
||||
|
||||
### 需求 3:DWD 层任务说明
|
||||
|
||||
**用户故事:** 作为开发者,我希望了解 DWD 层任务如何从 ODS 读取数据并清洗装载到维度表和事实表,以便理解数据血缘。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Task_Document SHALL 为每个 DWD 任务列出任务代码、Python 类、源 ODS 表和目标 DWD 表
|
||||
2. THE Task_Document SHALL 说明 DWD_LOAD_FROM_ODS 任务的 TABLE_MAP 映射关系及维度/事实分流逻辑
|
||||
3. THE Task_Document SHALL 说明维度表的 SCD2 处理方式(生效区间、变更检测、历史版本管理)
|
||||
4. THE Task_Document SHALL 说明事实表的增量装载方式(水位线、去重、冲突处理)
|
||||
5. THE Task_Document SHALL 说明 DWD_QUALITY_CHECK 任务的行数/金额核对逻辑和报表输出格式
|
||||
6. THE Task_Document SHALL 说明 TICKET_DWD、PAYMENTS_DWD、MEMBERS_DWD 三个独立 DWD 任务各自的处理特点
|
||||
|
||||
### 需求 4:DWS 层任务说明
|
||||
|
||||
**用户故事:** 作为开发者,我希望了解 DWS 层每个汇总任务的业务含义、数据来源和计算规则,以便验证业务报表的正确性。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Task_Document SHALL 为每个 DWS 任务列出任务代码、Python 类、目标表、主键和统计粒度
|
||||
2. THE Task_Document SHALL 说明每个 DWS 任务的数据来源表(DWD 层的哪些表)
|
||||
3. THE Task_Document SHALL 说明每个 DWS 任务的核心业务计算规则(如工资计算公式、业绩档位、排名逻辑等)
|
||||
4. THE Task_Document SHALL 说明每个 DWS 任务的更新策略(delete-before-insert 或 upsert)
|
||||
5. THE Task_Document SHALL 说明物化视图刷新任务(MV_REFRESH)的分层刷新机制和配置方式
|
||||
6. THE Task_Document SHALL 说明数据保留清理任务(RETENTION_CLEANUP)的时间分层策略和配置参数
|
||||
|
||||
### 需求 5:INDEX 层任务说明
|
||||
|
||||
**用户故事:** 作为开发者,我希望了解指数算法任务的计算逻辑和参数含义,以便调优指数模型。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Task_Document SHALL 为每个 INDEX 任务列出任务代码、Python 类、目标表和指数类型
|
||||
2. THE Task_Document SHALL 说明每个指数的计算公式或算法概要(WBI/NCI/RS/ML)
|
||||
3. THE Task_Document SHALL 说明指数参数的配置来源(cfg_index_parameters 表)和参数含义
|
||||
4. THE Task_Document SHALL 说明 ML_MANUAL_IMPORT 任务的 Excel 导入逻辑和模板格式
|
||||
|
||||
### 需求 6:工具类任务说明
|
||||
|
||||
**用户故事:** 作为运维人员,我希望了解 Schema 初始化、手动入库等工具类任务的用途和使用方式。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Task_Document SHALL 为每个工具类任务列出任务代码、Python 类和用途说明
|
||||
2. THE Task_Document SHALL 说明 INIT_ODS_SCHEMA、INIT_DWD_SCHEMA、INIT_DWS_SCHEMA 三个初始化任务执行的 DDL 文件和创建的目录
|
||||
3. THE Task_Document SHALL 说明 MANUAL_INGEST 任务的文件匹配规则、JSON 解析逻辑和入库流程
|
||||
4. THE Task_Document SHALL 说明 ODS_JSON_ARCHIVE 任务的归档策略
|
||||
5. THE Task_Document SHALL 说明 CHECK_CUTOFF 和 DATA_INTEGRITY_CHECK 任务的校验逻辑
|
||||
|
||||
### 需求 7:执行方式与参数说明
|
||||
|
||||
**用户故事:** 作为运维人员,我希望了解如何通过 CLI 和管道模式执行任务,以及各参数的含义。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Task_Document SHALL 说明 CLI 入口(`python -m cli.main`)的所有参数及其含义
|
||||
2. THE Task_Document SHALL 说明管道类型(api_ods、api_ods_dwd、api_full、ods_dwd、dwd_dws、dwd_dws_index、dwd_index)各自包含的层和执行顺序
|
||||
3. THE Task_Document SHALL 说明处理模式(increment_only、verify_only、increment_verify)的区别和适用场景
|
||||
4. THE Task_Document SHALL 说明时间窗口参数(window-start、window-end、window-split、lookback-hours、overlap-seconds)的计算逻辑
|
||||
5. THE Task_Document SHALL 说明数据源模式(online、offline、hybrid)的区别
|
||||
6. THE Task_Document SHALL 提供常见使用场景的命令示例
|
||||
|
||||
### 需求 8:BaseTask 与公共机制说明
|
||||
|
||||
**用户故事:** 作为开发者,我希望了解任务基类的模板方法和公共机制,以便开发新任务时遵循统一模式。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Task_Document SHALL 说明 BaseTask 的 Execute → Extract → Transform → Load 模板方法流程
|
||||
2. THE Task_Document SHALL 说明 TaskContext 的字段含义(store_id、window_start、window_end、window_minutes、cursor)
|
||||
3. THE Task_Document SHALL 说明时间窗口的计算逻辑(游标优先、闲忙时段、手动覆盖)
|
||||
4. THE Task_Document SHALL 说明窗口分段(build_window_segments)的切分策略
|
||||
5. THE Task_Document SHALL 说明任务注册表(TaskRegistry)的注册方式和元数据结构(layer、task_type、requires_db_config)
|
||||
125
.kiro/specs/etl-task-documentation/tasks.md
Normal file
125
.kiro/specs/etl-task-documentation/tasks.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# 实施计划:ETL 任务说明文档
|
||||
|
||||
## 概述
|
||||
|
||||
基于对 `tasks/`、`loaders/`、`orchestration/`、`cli/` 目录下源代码的分析,生成 7 个 Markdown 文档文件,放置于 `docs/etl_tasks/` 目录下。每个任务按照设计文档中定义的结构和内容范围编写。
|
||||
|
||||
## 任务
|
||||
|
||||
- [x] 1. 创建 `docs/etl_tasks/base_task_mechanism.md`
|
||||
- 说明 BaseTask 的 execute → extract → transform → load 模板方法流程
|
||||
- 说明 TaskContext 字段含义(store_id、window_start、window_end、window_minutes、cursor)
|
||||
- 说明时间窗口计算逻辑(手动覆盖 > 游标 > 闲忙时段默认值)
|
||||
- 说明窗口分段(build_window_segments)切分策略
|
||||
- 说明 TaskRegistry 注册方式与 TaskMeta 元数据结构(layer、task_type、requires_db_config)
|
||||
- 说明 PipelineRunner 管道执行流程与校验框架概述
|
||||
- _Requirements: 8.1, 8.2, 8.3, 8.4, 8.5_
|
||||
|
||||
- [x] 2. 创建 `docs/etl_tasks/ods_tasks.md`
|
||||
- [x] 2.1 编写独立 ODS 任务说明(14 个任务:ORDERS、PAYMENTS、MEMBERS、PRODUCTS、TABLES、ASSISTANTS、PACKAGES_DEF、REFUNDS、COUPON_USAGE、INVENTORY_CHANGE、TOPUPS、TABLE_DISCOUNT、ASSISTANT_ABOLISH、LEDGER)
|
||||
- 每个任务列出:任务代码、Python 类、API 端点、请求参数、字段解析逻辑、目标表、写入策略
|
||||
- _Requirements: 2.1, 2.2, 2.3, 2.4_
|
||||
- [x] 2.2 编写通用 ODS 任务说明(BaseOdsTask + OdsTaskSpec 模式)
|
||||
- 说明 OdsTaskSpec 配置结构(endpoint、table、columns、pk_columns、snapshot_mode 等)
|
||||
- 说明 BaseOdsTask 的通用 execute 流程(API 调用、schema-aware 插入、content_hash 去重、软删除标记)
|
||||
- 列出由 ODS_TASK_CLASSES 动态注册的所有任务
|
||||
- _Requirements: 2.5, 2.6_
|
||||
|
||||
- [x] 3. 创建 `docs/etl_tasks/dwd_tasks.md`
|
||||
- [x] 3.1 编写 DWD_LOAD_FROM_ODS 核心任务说明
|
||||
- 列出完整的 TABLE_MAP 映射表(DWD 表 → ODS 表)
|
||||
- 说明维度/事实分流逻辑(dim_* 走 SCD2 或 Type1 Upsert,其余走增量插入)
|
||||
- 说明 SCD2 处理流程(最新快照选取、变更检测、版本关闭与新建)
|
||||
- 说明事实表增量装载(fetched_at 水位线、upsert/insert-only、FACT_MAPPINGS 列映射)
|
||||
- _Requirements: 3.2, 3.3, 3.4_
|
||||
- [x] 3.2 编写独立 DWD 任务说明(TICKET_DWD、PAYMENTS_DWD、MEMBERS_DWD)
|
||||
- 每个任务列出:源 ODS 表、目标 DWD 表、处理特点
|
||||
- _Requirements: 3.6_
|
||||
- [x] 3.3 编写 DWD_QUALITY_CHECK 任务说明
|
||||
- 说明行数/金额核对逻辑、金额列自动扫描规则、JSON 报表输出格式
|
||||
- _Requirements: 3.5_
|
||||
|
||||
- [x] 4. 创建 `docs/etl_tasks/dws_tasks.md`
|
||||
- [x] 4.1 编写 BaseDwsTask 公共机制说明
|
||||
- 说明时间分层(TimeLayer)、配置缓存(ConfigCache)、delete-before-insert 策略、bulk_insert/upsert 方法
|
||||
- _Requirements: 4.1_
|
||||
- [x] 4.2 编写助教业绩域任务说明(5 个任务)
|
||||
- DWS_ASSISTANT_DAILY:日度服务明细聚合,数据来源、聚合维度、输出字段
|
||||
- DWS_ASSISTANT_MONTHLY:月度汇总,业绩档位计算、排名逻辑、新人封顶规则
|
||||
- DWS_ASSISTANT_CUSTOMER:助教-客户关系统计
|
||||
- DWS_ASSISTANT_SALARY:工资计算公式(基础工资+提成+奖金+扣款)
|
||||
- DWS_ASSISTANT_FINANCE:助教收支分析(收入 vs 日均成本、毛利率)
|
||||
- _Requirements: 4.2, 4.3, 4.4_
|
||||
- [x] 4.3 编写会员分析域任务说明(2 个任务)
|
||||
- DWS_MEMBER_CONSUMPTION:会员消费汇总、客户分层
|
||||
- DWS_MEMBER_VISIT:会员到店明细、服务时长、折扣计算
|
||||
- _Requirements: 4.2, 4.3, 4.4_
|
||||
- [x] 4.4 编写财务统计域任务说明(4 个任务)
|
||||
- DWS_FINANCE_DAILY:财务日报(结算汇总、团购、充值、赠卡消费、费用、平台)
|
||||
- DWS_FINANCE_RECHARGE:充值统计(首充/续充、现金/赠送、卡余额)
|
||||
- DWS_FINANCE_INCOME_STRUCTURE:收入结构分析(按类型、按区域)
|
||||
- DWS_FINANCE_DISCOUNT_DETAIL:折扣明细统计
|
||||
- _Requirements: 4.2, 4.3, 4.4_
|
||||
- [x] 4.5 编写运维任务说明(4 个任务)
|
||||
- DWS_BUILD_ORDER_SUMMARY:订单汇总中间表构建
|
||||
- DWS_RETENTION_CLEANUP:时间分层清理策略、配置参数(enabled、layer、tables、table_layers)
|
||||
- DWS_MV_REFRESH_FINANCE_DAILY / DWS_MV_REFRESH_ASSISTANT_DAILY:物化视图分层刷新机制、L1-L4 层级、配置方式
|
||||
- _Requirements: 4.5, 4.6_
|
||||
|
||||
- [x] 5. 创建 `docs/etl_tasks/index_tasks.md`
|
||||
- 编写 BaseIndexTask 公共机制(参数加载、百分位历史)
|
||||
- 编写 4 个指数任务说明:WBI(回流指数)、NCI(新客转化指数)、RS(关系指数)、ML(手动台账导入)
|
||||
- 说明 cfg_index_parameters 配置表结构和参数含义
|
||||
- 说明 ML_MANUAL_IMPORT 的 Excel 模板格式和导入逻辑
|
||||
- _Requirements: 5.1, 5.2, 5.3, 5.4_
|
||||
|
||||
- [x] 6. 创建 `docs/etl_tasks/utility_tasks.md`
|
||||
- 编写 8 个工具类任务说明:INIT_ODS_SCHEMA、INIT_DWD_SCHEMA、INIT_DWS_SCHEMA、MANUAL_INGEST、ODS_JSON_ARCHIVE、CHECK_CUTOFF、SEED_DWS_CONFIG、DATA_INTEGRITY_CHECK
|
||||
- 每个任务列出:用途、执行的 DDL/操作、配置参数
|
||||
- 重点说明 MANUAL_INGEST 的文件匹配规则和入库流程
|
||||
- _Requirements: 6.1, 6.2, 6.3, 6.4, 6.5_
|
||||
|
||||
- [x] 7. 创建 `docs/etl_tasks/README.md`(总览)
|
||||
- 编写系统简介和数据流向图(API → ODS → DWD → DWS)
|
||||
- 编写按层分组的任务清单表格(任务代码、Python 类、简要说明、跳转链接)
|
||||
- 编写管道类型说明(7 种管道的层组合)
|
||||
- 编写处理模式说明(increment_only / verify_only / increment_verify)
|
||||
- 编写数据源模式说明(online / offline / hybrid)
|
||||
- 编写 CLI 参数速查表(所有参数的表格)
|
||||
- 编写常见命令示例
|
||||
- _Requirements: 1.1, 1.2, 1.3, 7.1, 7.2, 7.3, 7.5, 7.6_
|
||||
|
||||
- [x] 8. 检查点 - 验证文档完整性
|
||||
- 确认 7 个文件全部存在于 `docs/etl_tasks/` 目录下
|
||||
- 确认 README.md 中的任务清单覆盖所有已注册任务
|
||||
- 确认各分层文件中的任务代码与 task_registry.py 一致
|
||||
- Ensure all files are valid Markdown, ask the user if questions arise.
|
||||
|
||||
- [x] 9. 编写文档覆盖完整性验证脚本
|
||||
- [x] 9.1 编写 ODS 任务覆盖验证
|
||||
- **Property 1: ODS 任务文档覆盖完整性**
|
||||
- **Validates: Requirements 2.1, 2.4**
|
||||
- [x] 9.2 编写 DWD 任务覆盖验证
|
||||
- **Property 2: DWD 任务文档覆盖完整性**
|
||||
- **Validates: Requirements 3.1**
|
||||
- [x] 9.3 编写 DWS 任务覆盖验证
|
||||
- **Property 3: DWS 任务文档覆盖完整性**
|
||||
- **Validates: Requirements 4.1, 4.4**
|
||||
- [x] 9.4 编写 INDEX 和 Utility 任务覆盖验证
|
||||
- **Property 4: INDEX 任务文档覆盖完整性**
|
||||
- **Property 5: Utility 任务文档覆盖完整性**
|
||||
- **Validates: Requirements 5.1, 6.1**
|
||||
- [x] 9.5 编写 CLI 参数和管道类型覆盖验证
|
||||
- **Property 6: CLI 参数文档覆盖完整性**
|
||||
- **Property 7: 管道类型文档覆盖完整性**
|
||||
- **Validates: Requirements 7.1, 7.2**
|
||||
|
||||
- [x] 10. 最终检查点
|
||||
- Ensure all tests pass, ask the user if questions arise.
|
||||
|
||||
## 说明
|
||||
|
||||
- 任务标记 `*` 的为可选项,可跳过以加快 MVP 进度
|
||||
- 每个任务引用了具体的需求编号以便追溯
|
||||
- 检查点确保增量验证
|
||||
- 文档编写顺序:先写公共机制(task 1),再按层写各任务(task 2-6),最后写总览(task 7)
|
||||
1
.kiro/specs/monorepo-migration/.config.kiro
Normal file
1
.kiro/specs/monorepo-migration/.config.kiro
Normal file
@@ -0,0 +1 @@
|
||||
{"generationMode": "requirements-first"}
|
||||
553
.kiro/specs/monorepo-migration/design.md
Normal file
553
.kiro/specs/monorepo-migration/design.md
Normal file
@@ -0,0 +1,553 @@
|
||||
# 设计文档:Monorepo 迁移
|
||||
|
||||
## 概述
|
||||
|
||||
本设计将现有单一 ETL 仓库(`FQ-ETL`)迁移为 Monorepo 单体仓库(`NeoZQYY`),采用一次性搬迁策略。核心设计原则:
|
||||
|
||||
1. **最小破坏性**:ETL 整体平移,保持内部结构不变,仅调整外部引用
|
||||
2. **分层隔离**:通过 uv workspace 实现 Python 包依赖隔离,通过 `.env` 分层实现配置隔离
|
||||
3. **数据库重组**:从现有 4 个 schema(billiards_ods/billiards_dwd/billiards_dws/etl_admin)重组为 6 层 schema(meta/ods/dwd/core/dws/app)
|
||||
4. **渐进式扩展**:第一阶段只建必要骨架,未来扩展点记录在 Roadmap 中
|
||||
|
||||
## 架构
|
||||
|
||||
### 整体架构
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "NeoZQYY Monorepo"
|
||||
subgraph "apps/"
|
||||
ETL["apps/etl/pipelines/feiqiu/"]
|
||||
Backend["apps/backend/ (FastAPI)"]
|
||||
Mini["apps/miniprogram/ (Donut+TDesign)"]
|
||||
Admin["apps/admin-web/ (未来)"]
|
||||
end
|
||||
|
||||
subgraph "packages/"
|
||||
Shared["packages/shared/"]
|
||||
end
|
||||
|
||||
subgraph "gui/"
|
||||
GUI["gui/ (PySide6,过渡期)"]
|
||||
end
|
||||
|
||||
subgraph "db/"
|
||||
ETLDB["db/etl_feiqiu/"]
|
||||
AppDB["db/zqyy_app/"]
|
||||
FDW["db/fdw/"]
|
||||
end
|
||||
end
|
||||
|
||||
ETL --> Shared
|
||||
Backend --> Shared
|
||||
GUI --> Shared
|
||||
Backend --> AppDB
|
||||
ETL --> ETLDB
|
||||
AppDB -.->|postgres_fdw 只读| ETLDB
|
||||
```
|
||||
|
||||
### 数据流架构
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
API["上游 SaaS API"] --> ODS["ods (原始数据)"]
|
||||
ODS --> DWD["dwd (main+EX 明细)"]
|
||||
DWD --> Core["core (统一最小字段集)"]
|
||||
DWD --> DWS["dws (汇总/工资)"]
|
||||
Core --> DWS
|
||||
DWS --> App["app (视图+RLS)"]
|
||||
App -.->|FDW 只读映射| ZqyyApp["zqyy_app DB"]
|
||||
ZqyyApp --> FastAPI["FastAPI 后端"]
|
||||
FastAPI --> MiniApp["微信小程序"]
|
||||
|
||||
subgraph "etl_feiqiu DB"
|
||||
Meta["meta (调度/游标)"]
|
||||
ODS
|
||||
DWD
|
||||
Core
|
||||
DWS
|
||||
App
|
||||
end
|
||||
```
|
||||
|
||||
## 组件与接口
|
||||
|
||||
### 1. 目录结构生成器(Scaffold)
|
||||
|
||||
负责创建 Monorepo 完整目录结构和基础配置文件。
|
||||
|
||||
**输入**:目标路径 `C:\NeoZQYY\`
|
||||
**输出**:完整目录树 + README.md + 配置文件
|
||||
|
||||
**关键行为**:
|
||||
- 创建所有一级和二级目录
|
||||
- 为每个一级目录生成 README.md(作用 + 结构 + Roadmap)
|
||||
- 生成 `.gitignore`、`.kiroignore`、`.env.template`
|
||||
- 初始化 Git 仓库
|
||||
|
||||
### 2. uv Workspace 配置
|
||||
|
||||
**根 `pyproject.toml`**:
|
||||
```toml
|
||||
[project]
|
||||
name = "neozqyy"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
[tool.uv.workspace]
|
||||
members = [
|
||||
"apps/etl/pipelines/feiqiu",
|
||||
"apps/backend",
|
||||
"packages/shared",
|
||||
"gui",
|
||||
]
|
||||
```
|
||||
|
||||
**子项目 `pyproject.toml` 模式**(以 ETL 为例):
|
||||
```toml
|
||||
[project]
|
||||
name = "etl-feiqiu"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"psycopg2-binary>=2.9.0",
|
||||
"requests>=2.28.0",
|
||||
"python-dateutil>=2.8.0",
|
||||
"tzdata>=2023.0",
|
||||
"python-dotenv",
|
||||
"openpyxl>=3.1.0",
|
||||
"neozqyy-shared",
|
||||
]
|
||||
|
||||
[tool.uv.sources]
|
||||
neozqyy-shared = { workspace = true }
|
||||
```
|
||||
|
||||
### 3. 配置隔离机制
|
||||
|
||||
**分层加载顺序**:
|
||||
```
|
||||
根 .env(公共配置)→ 应用 .env.local(私有覆盖)→ 环境变量 → CLI 参数
|
||||
```
|
||||
|
||||
**实现方式**:
|
||||
- 现有 `AppConfig` 的 `DEFAULTS < ENV < CLI` 模式保持不变
|
||||
- 新增:在 `load_env_overrides()` 中先加载根 `.env`,再加载应用级 `.env.local`
|
||||
- 冲突策略:应用级优先(后加载覆盖先加载)
|
||||
- 缺失检测:在 `_validate()` 中检查必需项,报告缺失项名称
|
||||
|
||||
### 4. ETL 平移策略
|
||||
|
||||
**平移范围**:
|
||||
| 源路径 | 目标路径 | 说明 |
|
||||
|--------|----------|------|
|
||||
| `api/` | `apps/etl/pipelines/feiqiu/api/` | API 客户端 |
|
||||
| `cli/` | `apps/etl/pipelines/feiqiu/cli/` | CLI 入口 |
|
||||
| `config/` | `apps/etl/pipelines/feiqiu/config/` | 配置 |
|
||||
| `loaders/` | `apps/etl/pipelines/feiqiu/loaders/` | 加载器 |
|
||||
| `models/` | `apps/etl/pipelines/feiqiu/models/` | 模型 |
|
||||
| `orchestration/` | `apps/etl/pipelines/feiqiu/orchestration/` | 调度 |
|
||||
| `scd/` | `apps/etl/pipelines/feiqiu/scd/` | SCD2 |
|
||||
| `tasks/` | `apps/etl/pipelines/feiqiu/tasks/` | 任务 |
|
||||
| `utils/` | `apps/etl/pipelines/feiqiu/utils/` | 工具 |
|
||||
| `quality/` | `apps/etl/pipelines/feiqiu/quality/` | 质量检查 |
|
||||
| `tests/` | `apps/etl/pipelines/feiqiu/tests/` | 测试 |
|
||||
| `database/*.sql` | `db/etl_feiqiu/schemas/` | DDL |
|
||||
| `database/migrations/` | `db/etl_feiqiu/migrations/` | 迁移脚本 |
|
||||
| `database/seed_*.sql` | `db/etl_feiqiu/seeds/` | 种子数据 |
|
||||
| `gui/` | `gui/` | GUI(顶层) |
|
||||
|
||||
**import 路径策略**:
|
||||
- ETL 内部使用相对 import(`from .config.settings import AppConfig`)或保持现有绝对 import
|
||||
- `pyproject.toml` 中设置 `pythonpath`,使 `apps/etl/pipelines/feiqiu/` 为 Python 路径根
|
||||
- `pytest.ini` 同步更新 `pythonpath = .`
|
||||
- 目标:ETL 内部代码零修改或最小修改
|
||||
|
||||
### 5. 小程序平移策略
|
||||
|
||||
**平移范围**:
|
||||
| 源路径 | 目标路径 |
|
||||
|--------|----------|
|
||||
| `C:\ZQYY\XCX\`(除 Prototype) | `apps/miniprogram/` |
|
||||
| `C:\ZQYY\XCX\Prototype\` | `docs/h5_ui/` |
|
||||
|
||||
小程序为独立前端项目(Donut + TDesign),不涉及 Python 依赖管理,直接复制即可。
|
||||
|
||||
|
||||
### 6. 数据库 Schema 重组(etl_feiqiu)
|
||||
|
||||
**现有 → 新 schema 映射**:
|
||||
|
||||
| 现有 Schema | 新 Schema | 说明 |
|
||||
|-------------|-----------|------|
|
||||
| `etl_admin` | `meta` | 调度、游标、运行记录 |
|
||||
| `billiards_ods` | `ods` | ODS 原始数据,结构不变 |
|
||||
| `billiards_dwd` | `dwd` | DWD 明细,保留 main+EX 拆分 |
|
||||
| (新增) | `core` | 统一维度/事实最小字段集 |
|
||||
| `billiards_dws` | `dws` | DWS 汇总,结构不变 |
|
||||
| (新增) | `app` | 面向外部的视图/函数 + RLS |
|
||||
|
||||
**core schema 设计原则**:
|
||||
- 仅包含跨系统共享的最小字段集(如会员 ID、姓名、手机号、状态)
|
||||
- 维度表从 DWD 维度表提取核心字段
|
||||
- 事实表从 DWD 事实表提取核心度量
|
||||
- 第一版保持精简,后续按需扩展
|
||||
|
||||
**app schema 设计原则**:
|
||||
- 以视图(VIEW)封装 DWS/Core 层数据
|
||||
- 所有视图启用 RLS,以 `site_id` 过滤
|
||||
- 提供函数接口供 FDW 映射使用
|
||||
- 不存储实际数据,仅做访问层
|
||||
|
||||
**RLS 实现方案**:
|
||||
```sql
|
||||
-- 创建应用角色
|
||||
CREATE ROLE app_reader;
|
||||
|
||||
-- 在 app schema 的视图上启用 RLS
|
||||
ALTER TABLE app.v_member_summary ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- 创建策略:根据会话变量 app.current_site_id 过滤
|
||||
CREATE POLICY site_isolation ON app.v_member_summary
|
||||
FOR SELECT TO app_reader
|
||||
USING (site_id = current_setting('app.current_site_id')::bigint);
|
||||
```
|
||||
|
||||
### 7. 业务数据库设计(zqyy_app)
|
||||
|
||||
**核心表**:
|
||||
- `users`:用户账户(微信 OpenID、手机号、角色)
|
||||
- `roles` / `permissions`:RBAC 权限模型
|
||||
- `user_roles`:用户-角色关联
|
||||
- `tasks`:任务管理(审批流)
|
||||
- `approvals`:审批记录
|
||||
|
||||
**FDW 映射**:
|
||||
```sql
|
||||
-- 在 zqyy_app 中创建外部服务器
|
||||
CREATE SERVER etl_feiqiu_server
|
||||
FOREIGN DATA WRAPPER postgres_fdw
|
||||
OPTIONS (host 'localhost', dbname 'etl_feiqiu', port '5432');
|
||||
|
||||
-- 创建用户映射
|
||||
CREATE USER MAPPING FOR app_user
|
||||
SERVER etl_feiqiu_server
|
||||
OPTIONS (user 'app_reader', password '***');
|
||||
|
||||
-- 导入 app schema 的外部表
|
||||
IMPORT FOREIGN SCHEMA app
|
||||
FROM SERVER etl_feiqiu_server
|
||||
INTO fdw_etl;
|
||||
```
|
||||
|
||||
**约束**:FDW 映射为只读,`zqyy_app` 不存储 ETL 数据副本。
|
||||
|
||||
### 8. FastAPI 后端骨架
|
||||
|
||||
**项目结构**:
|
||||
```
|
||||
apps/backend/
|
||||
├── app/
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py # FastAPI 入口
|
||||
│ ├── config.py # 配置加载
|
||||
│ ├── database.py # 数据库连接
|
||||
│ ├── routers/ # 路由模块
|
||||
│ │ └── __init__.py
|
||||
│ ├── middleware/ # 中间件
|
||||
│ │ └── __init__.py
|
||||
│ └── schemas/ # Pydantic 模型
|
||||
│ └── __init__.py
|
||||
├── tests/
|
||||
│ └── __init__.py
|
||||
├── pyproject.toml
|
||||
└── README.md
|
||||
```
|
||||
|
||||
**关键配置**:
|
||||
- 连接 `zqyy_app` 数据库(通过 FDW 访问 ETL 数据)
|
||||
- OpenAPI 文档自动生成(FastAPI 内置)
|
||||
- 依赖 `packages/shared` 获取通用工具
|
||||
|
||||
### 9. 共享包(packages/shared)
|
||||
|
||||
**模块划分**:
|
||||
```
|
||||
packages/shared/
|
||||
├── src/
|
||||
│ └── neozqyy_shared/
|
||||
│ ├── __init__.py
|
||||
│ ├── enums.py # 字段枚举定义
|
||||
│ ├── money.py # 金额精度工具(CNY, numeric(2))
|
||||
│ └── datetime_utils.py # 时间处理工具
|
||||
├── tests/
|
||||
│ └── __init__.py
|
||||
├── pyproject.toml
|
||||
└── README.md
|
||||
```
|
||||
|
||||
**提取来源**:
|
||||
- `enums.py`:从 ETL 的 `models/` 中提取通用枚举
|
||||
- `money.py`:金额四舍五入、格式化(`Decimal` + `ROUND_HALF_UP`,scale=2)
|
||||
- `datetime_utils.py`:时区转换、日期范围计算(从 `utils/` 提取)
|
||||
|
||||
### 10. .kiro 迁移
|
||||
|
||||
**迁移内容**:
|
||||
- 复制 `.kiro/steering/` 到 Monorepo
|
||||
- 更新 `product.md`:从单一 ETL 视角扩展为 Monorepo 全局视角
|
||||
- 更新 `tech.md`:新增 FastAPI、uv workspace、Donut+TDesign 等技术栈
|
||||
- 更新 `structure-lite.md`:反映 Monorepo 目录结构和模块边界
|
||||
- 更新路径引用:所有 steering 文件中的路径适配新结构
|
||||
|
||||
## 数据模型
|
||||
|
||||
### etl_feiqiu 数据库(六层 Schema)
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
META {
|
||||
bigint run_id PK
|
||||
text task_code
|
||||
timestamptz started_at
|
||||
timestamptz ended_at
|
||||
text status
|
||||
jsonb result_summary
|
||||
}
|
||||
|
||||
META ||--o{ ODS : "调度触发"
|
||||
|
||||
ODS {
|
||||
bigint id PK
|
||||
text content_hash PK
|
||||
jsonb payload
|
||||
text source_endpoint
|
||||
timestamptz fetched_at
|
||||
}
|
||||
|
||||
ODS ||--o{ DWD : "清洗装载"
|
||||
|
||||
DWD {
|
||||
bigint id PK
|
||||
timestamptz scd2_start_time
|
||||
timestamptz scd2_end_time
|
||||
int scd2_is_current
|
||||
int scd2_version
|
||||
}
|
||||
|
||||
DWD ||--o{ CORE : "提取最小字段集"
|
||||
|
||||
CORE {
|
||||
bigint id PK
|
||||
text name
|
||||
bigint site_id
|
||||
}
|
||||
|
||||
DWD ||--o{ DWS : "汇总聚合"
|
||||
CORE ||--o{ DWS : "汇总聚合"
|
||||
|
||||
DWS {
|
||||
bigint id PK
|
||||
date stat_date
|
||||
numeric amount
|
||||
bigint site_id
|
||||
}
|
||||
|
||||
DWS ||--o{ APP : "视图封装"
|
||||
|
||||
APP {
|
||||
text view_name
|
||||
text rls_policy
|
||||
}
|
||||
```
|
||||
|
||||
### zqyy_app 数据库
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
USERS {
|
||||
bigint id PK
|
||||
text wx_openid UK
|
||||
text mobile
|
||||
text nickname
|
||||
int status
|
||||
timestamptz created_at
|
||||
}
|
||||
|
||||
ROLES {
|
||||
int id PK
|
||||
text name UK
|
||||
text description
|
||||
}
|
||||
|
||||
USER_ROLES {
|
||||
bigint user_id FK
|
||||
int role_id FK
|
||||
}
|
||||
|
||||
PERMISSIONS {
|
||||
int id PK
|
||||
text resource
|
||||
text action
|
||||
}
|
||||
|
||||
ROLE_PERMISSIONS {
|
||||
int role_id FK
|
||||
int permission_id FK
|
||||
}
|
||||
|
||||
USERS ||--o{ USER_ROLES : "拥有"
|
||||
ROLES ||--o{ USER_ROLES : "分配给"
|
||||
ROLES ||--o{ ROLE_PERMISSIONS : "包含"
|
||||
PERMISSIONS ||--o{ ROLE_PERMISSIONS : "授予"
|
||||
|
||||
FDW_ETL_VIEWS {
|
||||
text foreign_table_name
|
||||
text source_schema
|
||||
text mapping_type
|
||||
}
|
||||
```
|
||||
|
||||
### 配置分层模型
|
||||
|
||||
```
|
||||
优先级(低 → 高):
|
||||
┌─────────────────────────────┐
|
||||
│ 根 .env(公共配置模板) │ DB_HOST, DB_PORT, TIMEZONE
|
||||
├─────────────────────────────┤
|
||||
│ 应用 .env.local(私有覆盖) │ DB_NAME, DB_PASSWORD, API_TOKEN
|
||||
├─────────────────────────────┤
|
||||
│ 环境变量 │ 运行时覆盖
|
||||
├─────────────────────────────┤
|
||||
│ CLI 参数 │ 最高优先级
|
||||
└─────────────────────────────┘
|
||||
```
|
||||
|
||||
|
||||
## 正确性属性
|
||||
|
||||
*属性是系统在所有有效执行中都应保持为真的特征或行为——本质上是关于系统应该做什么的形式化陈述。属性是人类可读规格与机器可验证正确性保证之间的桥梁。*
|
||||
|
||||
### Property 1: README.md 结构完整性
|
||||
|
||||
*对于任意* Monorepo 一级目录,其 README.md 文件应存在且包含"作用说明"、"结构描述"和"Roadmap"三个段落。
|
||||
|
||||
**Validates: Requirements 1.5**
|
||||
|
||||
### Property 2: Python 子项目配置完整性
|
||||
|
||||
*对于任意* uv workspace 声明的 Python 子项目成员,该子项目目录下应存在独立的 `pyproject.toml` 文件,且文件中包含 `[project]` 段落。
|
||||
|
||||
**Validates: Requirements 3.2**
|
||||
|
||||
### Property 3: 配置优先级 - .env.local 覆盖
|
||||
|
||||
*对于任意*配置项名称和两个不同的值,当根 `.env` 和应用 `.env.local` 都定义了该配置项时,配置加载器返回的值应等于 `.env.local` 中的值。
|
||||
|
||||
**Validates: Requirements 4.3**
|
||||
|
||||
### Property 4: 必需配置缺失检测
|
||||
|
||||
*对于任意*必需配置项,当所有配置层级(.env、.env.local、环境变量、CLI)均未提供该项时,配置加载器应抛出错误,且错误信息中包含该缺失配置项的名称。
|
||||
|
||||
**Validates: Requirements 4.4**
|
||||
|
||||
### Property 5: 文件迁移完整性
|
||||
|
||||
*对于任意*源-目标目录映射关系(ETL 业务代码、database 文件、tests 目录),源目录中的每个文件在目标目录的对应位置都应存在且内容一致。
|
||||
|
||||
**Validates: Requirements 5.1, 5.2, 5.3**
|
||||
|
||||
### Property 6: Schema 表定义迁移完整性
|
||||
|
||||
*对于任意*现有数据库 schema(billiards_ods、billiards_dws)中的表,新 schema(ods、dws)的 DDL 文件中应包含该表的 CREATE TABLE 定义。
|
||||
|
||||
**Validates: Requirements 7.3, 7.6**
|
||||
|
||||
### Property 7: Core schema 最小字段集
|
||||
|
||||
*对于任意* core schema 中的表,其字段数量应严格少于对应 dwd schema 中同名(或对应)表的字段数量。
|
||||
|
||||
**Validates: Requirements 7.5**
|
||||
|
||||
### Property 8: 测试数据库结构一致性
|
||||
|
||||
*对于任意*生产数据库(etl_feiqiu、zqyy_app)中的 schema 和表定义,对应的测试数据库(test_etl_feiqiu、test_zqyy_app)中应存在相同的 schema 和表结构。
|
||||
|
||||
**Validates: Requirements 9.1, 9.2**
|
||||
|
||||
### Property 9: Steering 文件路径更新
|
||||
|
||||
*对于任意* `.kiro/steering/` 目录下的文件,文件内容中不应包含旧仓库路径引用(如 `FQ-ETL`、`C:\ZQYY\FQ-ETL`)。
|
||||
|
||||
**Validates: Requirements 10.2**
|
||||
|
||||
### Property 10: 业务表 site_id 字段存在性
|
||||
|
||||
*对于任意* app schema 中的业务视图和 dws/core schema 中的业务表,其定义中应包含 `site_id` 字段。
|
||||
|
||||
**Validates: Requirements 13.1**
|
||||
|
||||
### Property 11: RLS 按 site_id 隔离
|
||||
|
||||
*对于任意* app schema 中启用了 RLS 的视图,当会话变量 `app.current_site_id` 设置为某个门店 ID 时,查询结果应仅包含该 `site_id` 的数据行。
|
||||
|
||||
**Validates: Requirements 13.2**
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 配置错误
|
||||
- **缺失必需配置**:启动时立即报错,列出所有缺失项名称,不启动服务
|
||||
- **配置值格式错误**:报告具体的配置项路径和期望格式
|
||||
- **.env 文件不存在**:使用默认值继续,不报错(.env.template 仅为模板)
|
||||
|
||||
### 迁移错误
|
||||
- **源文件不存在**:记录警告日志,继续迁移其他文件,最终汇总报告缺失文件列表
|
||||
- **目标目录已存在**:提示用户确认是否覆盖,默认不覆盖
|
||||
- **import 路径修复失败**:记录错误日志,标记需要手动修复的文件
|
||||
|
||||
### 数据库错误
|
||||
- **Schema 创建失败**:回滚当前 schema 的所有 DDL,报告失败原因
|
||||
- **FDW 连接失败**:记录错误日志,不影响本地表的正常使用
|
||||
- **RLS 策略创建失败**:回滚策略创建,报告受影响的表
|
||||
|
||||
### 测试数据库错误
|
||||
- **结构不一致**:提供 diff 工具比较生产与测试库结构差异
|
||||
- **数据迁移失败**:回滚到迁移前状态,报告失败的表和原因
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 测试框架
|
||||
- **单元测试**:`pytest`(Python 子项目)
|
||||
- **属性测试**:`hypothesis`(Python 属性测试库)
|
||||
- 每个属性测试配置最少 100 次迭代
|
||||
|
||||
### 单元测试覆盖
|
||||
|
||||
1. **Scaffold 测试**:验证目录创建、文件生成的具体示例
|
||||
2. **配置加载器测试**:验证分层加载、冲突处理、缺失检测的边界情况
|
||||
3. **迁移脚本测试**:验证文件复制、路径映射的具体场景
|
||||
4. **DDL 语法测试**:验证生成的 SQL 语法正确性
|
||||
|
||||
### 属性测试覆盖
|
||||
|
||||
每个属性测试必须引用设计文档中的属性编号:
|
||||
|
||||
- **Feature: monorepo-migration, Property 1: README.md 结构完整性** — 验证所有一级目录 README 包含必需段落
|
||||
- **Feature: monorepo-migration, Property 2: Python 子项目配置完整性** — 验证所有 workspace 成员有 pyproject.toml
|
||||
- **Feature: monorepo-migration, Property 3: 配置优先级** — 生成随机配置项,验证 .env.local 覆盖行为
|
||||
- **Feature: monorepo-migration, Property 4: 必需配置缺失检测** — 生成随机必需项组合,验证缺失报错
|
||||
- **Feature: monorepo-migration, Property 5: 文件迁移完整性** — 验证源-目标文件映射的完整性
|
||||
- **Feature: monorepo-migration, Property 6: Schema 表定义迁移完整性** — 验证现有表在新 DDL 中存在
|
||||
- **Feature: monorepo-migration, Property 7: Core schema 最小字段集** — 验证 core 表字段数少于 dwd
|
||||
- **Feature: monorepo-migration, Property 8: 测试数据库结构一致性** — 验证测试库与生产库结构相同
|
||||
- **Feature: monorepo-migration, Property 9: Steering 文件路径更新** — 验证无旧路径残留
|
||||
- **Feature: monorepo-migration, Property 10: 业务表 site_id 存在性** — 验证业务表包含 site_id
|
||||
- **Feature: monorepo-migration, Property 11: RLS 隔离** — 验证 RLS 按 site_id 过滤(集成测试)
|
||||
|
||||
### 集成测试
|
||||
|
||||
- **ETL 运行验证**:在新目录结构下运行 `pytest tests/unit`,确保所有现有测试通过
|
||||
- **数据库 Schema 验证**:在测试数据库上执行 DDL,验证 schema 创建成功
|
||||
- **FDW 连接验证**:验证 zqyy_app 通过 FDW 可读取 etl_feiqiu 的 app schema 数据
|
||||
- **uv workspace 验证**:运行 `uv sync`,验证所有子项目依赖正确解析
|
||||
186
.kiro/specs/monorepo-migration/requirements.md
Normal file
186
.kiro/specs/monorepo-migration/requirements.md
Normal file
@@ -0,0 +1,186 @@
|
||||
# 需求文档:Monorepo 迁移
|
||||
|
||||
## 简介
|
||||
|
||||
将现有台球厅运营助手项目从单一 ETL 仓库(`FQ-ETL`)扩展为 Monorepo 单体仓库(`NeoZQYY`),整合 ETL 管线、微信小程序后端、小程序前端、管理后台等多个子项目。迁移采用一次性搬迁策略,不保留 Git 历史,所有架构决策已在前期讨论中确认。
|
||||
|
||||
## 术语表
|
||||
|
||||
- **Monorepo**:单体仓库,多个子项目共存于同一 Git 仓库中
|
||||
- **ETL_Pipeline**:数据抽取-转换-加载管线,负责从上游 SaaS API 抓取数据并逐层处理
|
||||
- **ODS**:操作数据存储层(Operational Data Store),保留源 payload
|
||||
- **DWD**:明细数据层(Data Warehouse Detail),清洗后的明细数据
|
||||
- **DWS**:数据服务层(Data Warehouse Service),汇总与聚合数据
|
||||
- **Core**:统一维度/事实最小字段集层,位于 DWD 与 DWS 之间
|
||||
- **App_Schema**:应用层 schema,提供视图/函数 + RLS 供外部访问
|
||||
- **Meta_Schema**:元数据层 schema,存储 ETL 调度、游标、运行记录
|
||||
- **FDW**:PostgreSQL 外部数据包装器(Foreign Data Wrapper),用于跨库只读映射
|
||||
- **uv_Workspace**:Python 包管理工具 uv 的 workspace 模式,管理多包依赖
|
||||
- **RLS**:行级安全策略(Row Level Security),用于多门店数据隔离
|
||||
- **SCD2**:缓慢变化维度类型 2(Slowly Changing Dimension Type 2),维度历史追踪
|
||||
- **etl_feiqiu**:飞球平台 ETL 数据库实例名
|
||||
- **zqyy_app**:业务应用数据库实例名(用户/权限/任务/审批)
|
||||
- **site_id**:门店标识字段,用于多门店数据隔离
|
||||
- **Scaffold**:项目骨架,包含目录结构、配置文件、README 等基础设施
|
||||
|
||||
## 需求
|
||||
|
||||
### 需求 1:Monorepo 骨架搭建
|
||||
|
||||
**用户故事:** 作为开发者,我希望在 `C:\NeoZQYY\` 创建完整的 Monorepo 目录结构和基础配置,以便所有子项目有统一的组织方式和开发规范。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN Scaffold 初始化执行时,THE Scaffold SHALL 在 `C:\NeoZQYY\` 下创建以下一级目录:`apps/`、`gui/`、`packages/`、`db/`、`docs/`、`infra/`、`scripts/`、`samples/`、`tests/`、`tmp/`、`.kiro/`
|
||||
2. WHEN Scaffold 初始化执行时,THE Scaffold SHALL 在 `apps/` 下创建子目录:`etl/`(含 `pipelines/feiqiu/`)、`backend/`、`miniprogram/`、`admin-web/`
|
||||
3. WHEN Scaffold 初始化执行时,THE Scaffold SHALL 在 `db/` 下创建子目录:`etl_feiqiu/`(含 `schemas/`、`migrations/`、`seeds/`)、`zqyy_app/`(含 `schemas/`、`migrations/`、`seeds/`)、`fdw/`
|
||||
4. WHEN Scaffold 初始化执行时,THE Scaffold SHALL 在 `docs/` 下创建子目录:`prd/`、`contracts/`(含 `openapi/`、`schemas/`、`data_dictionary/`)、`permission_matrix/`、`architecture/`、`database/`、`h5_ui/`、`ops/`、`audit/`、`roadmap/`
|
||||
5. THE Scaffold SHALL 为每个一级目录生成 `README.md` 文件,包含该目录的作用说明、内部结构描述和 Roadmap 段落
|
||||
6. WHEN 某个功能"暂不实施但未来必须做"时,THE Scaffold SHALL 将该内容记录在对应目录 `README.md` 的 Roadmap 段落中
|
||||
|
||||
### 需求 2:Git 仓库与版本控制配置
|
||||
|
||||
**用户故事:** 作为开发者,我希望新 Monorepo 有正确的 Git 配置,以便代码版本管理规范且安全。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN Git 仓库初始化时,THE Scaffold SHALL 创建新的 Git 仓库,不迁移旧仓库历史
|
||||
2. THE Scaffold SHALL 生成 `.gitignore` 文件,排除 `tmp/`、`__pycache__/`、`.env`(非模板)、`*.pyc`、`.hypothesis/`、`.pytest_cache/`、`logs/`、`node_modules/`、虚拟环境目录等
|
||||
3. THE Scaffold SHALL 生成 `.kiroignore` 文件,排除不需要 Kiro 索引的目录
|
||||
|
||||
### 需求 3:Python 包管理与 uv Workspace 配置
|
||||
|
||||
**用户故事:** 作为开发者,我希望使用 `pyproject.toml` + `uv` workspace 管理多包依赖,以便各子项目的依赖隔离且可统一管理。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Scaffold SHALL 在 Monorepo 根目录生成 `pyproject.toml`,配置 uv workspace 并声明所有 Python 子项目成员
|
||||
2. THE Scaffold SHALL 为每个 Python 子项目(`apps/etl/pipelines/feiqiu/`、`apps/backend/`、`packages/shared/`、`gui/`)生成独立的 `pyproject.toml`
|
||||
3. WHEN 子项目声明对 `packages/shared` 的依赖时,THE uv_Workspace SHALL 通过 workspace 路径引用解析该依赖
|
||||
|
||||
### 需求 4:环境配置隔离
|
||||
|
||||
**用户故事:** 作为开发者,我希望公共配置和各应用私有配置分层管理,以便敏感信息不泄露且配置不冲突。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Scaffold SHALL 在 Monorepo 根目录生成 `.env.template` 文件,包含公共配置项(数据库主机、端口等非敏感信息)的模板
|
||||
2. WHEN 各应用需要私有配置时,THE Scaffold SHALL 支持在应用目录下放置 `.env.local` 文件覆盖公共配置
|
||||
3. IF 公共 `.env` 与应用 `.env.local` 存在同名配置项且值冲突,THEN THE 配置加载器 SHALL 以应用级 `.env.local` 的值为准
|
||||
4. IF 必需的配置项在所有层级均缺失,THEN THE 配置加载器 SHALL 在启动时报告明确的错误信息,指出缺失的配置项名称
|
||||
|
||||
### 需求 5:ETL 项目平移
|
||||
|
||||
**用户故事:** 作为开发者,我希望将现有 ETL 项目整体平移到 Monorepo 中,以便 ETL 功能在新仓库中正常运行。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN ETL 平移执行时,THE 迁移脚本 SHALL 将 `C:\ZQYY\FQ-ETL` 的业务代码(`api/`、`cli/`、`config/`、`loaders/`、`models/`、`orchestration/`、`scd/`、`tasks/`、`utils/`、`quality/`)复制到 `apps/etl/pipelines/feiqiu/`
|
||||
2. WHEN ETL 平移执行时,THE 迁移脚本 SHALL 将 `database/` 目录的 DDL、seed、migration 文件迁移到 `db/etl_feiqiu/` 对应子目录
|
||||
3. WHEN ETL 平移执行时,THE 迁移脚本 SHALL 将 `tests/` 目录复制到 `apps/etl/pipelines/feiqiu/tests/`
|
||||
4. WHEN ETL 平移完成后,THE ETL_Pipeline SHALL 通过 `pytest tests/unit` 验证所有单元测试通过
|
||||
5. IF ETL 内部存在需要调整的 import 路径,THEN THE 迁移脚本 SHALL 更新这些路径以适配新目录结构
|
||||
6. WHEN ETL 平移执行时,THE 迁移脚本 SHALL 将现有 `gui/` 目录迁移到 Monorepo 顶层 `gui/`
|
||||
|
||||
### 需求 6:小程序前端平移
|
||||
|
||||
**用户故事:** 作为开发者,我希望将微信小程序项目迁移到 Monorepo 中,以便前端代码与后端统一管理。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 小程序平移执行时,THE 迁移脚本 SHALL 将 `C:\ZQYY\XCX` 的项目文件复制到 `apps/miniprogram/`
|
||||
2. WHEN 小程序平移执行时,THE 迁移脚本 SHALL 将 `C:\ZQYY\XCX\Prototype` 目录复制到 `docs/h5_ui/`
|
||||
3. WHEN 小程序平移完成后,THE 小程序项目 SHALL 保持原有的 Donut + TDesign 技术栈配置不变
|
||||
|
||||
### 需求 7:数据库 Schema 重组(etl_feiqiu)
|
||||
|
||||
**用户故事:** 作为数据工程师,我希望将 ETL 数据库重组为六层 schema 架构,以便数据分层清晰、职责明确。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE 数据库迁移 SHALL 为 `etl_feiqiu` 数据库创建六个 schema:`meta`、`ods`、`dwd`、`core`、`dws`、`app`
|
||||
2. WHEN `meta` schema 创建时,THE DDL SHALL 包含 ETL 调度、游标、运行记录相关表(从现有 `etl_admin` schema 迁移)
|
||||
3. WHEN `ods` schema 创建时,THE DDL SHALL 包含现有 `billiards_ods` 的所有表定义
|
||||
4. WHEN `dwd` schema 创建时,THE DDL SHALL 保留现有 main + EX 拆分模式(因字段量大)
|
||||
5. WHEN `core` schema 创建时,THE DDL SHALL 仅包含统一维度表和事实表的最小字段集
|
||||
6. WHEN `dws` schema 创建时,THE DDL SHALL 包含现有 `billiards_dws` 的汇总表定义(助教业绩、财务日报、工资计算等)
|
||||
7. WHEN `app` schema 创建时,THE DDL SHALL 创建面向外部访问的视图和函数,并配置 RLS 策略以 `site_id` 隔离多门店数据
|
||||
8. THE 数据库迁移 SHALL 将所有 DDL 文件存放在 `db/etl_feiqiu/schemas/` 目录下,每个 schema 一个独立文件
|
||||
|
||||
### 需求 8:业务数据库设计(zqyy_app)
|
||||
|
||||
**用户故事:** 作为后端开发者,我希望有独立的业务数据库存储用户、权限、任务、审批等应用数据,以便业务逻辑与 ETL 数据解耦。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE 数据库迁移 SHALL 为 `zqyy_app` 数据库创建用户管理、权限控制、任务管理、审批流程相关的表结构
|
||||
2. THE 数据库迁移 SHALL 将 `zqyy_app` 的 DDL 文件存放在 `db/zqyy_app/schemas/` 目录下
|
||||
3. WHEN `zqyy_app` 需要访问 ETL 数据时,THE FDW 配置 SHALL 通过 `postgres_fdw` 将 `etl_feiqiu` 的 `app` schema 映射为 `zqyy_app` 中的外部表
|
||||
4. THE FDW 配置 SHALL 以只读方式映射,`zqyy_app` 不存储 ETL 数据的副本
|
||||
5. THE FDW 配置文件 SHALL 存放在 `db/fdw/` 目录下
|
||||
|
||||
### 需求 9:测试数据库镜像
|
||||
|
||||
**用户故事:** 作为开发者,我希望有与生产结构完全一致的测试数据库,以便在不影响生产数据的情况下进行开发和测试。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE 数据库迁移 SHALL 创建 `test_etl_feiqiu` 数据库,其 schema 结构与 `etl_feiqiu` 完全一致
|
||||
2. THE 数据库迁移 SHALL 创建 `test_zqyy_app` 数据库,其 schema 结构与 `zqyy_app` 完全一致
|
||||
3. WHEN 测试数据库创建完成后,THE 迁移脚本 SHALL 提供从现有 `LLZQ-test` 数据库迁移测试数据到新结构的脚本
|
||||
4. WHEN 生产数据库 schema 发生变更时,THE 测试数据库 SHALL 同步应用相同的迁移脚本以保持结构一致
|
||||
|
||||
### 需求 10:.kiro 配置迁移与 Steering 更新
|
||||
|
||||
**用户故事:** 作为开发者,我希望 Kiro IDE 的配置和 steering 文件适配 Monorepo 结构,以便 AI 辅助开发在新仓库中正常工作。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN .kiro 迁移执行时,THE 迁移脚本 SHALL 将现有 `.kiro/steering/` 文件复制到 Monorepo 的 `.kiro/steering/`
|
||||
2. WHEN .kiro 迁移完成后,THE Steering 文件 SHALL 更新所有路径引用以反映 Monorepo 目录结构
|
||||
3. WHEN .kiro 迁移完成后,THE Steering 文件 SHALL 更新 `product.md`、`tech.md`、`structure.md` 为 Monorepo 视角的内容
|
||||
|
||||
### 需求 11:FastAPI 后端骨架
|
||||
|
||||
**用户故事:** 作为后端开发者,我希望有 FastAPI 项目骨架,以便快速开始小程序后端 API 的开发。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 后端骨架创建时,THE Scaffold SHALL 在 `apps/backend/` 下生成 FastAPI 项目结构,包含入口文件、路由目录、中间件目录、配置文件
|
||||
2. THE 后端骨架 SHALL 配置 OpenAPI 文档自动生成
|
||||
3. THE 后端骨架 SHALL 配置数据库连接模块,支持连接 `zqyy_app` 数据库
|
||||
4. THE 后端骨架 SHALL 包含独立的 `pyproject.toml`,声明 FastAPI 及相关依赖
|
||||
|
||||
### 需求 12:共享包基础结构
|
||||
|
||||
**用户故事:** 作为开发者,我希望有统一的共享包存放跨项目复用的工具代码,以便避免代码重复。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 共享包创建时,THE Scaffold SHALL 在 `packages/shared/` 下生成 Python 包结构,包含 `__init__.py` 和 `pyproject.toml`
|
||||
2. THE 共享包 SHALL 提取并包含以下通用工具模块:字段枚举定义、金额精度处理工具(CNY,numeric(2))、时间处理工具
|
||||
3. WHEN ETL 或后端项目引用共享包时,THE uv_Workspace SHALL 通过 workspace 路径依赖解析 `packages/shared`
|
||||
|
||||
### 需求 13:多门店数据隔离
|
||||
|
||||
**用户故事:** 作为系统架构师,我希望在同一数据库内通过 RLS 实现多门店数据隔离,以便未来扩展到多门店场景。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE 数据库设计 SHALL 在所有业务表中包含 `site_id` 字段标识门店归属
|
||||
2. WHEN RLS 策略启用时,THE 数据库 SHALL 根据当前会话的 `site_id` 参数自动过滤查询结果,仅返回该门店的数据
|
||||
3. WHEN 每个门店运行 ETL 时,THE ETL_Pipeline SHALL 作为独立进程执行,使用该门店的 `site_id` 标识数据
|
||||
|
||||
### 需求 14:基础设施配置管理
|
||||
|
||||
**用户故事:** 作为运维人员,我希望基础设施配置纳入版本控制,以便环境配置可追溯、可复现。
|
||||
|
||||
### 需求15:避免影响kiro性能,完成Monorepo后,根据文件和目录结构。编辑.kiroignore
|
||||
|
||||
验收标准:完善
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Scaffold SHALL 在 `infra/` 下创建 `jump_proxy/`、`tailscale/`、`firewall/` 子目录
|
||||
2. THE infra 目录 SHALL 纳入 Git 版本控制
|
||||
3. IF infra 目录中包含敏感配置文件,THEN THE `.gitignore` SHALL 排除这些敏感文件,同时保留非敏感的配置模板
|
||||
215
.kiro/specs/monorepo-migration/tasks.md
Normal file
215
.kiro/specs/monorepo-migration/tasks.md
Normal file
@@ -0,0 +1,215 @@
|
||||
# 实施计划:Monorepo 迁移
|
||||
|
||||
## 概述
|
||||
|
||||
将现有 ETL 仓库迁移为 Monorepo 单体仓库,分 7 个阶段执行。每个阶段包含具体的代码/文件操作任务,按依赖顺序排列。
|
||||
|
||||
## 任务
|
||||
|
||||
- [x] 1. Monorepo 骨架搭建
|
||||
- [x] 1.1 在 `C:\NeoZQYY\` 创建完整目录结构
|
||||
- 创建所有一级目录:`apps/`、`gui/`、`packages/`、`db/`、`docs/`、`infra/`、`scripts/`、`samples/`、`tests/`、`tmp/`、`.kiro/`
|
||||
- 创建 `apps/` 子目录:`etl/pipelines/feiqiu/`、`backend/`、`miniprogram/`、`admin-web/`
|
||||
- 创建 `db/` 子目录:`etl_feiqiu/schemas/`、`etl_feiqiu/migrations/`、`etl_feiqiu/seeds/`、`zqyy_app/schemas/`、`zqyy_app/migrations/`、`zqyy_app/seeds/`、`fdw/`
|
||||
- 创建 `docs/` 子目录:`prd/`、`contracts/openapi/`、`contracts/schemas/`、`contracts/data_dictionary/`、`permission_matrix/`、`architecture/`、`database/`、`h5_ui/`、`ops/`、`audit/`、`roadmap/`
|
||||
- 创建 `infra/` 子目录:`jump_proxy/`、`tailscale/`、`firewall/`
|
||||
- _Requirements: 1.1, 1.2, 1.3, 1.4, 14.1_
|
||||
|
||||
- [x] 1.2 生成所有一级目录的 README.md
|
||||
- 每个 README 包含:作用说明、内部结构描述、Roadmap 段落
|
||||
- 一级目录列表:`apps/`、`gui/`、`packages/`、`db/`、`docs/`、`infra/`、`scripts/`、`samples/`、`tests/`
|
||||
- `apps/etl/README.md` 的 Roadmap 记录未来 sdk/connectors 拆分计划
|
||||
- `packages/README.md` 的 Roadmap 记录 etl_sdk、authz、data_contracts 候选
|
||||
- `db/README.md` 的 Roadmap 记录 FDW 演进计划
|
||||
- _Requirements: 1.5, 1.6_
|
||||
|
||||
- [x] 1.3 编写 README 结构完整性属性测试
|
||||
- **Property 1: README.md 结构完整性**
|
||||
- **Validates: Requirements 1.5**
|
||||
|
||||
- [x] 1.4 初始化 Git 仓库并生成版本控制配置
|
||||
- 在 `C:\NeoZQYY\` 执行 `git init`
|
||||
- 生成 `.gitignore`:排除 `tmp/`、`__pycache__/`、`.env`、`*.pyc`、`.hypothesis/`、`.pytest_cache/`、`logs/`、`node_modules/`、虚拟环境目录、`infra/` 下的敏感文件
|
||||
- 生成 `.kiroignore`
|
||||
- _Requirements: 2.1, 2.2, 2.3, 14.2, 14.3_
|
||||
|
||||
- [x] 1.5 配置 pyproject.toml 和 uv workspace
|
||||
- 生成根 `pyproject.toml`,声明 workspace 成员:`apps/etl/pipelines/feiqiu`、`apps/backend`、`packages/shared`、`gui`
|
||||
- 为每个 Python 子项目生成独立 `pyproject.toml`
|
||||
- _Requirements: 3.1, 3.2_
|
||||
|
||||
- [x] 1.6 编写 Python 子项目配置完整性属性测试
|
||||
- **Property 2: Python 子项目配置完整性**
|
||||
- **Validates: Requirements 3.2**
|
||||
|
||||
- [x] 1.7 生成环境配置模板
|
||||
- 生成根 `.env.template`,包含公共配置项模板(DB_HOST、DB_PORT、TIMEZONE 等)
|
||||
- _Requirements: 4.1_
|
||||
|
||||
- [x] 2. 检查点 - 骨架验证
|
||||
- 确保所有目录和文件已创建,ask the user if questions arise.
|
||||
|
||||
- [x] 3. ETL 项目平移
|
||||
- [x] 3.1 复制 ETL 业务代码到 Monorepo
|
||||
- 将 `C:\ZQYY\FQ-ETL` 的 `api/`、`cli/`、`config/`、`loaders/`、`models/`、`orchestration/`、`scd/`、`tasks/`、`utils/`、`quality/` 复制到 `apps/etl/pipelines/feiqiu/`
|
||||
- 将 `tests/` 复制到 `apps/etl/pipelines/feiqiu/tests/`
|
||||
- 将 `requirements.txt`、`pytest.ini`、`run_etl.bat`、`run_etl.sh` 复制到 `apps/etl/pipelines/feiqiu/`
|
||||
- _Requirements: 5.1, 5.3_
|
||||
|
||||
- [x] 3.2 迁移数据库文件到 db/etl_feiqiu/
|
||||
- 将 `database/schema_*.sql` 复制到 `db/etl_feiqiu/schemas/`
|
||||
- 将 `database/migrations/` 复制到 `db/etl_feiqiu/migrations/`
|
||||
- 将 `database/seed_*.sql` 复制到 `db/etl_feiqiu/seeds/`
|
||||
- 将 `database/connection.py`、`database/operations.py`、`database/base.py` 保留在 ETL 内部(`apps/etl/pipelines/feiqiu/database/`)
|
||||
- _Requirements: 5.2_
|
||||
|
||||
- [x] 3.3 迁移 GUI 到顶层
|
||||
- 将 `C:\ZQYY\FQ-ETL\gui/` 复制到 `C:\NeoZQYY\gui/`
|
||||
- 生成 `gui/pyproject.toml`,声明 PySide6 依赖
|
||||
- _Requirements: 5.6_
|
||||
|
||||
- [x] 3.4 调整 ETL 的 pyproject.toml 和 pytest.ini
|
||||
- 更新 `apps/etl/pipelines/feiqiu/pyproject.toml`,从 `requirements.txt` 提取依赖
|
||||
- 更新 `apps/etl/pipelines/feiqiu/pytest.ini`,设置 `pythonpath = .`
|
||||
- _Requirements: 5.4, 5.5_
|
||||
|
||||
- [x] 3.5 编写文件迁移完整性属性测试
|
||||
- **Property 5: 文件迁移完整性**
|
||||
- **Validates: Requirements 5.1, 5.2, 5.3**
|
||||
|
||||
- [x] 4. 检查点 - ETL 平移验证
|
||||
- 在 `apps/etl/pipelines/feiqiu/` 下运行 `pytest tests/unit`,确保所有单元测试通过
|
||||
- Ensure all tests pass, ask the user if questions arise.
|
||||
|
||||
- [x] 5. 小程序前端平移
|
||||
- [x] 5.1 复制小程序项目到 Monorepo
|
||||
- 将 `C:\ZQYY\XCX\`(除 Prototype 目录)复制到 `apps/miniprogram/`
|
||||
- 将 `C:\ZQYY\XCX\Prototype\` 复制到 `docs/h5_ui/`
|
||||
- 生成 `apps/miniprogram/README.md`
|
||||
- _Requirements: 6.1, 6.2, 6.3_
|
||||
|
||||
- [x] 6. 数据库 Schema 重组
|
||||
- [x] 6.1 编写 etl_feiqiu 六层 Schema DDL
|
||||
- 创建 `db/etl_feiqiu/schemas/meta.sql`:从现有 `etl_admin` schema 迁移调度、游标、运行记录表
|
||||
- 创建 `db/etl_feiqiu/schemas/ods.sql`:从现有 `billiards_ods` 迁移所有表定义,schema 名改为 `ods`
|
||||
- 创建 `db/etl_feiqiu/schemas/dwd.sql`:从现有 `billiards_dwd` 迁移,保留 main+EX 拆分
|
||||
- 创建 `db/etl_feiqiu/schemas/core.sql`:设计统一维度/事实最小字段集表
|
||||
- 创建 `db/etl_feiqiu/schemas/dws.sql`:从现有 `billiards_dws` 迁移汇总表
|
||||
- 创建 `db/etl_feiqiu/schemas/app.sql`:创建面向外部的视图 + RLS 策略(以 `site_id` 隔离)
|
||||
- _Requirements: 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8_
|
||||
|
||||
- [x] 6.2 编写 Schema 表定义迁移完整性属性测试
|
||||
- **Property 6: Schema 表定义迁移完整性**
|
||||
- **Validates: Requirements 7.3, 7.6**
|
||||
|
||||
- [x] 6.3 编写 Core schema 最小字段集属性测试
|
||||
- **Property 7: Core schema 最小字段集**
|
||||
- **Validates: Requirements 7.5**
|
||||
|
||||
- [x] 6.4 编写 zqyy_app 数据库 Schema DDL
|
||||
- 创建 `db/zqyy_app/schemas/init.sql`:用户表、角色表、权限表、用户角色关联表、任务表、审批表
|
||||
- 所有业务表包含 `site_id` 字段
|
||||
- _Requirements: 8.1, 8.2, 13.1_
|
||||
|
||||
- [x] 6.5 编写 FDW 映射配置
|
||||
- 创建 `db/fdw/setup_fdw.sql`:CREATE SERVER、CREATE USER MAPPING(只读角色)、IMPORT FOREIGN SCHEMA
|
||||
- _Requirements: 8.3, 8.4, 8.5_
|
||||
|
||||
- [x] 6.6 编写业务表 site_id 存在性属性测试
|
||||
- **Property 10: 业务表 site_id 字段存在性**
|
||||
- **Validates: Requirements 13.1**
|
||||
|
||||
- [x] 6.7 编写测试数据库创建脚本
|
||||
- 创建 `db/etl_feiqiu/scripts/create_test_db.sql`:创建 `test_etl_feiqiu`,复用生产 DDL
|
||||
- 创建 `db/zqyy_app/scripts/create_test_db.sql`:创建 `test_zqyy_app`,复用生产 DDL
|
||||
- 创建 `db/scripts/migrate_test_data.sql`:从 `LLZQ-test` 迁移测试数据的脚本
|
||||
- _Requirements: 9.1, 9.2, 9.3_
|
||||
|
||||
- [x] 6.8 编写测试数据库结构一致性属性测试
|
||||
- **Property 8: 测试数据库结构一致性**
|
||||
- **Validates: Requirements 9.1, 9.2**
|
||||
|
||||
- [x] 7. 检查点 - 数据库 Schema 验证
|
||||
- 确保所有 DDL 文件语法正确,ask the user if questions arise.
|
||||
|
||||
|
||||
- [ ] 8. .kiro 迁移与 Steering 更新
|
||||
- [-] 8.1 复制 .kiro/steering/ 到 Monorepo
|
||||
- 将 `C:\ZQYY\FQ-ETL\.kiro\steering\` 所有文件复制到 `C:\NeoZQYY\.kiro\steering\`
|
||||
- 将 `C:\ZQYY\FQ-ETL\.kiro\specs\` 复制到 `C:\NeoZQYY\.kiro\specs\`(包含本 spec)
|
||||
- _Requirements: 10.1_
|
||||
|
||||
- [~] 8.2 更新 Steering 文件为 Monorepo 视角
|
||||
- 更新 `product.md`:从单一 ETL 扩展为 Monorepo 全局视角(ETL + 后端 + 小程序 + GUI)
|
||||
- 更新 `tech.md`:新增 FastAPI、uv workspace、Donut+TDesign 技术栈
|
||||
- 更新 `structure-lite.md`:反映 Monorepo 目录结构和模块边界
|
||||
- 更新所有 steering 文件中的路径引用,移除旧仓库路径(`FQ-ETL`、`C:\ZQYY\FQ-ETL`)
|
||||
- _Requirements: 10.2, 10.3_
|
||||
|
||||
- [~] 8.3 编写 Steering 文件路径更新属性测试
|
||||
- **Property 9: Steering 文件路径更新**
|
||||
- **Validates: Requirements 10.2**
|
||||
|
||||
- [ ] 9. FastAPI 后端骨架
|
||||
- [~] 9.1 创建 FastAPI 项目结构
|
||||
- 创建 `apps/backend/app/__init__.py`、`main.py`、`config.py`、`database.py`
|
||||
- 创建 `apps/backend/app/routers/__init__.py`
|
||||
- 创建 `apps/backend/app/middleware/__init__.py`
|
||||
- 创建 `apps/backend/app/schemas/__init__.py`
|
||||
- 创建 `apps/backend/tests/__init__.py`
|
||||
- `main.py` 中配置 FastAPI 实例,启用 OpenAPI 文档自动生成
|
||||
- `database.py` 中配置 `zqyy_app` 数据库连接
|
||||
- _Requirements: 11.1, 11.2, 11.3_
|
||||
|
||||
- [~] 9.2 生成 apps/backend/pyproject.toml
|
||||
- 声明 FastAPI、uvicorn、psycopg2-binary、neozqyy-shared 等依赖
|
||||
- 配置 uv workspace 源引用 `neozqyy-shared`
|
||||
- _Requirements: 11.4_
|
||||
|
||||
- [~] 9.3 生成 apps/backend/README.md
|
||||
- 包含作用说明、项目结构、启动方式、Roadmap
|
||||
- _Requirements: 1.5_
|
||||
|
||||
- [ ] 10. 共享包搭建
|
||||
- [~] 10.1 创建 packages/shared 包结构
|
||||
- 创建 `packages/shared/src/neozqyy_shared/__init__.py`
|
||||
- 创建 `packages/shared/src/neozqyy_shared/enums.py`:字段枚举定义(从 ETL models/ 提取通用枚举)
|
||||
- 创建 `packages/shared/src/neozqyy_shared/money.py`:金额精度工具(Decimal + ROUND_HALF_UP,scale=2)
|
||||
- 创建 `packages/shared/src/neozqyy_shared/datetime_utils.py`:时区转换、日期范围计算
|
||||
- 创建 `packages/shared/tests/__init__.py`
|
||||
- _Requirements: 12.1, 12.2_
|
||||
|
||||
- [~] 10.2 生成 packages/shared/pyproject.toml
|
||||
- 声明包名 `neozqyy-shared`,最小依赖(python-dateutil、tzdata)
|
||||
- _Requirements: 12.3_
|
||||
|
||||
- [~] 10.3 编写配置优先级属性测试
|
||||
- **Property 3: 配置优先级 - .env.local 覆盖**
|
||||
- **Validates: Requirements 4.3**
|
||||
|
||||
- [~] 10.4 编写必需配置缺失检测属性测试
|
||||
- **Property 4: 必需配置缺失检测**
|
||||
- **Validates: Requirements 4.4**
|
||||
|
||||
- [ ] 11. 检查点 - 全局验证
|
||||
- 验证 uv workspace 依赖解析:在根目录运行 `uv sync`
|
||||
- 验证 ETL 单元测试:在 `apps/etl/pipelines/feiqiu/` 下运行 `pytest tests/unit`
|
||||
- Ensure all tests pass, ask the user if questions arise.
|
||||
|
||||
- [ ] 12. RLS 与多门店隔离验证
|
||||
- [~] 12.1 编写 RLS 按 site_id 隔离属性测试
|
||||
- **Property 11: RLS 按 site_id 隔离**
|
||||
- **Validates: Requirements 13.2**
|
||||
- 需要集成测试环境(test_etl_feiqiu 数据库)
|
||||
|
||||
- [ ] 13. 最终检查点
|
||||
- 确保所有文件已创建、所有 README 已编写、所有 DDL 语法正确
|
||||
- Ensure all tests pass, ask the user if questions arise.
|
||||
|
||||
## 备注
|
||||
|
||||
- 标记 `*` 的任务为可选测试任务,可跳过以加速 MVP
|
||||
- 每个任务引用具体需求编号,确保可追溯
|
||||
- 检查点确保增量验证,避免问题累积
|
||||
- 属性测试验证通用正确性,单元测试验证具体边界情况
|
||||
- 文件复制操作需要用户在终端手动执行(涉及跨目录操作),Kiro 负责生成目标文件内容
|
||||
1
.kiro/specs/repo-audit/.config.kiro
Normal file
1
.kiro/specs/repo-audit/.config.kiro
Normal file
@@ -0,0 +1 @@
|
||||
{"generationMode": "requirements-first"}
|
||||
424
.kiro/specs/repo-audit/design.md
Normal file
424
.kiro/specs/repo-audit/design.md
Normal file
@@ -0,0 +1,424 @@
|
||||
# 设计文档:仓库治理只读审计
|
||||
|
||||
## 概述
|
||||
|
||||
本设计描述三个 Python 审计脚本的实现方案,用于对 etl-billiards 仓库进行只读分析并生成三份 Markdown 报告。脚本仅读取文件系统和源代码,不连接数据库、不修改任何现有文件,仅在 `docs/audit/repo/` 目录下输出报告。
|
||||
|
||||
审计脚本采用模块化设计:一个共享的仓库扫描器负责遍历文件系统,三个独立的分析器分别生成文件清单、流程树和文档对齐报告。
|
||||
|
||||
## 架构
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[scripts/audit/run_audit.py<br/>审计主入口] --> B[scripts/audit/scanner.py<br/>仓库扫描器]
|
||||
A --> C[scripts/audit/inventory_analyzer.py<br/>文件清单分析器]
|
||||
A --> D[scripts/audit/flow_analyzer.py<br/>流程树分析器]
|
||||
A --> E[scripts/audit/doc_alignment_analyzer.py<br/>文档对齐分析器]
|
||||
|
||||
B --> F[文件系统<br/>只读遍历]
|
||||
C --> G[docs/audit/repo/file_inventory.md]
|
||||
D --> H[docs/audit/repo/flow_tree.md]
|
||||
E --> I[docs/audit/repo/doc_alignment.md]
|
||||
|
||||
C --> B
|
||||
D --> B
|
||||
E --> B
|
||||
```
|
||||
|
||||
### 执行流程
|
||||
|
||||
1. `run_audit.py` 作为主入口,初始化扫描器并依次调用三个分析器
|
||||
2. `scanner.py` 递归遍历仓库,构建文件元信息列表(路径、大小、类型)
|
||||
3. 各分析器接收扫描结果,执行各自的分析逻辑,输出 Markdown 报告
|
||||
4. 所有报告写入 `docs/audit/repo/` 目录
|
||||
|
||||
## 组件与接口
|
||||
|
||||
### 1. 仓库扫描器 (`scripts/audit/scanner.py`)
|
||||
|
||||
负责递归遍历仓库文件系统,返回结构化的文件元信息。
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class FileEntry:
|
||||
"""单个文件/目录的元信息"""
|
||||
rel_path: str # 相对于仓库根目录的路径
|
||||
is_dir: bool # 是否为目录
|
||||
size_bytes: int # 文件大小(目录为 0)
|
||||
extension: str # 文件扩展名(小写,含点号)
|
||||
is_empty_dir: bool # 是否为空目录
|
||||
|
||||
EXCLUDED_PATTERNS: list[str] = [
|
||||
".git", "__pycache__", ".pytest_cache",
|
||||
"*.pyc", ".kiro",
|
||||
]
|
||||
|
||||
def scan_repo(root: Path, exclude: list[str] = EXCLUDED_PATTERNS) -> list[FileEntry]:
|
||||
"""递归扫描仓库,返回所有文件和目录的元信息列表"""
|
||||
...
|
||||
```
|
||||
|
||||
### 2. 文件清单分析器 (`scripts/audit/inventory_analyzer.py`)
|
||||
|
||||
对扫描结果进行用途分类和处置标签分配。
|
||||
|
||||
```python
|
||||
# 用途分类枚举
|
||||
class Category(str, Enum):
|
||||
CORE_CODE = "核心代码"
|
||||
CONFIG = "配置"
|
||||
DATABASE_DEF = "数据库定义"
|
||||
TEST = "测试"
|
||||
DOCS = "文档"
|
||||
SCRIPTS = "脚本工具"
|
||||
GUI = "GUI"
|
||||
BUILD_DEPLOY = "构建与部署"
|
||||
LOG_OUTPUT = "日志与输出"
|
||||
TEMP_DEBUG = "临时与调试"
|
||||
OTHER = "其他"
|
||||
|
||||
# 处置标签枚举
|
||||
class Disposition(str, Enum):
|
||||
KEEP = "保留"
|
||||
CANDIDATE_DELETE = "候选删除"
|
||||
CANDIDATE_ARCHIVE = "候选归档"
|
||||
NEEDS_REVIEW = "待确认"
|
||||
|
||||
@dataclass
|
||||
class InventoryItem:
|
||||
"""清单条目"""
|
||||
rel_path: str
|
||||
category: Category
|
||||
disposition: Disposition
|
||||
description: str
|
||||
|
||||
def classify(entry: FileEntry) -> InventoryItem:
|
||||
"""根据路径、扩展名等规则对单个文件/目录进行分类和标签分配"""
|
||||
...
|
||||
|
||||
def build_inventory(entries: list[FileEntry]) -> list[InventoryItem]:
|
||||
"""批量分类所有文件条目"""
|
||||
...
|
||||
|
||||
def render_inventory_report(items: list[InventoryItem], repo_root: str) -> str:
|
||||
"""生成 Markdown 格式的文件清单报告"""
|
||||
...
|
||||
```
|
||||
|
||||
**分类规则(按优先级从高到低)**:
|
||||
|
||||
| 路径模式 | 用途分类 | 默认处置 |
|
||||
|---------|---------|---------|
|
||||
| `tmp/` 下所有文件 | 临时与调试 | 候选删除/候选归档 |
|
||||
| `logs/`、`export/` 下的运行时产出 | 日志与输出 | 候选归档 |
|
||||
| `*.lnk`、`*.rar` 文件 | 其他 | 候选删除 |
|
||||
| 空目录(如 `Deleded & backup/`) | 其他 | 候选删除 |
|
||||
| `tasks/`、`loaders/`、`scd/`、`orchestration/`、`quality/`、`models/`、`utils/`、`api/` | 核心代码 | 保留 |
|
||||
| `config/` | 配置 | 保留 |
|
||||
| `database/*.sql`、`database/migrations/` | 数据库定义 | 保留 |
|
||||
| `database/*.py` | 核心代码 | 保留 |
|
||||
| `tests/` | 测试 | 保留 |
|
||||
| `docs/` | 文档 | 保留 |
|
||||
| `scripts/` 下的 `.py` 文件 | 脚本工具 | 保留/待确认 |
|
||||
| `gui/` | GUI | 保留 |
|
||||
| `setup.py`、`build_exe.py`、`*.bat`、`*.sh`、`*.ps1` | 构建与部署 | 保留 |
|
||||
| 根目录散落文件(`Prompt用.md`、`Untitled`、`fix_symbols.py` 等) | 其他 | 待确认 |
|
||||
|
||||
### 3. 流程树分析器 (`scripts/audit/flow_analyzer.py`)
|
||||
|
||||
通过静态分析 Python 源码的 `import` 语句和类继承关系,构建从入口到末端模块的调用树。
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class FlowNode:
|
||||
"""流程树节点"""
|
||||
name: str # 节点名称(模块名/类名/函数名)
|
||||
source_file: str # 所在源文件路径
|
||||
node_type: str # 类型:entry/module/class/function
|
||||
children: list["FlowNode"]
|
||||
|
||||
def parse_imports(filepath: Path) -> list[str]:
|
||||
"""使用 ast 模块解析 Python 文件的 import 语句,返回被导入的本地模块列表"""
|
||||
...
|
||||
|
||||
def build_flow_tree(repo_root: Path, entry_file: str) -> FlowNode:
|
||||
"""从指定入口文件出发,递归追踪 import 链,构建流程树"""
|
||||
...
|
||||
|
||||
def find_orphan_modules(repo_root: Path, all_entries: list[FileEntry], reachable: set[str]) -> list[str]:
|
||||
"""找出未被任何入口直接或间接引用的 Python 模块"""
|
||||
...
|
||||
|
||||
def render_flow_report(trees: list[FlowNode], orphans: list[str], repo_root: str) -> str:
|
||||
"""生成 Markdown 格式的流程树报告(含 Mermaid 图和缩进文本)"""
|
||||
...
|
||||
```
|
||||
|
||||
**入口点识别**:
|
||||
- CLI 入口:`cli/main.py` → `main()` 函数
|
||||
- GUI 入口:`gui/main.py` → `main()` 函数
|
||||
- 批处理入口:`run_etl.bat`、`run_gui.bat`、`run_ods.bat` → 解析其中的 `python` 命令
|
||||
- 运维脚本:`scripts/*.py` → 各自的 `if __name__ == "__main__"` 块
|
||||
|
||||
**静态分析策略**:
|
||||
- 使用 Python `ast` 模块解析源文件,提取 `import` 和 `from ... import` 语句
|
||||
- 仅追踪项目内部模块(排除标准库和第三方包)
|
||||
- 通过 `orchestration/task_registry.py` 的注册语句识别所有任务类及其源文件
|
||||
- 通过类继承关系(`BaseTask`、`BaseLoader`、`BaseDwsTask` 等)识别任务和加载器层级
|
||||
|
||||
### 4. 文档对齐分析器 (`scripts/audit/doc_alignment_analyzer.py`)
|
||||
|
||||
检查文档与代码之间的映射关系、过期点、冲突点和缺失点。
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class DocMapping:
|
||||
"""文档与代码的映射关系"""
|
||||
doc_path: str # 文档文件路径
|
||||
doc_topic: str # 文档主题
|
||||
related_code: list[str] # 关联的代码文件/模块
|
||||
status: str # 状态:aligned/stale/conflict/orphan
|
||||
|
||||
@dataclass
|
||||
class AlignmentIssue:
|
||||
"""对齐问题"""
|
||||
doc_path: str
|
||||
issue_type: str # stale/conflict/missing
|
||||
description: str
|
||||
related_code: str
|
||||
|
||||
def scan_docs(repo_root: Path) -> list[str]:
|
||||
"""扫描所有文档文件路径"""
|
||||
...
|
||||
|
||||
def extract_code_references(doc_path: Path) -> list[str]:
|
||||
"""从文档中提取代码引用(文件路径、类名、函数名、表名等)"""
|
||||
...
|
||||
|
||||
def check_reference_validity(ref: str, repo_root: Path) -> bool:
|
||||
"""检查文档中的代码引用是否仍然有效"""
|
||||
...
|
||||
|
||||
def find_undocumented_modules(repo_root: Path, documented: set[str]) -> list[str]:
|
||||
"""找出缺少文档的核心代码模块"""
|
||||
...
|
||||
|
||||
def check_ddl_vs_dictionary(repo_root: Path) -> list[AlignmentIssue]:
|
||||
"""比对 DDL 文件与数据字典文档的覆盖度"""
|
||||
...
|
||||
|
||||
def check_api_samples_vs_parsers(repo_root: Path) -> list[AlignmentIssue]:
|
||||
"""比对 API 响应样本与 ODS 表结构/解析器的一致性"""
|
||||
...
|
||||
|
||||
def render_alignment_report(mappings: list[DocMapping], issues: list[AlignmentIssue], repo_root: str) -> str:
|
||||
"""生成 Markdown 格式的文档对齐报告"""
|
||||
...
|
||||
```
|
||||
|
||||
**文档来源识别**:
|
||||
- `docs/` 目录下的 `.md`、`.txt`、`.csv` 文件
|
||||
- 根目录的 `README.md`
|
||||
- `开发笔记/` 目录
|
||||
- 各模块内的 `README.md`(`gui/README.md`、`fetch-test/README.md`)
|
||||
- `.kiro/steering/` 下的引导文件
|
||||
- `docs/test-json-doc/` 下的 API 响应样本及分析文档
|
||||
|
||||
**对齐检查策略**:
|
||||
- 过期点检测:文档中引用的文件路径、类名、函数名在代码中已不存在
|
||||
- 冲突点检测:DDL 中的表/字段定义与数据字典文档不一致;API 样本字段与解析器不匹配
|
||||
- 缺失点检测:核心代码模块(`tasks/`、`loaders/`、`orchestration/` 等)缺少对应文档
|
||||
|
||||
### 5. 审计主入口 (`scripts/audit/run_audit.py`)
|
||||
|
||||
```python
|
||||
def run_audit(repo_root: Path | None = None) -> None:
|
||||
"""执行完整审计流程,生成三份报告到 docs/audit/"""
|
||||
...
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_audit()
|
||||
```
|
||||
|
||||
## 数据模型
|
||||
|
||||
### FileEntry(文件元信息)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `rel_path` | `str` | 相对路径 |
|
||||
| `is_dir` | `bool` | 是否为目录 |
|
||||
| `size_bytes` | `int` | 文件大小 |
|
||||
| `extension` | `str` | 扩展名 |
|
||||
| `is_empty_dir` | `bool` | 是否为空目录 |
|
||||
|
||||
### InventoryItem(清单条目)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `rel_path` | `str` | 相对路径 |
|
||||
| `category` | `Category` | 用途分类 |
|
||||
| `disposition` | `Disposition` | 处置标签 |
|
||||
| `description` | `str` | 简要说明 |
|
||||
|
||||
### FlowNode(流程树节点)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `name` | `str` | 节点名称 |
|
||||
| `source_file` | `str` | 源文件路径 |
|
||||
| `node_type` | `str` | 节点类型 |
|
||||
| `children` | `list[FlowNode]` | 子节点列表 |
|
||||
|
||||
### DocMapping / AlignmentIssue(文档对齐)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `doc_path` | `str` | 文档路径 |
|
||||
| `doc_topic` / `issue_type` | `str` | 主题/问题类型 |
|
||||
| `related_code` | `list[str]` / `str` | 关联代码 |
|
||||
| `status` / `description` | `str` | 状态/描述 |
|
||||
|
||||
|
||||
## 正确性属性
|
||||
|
||||
*属性(Property)是指在系统所有合法执行路径上都应成立的特征或行为——本质上是对"系统应该做什么"的形式化陈述。属性是连接人类可读规格说明与机器可验证正确性保证之间的桥梁。*
|
||||
|
||||
### Property 1: classify 完整性
|
||||
|
||||
*对于任意* `FileEntry`,`classify` 函数返回的 `InventoryItem` 的 `category` 字段应属于 `Category` 枚举,`disposition` 字段应属于 `Disposition` 枚举,且 `description` 字段为非空字符串。
|
||||
|
||||
**Validates: Requirements 1.2, 1.3**
|
||||
|
||||
### Property 2: 清单渲染完整性
|
||||
|
||||
*对于任意* `InventoryItem` 列表,`render_inventory_report` 生成的 Markdown 文本中,每个条目对应的行应包含该条目的 `rel_path`、`category.value`、`disposition.value` 和 `description` 四个字段。
|
||||
|
||||
**Validates: Requirements 1.4**
|
||||
|
||||
### Property 3: 空目录标记为候选删除
|
||||
|
||||
*对于任意* `is_empty_dir=True` 的 `FileEntry`,`classify` 返回的 `disposition` 应为 `Disposition.CANDIDATE_DELETE`。
|
||||
|
||||
**Validates: Requirements 1.5**
|
||||
|
||||
### Property 4: .lnk/.rar 文件标记为候选删除
|
||||
|
||||
*对于任意* 扩展名为 `.lnk` 或 `.rar` 的 `FileEntry`,`classify` 返回的 `disposition` 应为 `Disposition.CANDIDATE_DELETE`。
|
||||
|
||||
**Validates: Requirements 1.6**
|
||||
|
||||
### Property 5: tmp/ 下文件处置范围
|
||||
|
||||
*对于任意* `rel_path` 以 `tmp/` 开头的 `FileEntry`,`classify` 返回的 `disposition` 应为 `Disposition.CANDIDATE_DELETE` 或 `Disposition.CANDIDATE_ARCHIVE` 之一。
|
||||
|
||||
**Validates: Requirements 1.7**
|
||||
|
||||
### Property 6: 运行时产出目录标记为候选归档
|
||||
|
||||
*对于任意* `rel_path` 以 `logs/` 或 `export/` 开头且非 `__init__.py` 的 `FileEntry`,`classify` 返回的 `disposition` 应为 `Disposition.CANDIDATE_ARCHIVE`。
|
||||
|
||||
**Validates: Requirements 1.8**
|
||||
|
||||
### Property 7: 扫描器排除规则
|
||||
|
||||
*对于任意* 文件树,`scan_repo` 返回的 `FileEntry` 列表中不应包含 `rel_path` 匹配排除模式(`.git`、`__pycache__`、`.pytest_cache`)的条目。
|
||||
|
||||
**Validates: Requirements 1.1**
|
||||
|
||||
### Property 8: 清单按分类分组
|
||||
|
||||
*对于任意* `InventoryItem` 列表,`render_inventory_report` 生成的 Markdown 中,同一 `Category` 的条目应连续出现(即按分类分组排列)。
|
||||
|
||||
**Validates: Requirements 1.10**
|
||||
|
||||
### Property 9: 流程树节点 source_file 有效性
|
||||
|
||||
*对于任意* `FlowNode` 树中的节点,`source_file` 字段应为非空字符串,且对应的文件在仓库中实际存在。
|
||||
|
||||
**Validates: Requirements 2.7**
|
||||
|
||||
### Property 10: 孤立模块检测正确性
|
||||
|
||||
*对于任意* 文件集合和可达模块集合,`find_orphan_modules` 返回的孤立模块列表中的每个模块都不应出现在可达集合中,且可达集合中的每个模块都不应出现在孤立列表中。
|
||||
|
||||
**Validates: Requirements 2.8**
|
||||
|
||||
### Property 11: 过期引用检测
|
||||
|
||||
*对于任意* 文档中提取的代码引用,若该引用指向的文件路径在仓库中不存在,则 `check_reference_validity` 应返回 `False`。
|
||||
|
||||
**Validates: Requirements 3.3**
|
||||
|
||||
### Property 12: 缺失文档检测
|
||||
|
||||
*对于任意* 核心代码模块集合和已文档化模块集合,`find_undocumented_modules` 返回的缺失列表应恰好等于核心模块集合与已文档化集合的差集。
|
||||
|
||||
**Validates: Requirements 3.5**
|
||||
|
||||
### Property 13: 统计摘要一致性
|
||||
|
||||
*对于任意* 报告的统计摘要,各分类/标签的计数之和应等于对应条目列表的总长度。
|
||||
|
||||
**Validates: Requirements 4.5, 4.6, 4.7**
|
||||
|
||||
### Property 14: 报告头部元信息
|
||||
|
||||
*对于任意* 报告输出,头部应包含一个符合 ISO 格式的时间戳字符串和仓库根目录路径字符串。
|
||||
|
||||
**Validates: Requirements 4.2**
|
||||
|
||||
### Property 15: 写操作仅限 docs/audit/
|
||||
|
||||
*对于任意* 审计执行过程,所有文件写操作的目标路径应以 `docs/audit/repo/` 为前缀。
|
||||
|
||||
**Validates: Requirements 5.2**
|
||||
|
||||
### Property 16: 文档对齐报告分区完整性
|
||||
|
||||
*对于任意* `render_alignment_report` 的输出,Markdown 文本应包含"映射关系"、"过期点"、"冲突点"、"缺失点"四个分区标题。
|
||||
|
||||
**Validates: Requirements 3.8**
|
||||
|
||||
## 错误处理
|
||||
|
||||
| 场景 | 处理方式 |
|
||||
|------|---------|
|
||||
| 文件读取权限不足 | 记录警告到报告的"错误"分区,跳过该文件,继续处理 |
|
||||
| Python 源文件语法错误(`ast.parse` 失败) | 记录警告,将该文件标记为"待确认",不中断流程树构建 |
|
||||
| 文档中的代码引用格式无法解析 | 跳过该引用,不产生误报 |
|
||||
| DDL 文件 SQL 语法不规范 | 使用正则提取 `CREATE TABLE` 和列定义,容忍非标准语法 |
|
||||
| `docs/audit/repo/` 目录创建失败 | 抛出异常并终止,因为无法输出报告 |
|
||||
| 编码问题(非 UTF-8 文件) | 尝试 `utf-8` → `gbk` → `latin-1` 回退读取,记录编码警告 |
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 测试框架
|
||||
|
||||
- 单元测试与属性测试均使用 `pytest`
|
||||
- 属性测试库:`hypothesis`(Python 生态最成熟的属性测试框架)
|
||||
- 测试文件位于 `tests/unit/test_audit_*.py`
|
||||
|
||||
### 单元测试
|
||||
|
||||
针对具体示例和边界情况:
|
||||
- 扫描器对实际仓库子集的遍历结果
|
||||
- classify 对已知文件路径的分类正确性(如 `tmp/hebing.py` → 临时与调试/候选删除)
|
||||
- 入口点识别对实际仓库的结果
|
||||
- DDL 与数据字典的比对结果
|
||||
- 文件读取失败时的容错行为
|
||||
- `docs/audit/repo/` 目录不存在时的自动创建
|
||||
|
||||
### 属性测试
|
||||
|
||||
每个正确性属性对应一个属性测试,使用 `hypothesis` 生成随机输入:
|
||||
|
||||
- 每个属性测试至少运行 100 次迭代
|
||||
- 每个测试用注释标注对应的设计属性编号
|
||||
- 标注格式:**Feature: repo-audit, Property {N}: {属性标题}**
|
||||
|
||||
**生成器策略**:
|
||||
- `FileEntry` 生成器:随机路径(含各种扩展名、目录层级)、随机大小、随机 is_dir/is_empty_dir
|
||||
- `InventoryItem` 生成器:随机 Category/Disposition 组合、随机描述文本
|
||||
- `FlowNode` 生成器:随机树结构(限制深度和宽度)
|
||||
- 文件树生成器:构造临时目录结构用于扫描器测试
|
||||
90
.kiro/specs/repo-audit/requirements.md
Normal file
90
.kiro/specs/repo-audit/requirements.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# 需求文档:仓库治理只读审计
|
||||
|
||||
## 简介
|
||||
|
||||
对飞球 ETL 系统 (etl-billiards) 仓库进行全面的只读审计分析,产出三份结构化报告:文件/目录清单(含处置建议)、项目流程树(从入口到末端逻辑)、文档对齐报告(文档与代码的映射关系)。本阶段不修改任何文件,所有处置决策留待用户逐一确认后再执行。
|
||||
|
||||
## 术语表
|
||||
|
||||
- **审计脚本 (Audit_Script)**:执行只读分析并生成报告的 Python 脚本集合
|
||||
- **文件清单 (File_Inventory)**:按用途归类的仓库文件与目录列表,每项附带处置标签
|
||||
- **处置标签 (Disposition_Tag)**:对文件/目录的处置建议,取值为:保留、候选删除、候选归档、待确认
|
||||
- **流程树 (Flow_Tree)**:从程序入口出发,沿调用链展开到各子模块/子逻辑的树状结构
|
||||
- **文档对齐报告 (Doc_Alignment_Report)**:文档与代码之间映射关系的分析报告,包含过期点、冲突点、缺失点
|
||||
- **入口 (Entry_Point)**:程序的顶层启动点,如 `cli/main.py`、`gui/main.py`、`scripts/*.py`
|
||||
- **ODS/DWD/DWS**:数据仓库三层架构——操作数据存储层/明细数据层/数据服务层
|
||||
- **SCD2**:缓慢变化维度类型 2,维度表的历史版本管理策略
|
||||
|
||||
## 需求
|
||||
|
||||
### 需求 1:文件与目录清单生成
|
||||
|
||||
**用户故事:** 作为项目维护者,我希望获得一份按用途归类的仓库文件与目录清单,以便了解每个文件的角色并决定其去留。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 审计脚本扫描仓库根目录时,THE Audit_Script SHALL 递归遍历所有文件和目录(排除 `.git/`、`__pycache__/`、`.pytest_cache/` 等运行时缓存目录)
|
||||
2. WHEN 审计脚本处理每个文件或目录时,THE Audit_Script SHALL 将其归入以下用途分类之一:核心代码、配置、数据库定义、测试、文档、脚本工具、GUI、构建与部署、日志与输出、临时与调试、其他
|
||||
3. WHEN 审计脚本完成归类后,THE Audit_Script SHALL 为每个条目分配一个处置标签(保留/候选删除/候选归档/待确认)
|
||||
4. WHEN 审计脚本生成清单时,THE File_Inventory SHALL 包含以下字段:相对路径、用途分类、处置标签、简要说明
|
||||
5. WHEN 审计脚本遇到空目录(如 `database/Deleded & backup/`、`scripts/Deleded & backup/`)时,THE Audit_Script SHALL 将其标记为"候选删除"
|
||||
6. WHEN 审计脚本遇到 `.lnk` 快捷方式文件或 `.rar` 压缩包时,THE Audit_Script SHALL 将其标记为"候选删除"
|
||||
7. WHEN 审计脚本遇到 `tmp/` 目录下的文件时,THE Audit_Script SHALL 逐一评估并标记为"候选删除"或"候选归档"
|
||||
8. WHEN 审计脚本遇到 `logs/`、`export/` 目录下的运行时产出文件时,THE Audit_Script SHALL 将其标记为"候选归档"
|
||||
9. IF 审计脚本无法确定某文件的用途分类,THEN THE Audit_Script SHALL 将其标记为"待确认"并在说明中注明原因
|
||||
10. WHEN 审计脚本完成清单生成后,THE File_Inventory SHALL 以 Markdown 表格格式输出,按用途分类分组排列
|
||||
|
||||
### 需求 2:项目流程树生成
|
||||
|
||||
**用户故事:** 作为项目维护者,我希望获得一份从入口到各子模块的调用流程树,以便理解系统的执行路径和模块依赖关系。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 审计脚本分析项目入口时,THE Audit_Script SHALL 识别以下入口点:`cli/main.py`(CLI 主入口)、`gui/main.py`(GUI 主入口)、`scripts/*.py`(运维脚本)、批处理文件(`run_etl.bat`、`run_gui.bat`、`run_ods.bat` 等)
|
||||
2. WHEN 审计脚本从 CLI 入口展开时,THE Flow_Tree SHALL 追踪以下调用链:CLI 参数解析 → 配置加载 → 调度器初始化 → 任务注册表查询 → 任务执行(Extract → Transform → Load)→ 加载器调用 → 数据库操作
|
||||
3. WHEN 审计脚本从 GUI 入口展开时,THE Flow_Tree SHALL 追踪以下调用链:GUI 主窗口初始化 → 各面板/组件加载 → 后台工作线程 → CLI 命令构建 → 任务执行
|
||||
4. WHEN 审计脚本分析任务模块时,THE Flow_Tree SHALL 区分以下任务类型:ODS 抓取任务、DWD 加载任务、DWS 汇总任务、校验任务、Schema 初始化任务
|
||||
5. WHEN 审计脚本分析加载器模块时,THE Flow_Tree SHALL 区分以下加载器类型:ODS 通用加载器、维度加载器(SCD2)、事实表加载器
|
||||
6. WHEN 审计脚本生成流程树时,THE Flow_Tree SHALL 以缩进文本或 Mermaid 图的形式输出,层级深度至少达到函数/方法级别
|
||||
7. WHEN 审计脚本分析模块依赖时,THE Flow_Tree SHALL 标注每个节点所在的源文件路径
|
||||
8. IF 审计脚本发现存在孤立模块(未被任何入口直接或间接引用的代码文件),THEN THE Flow_Tree SHALL 在报告末尾单独列出这些孤立模块
|
||||
|
||||
### 需求 3:文档对齐报告生成
|
||||
|
||||
**用户故事:** 作为项目维护者,我希望了解现有文档与代码之间的对齐状况,以便识别过期、冲突和缺失的文档。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 审计脚本扫描文档目录时,THE Audit_Script SHALL 识别以下文档来源:`docs/` 目录、`README.md`、`开发笔记/`、各模块内的 `README.md`(如 `gui/README.md`、`fetch-test/README.md`)、`.kiro/steering/` 下的引导文件
|
||||
2. WHEN 审计脚本分析每份文档时,THE Doc_Alignment_Report SHALL 建立文档与代码模块之间的映射关系
|
||||
3. WHEN 审计脚本检测到文档引用了已不存在的代码实体(函数、类、文件路径)时,THE Doc_Alignment_Report SHALL 将该引用标记为"过期点"
|
||||
4. WHEN 审计脚本检测到文档描述与代码实际行为不一致时,THE Doc_Alignment_Report SHALL 将该处标记为"冲突点"
|
||||
5. WHEN 审计脚本检测到核心代码模块缺少对应文档时,THE Doc_Alignment_Report SHALL 将该模块标记为"缺失点"
|
||||
6. WHEN 审计脚本分析 DDL 文件(`database/schema_*.sql`)时,THE Doc_Alignment_Report SHALL 检查数据字典文档(`docs/dwd_main_tables_dictionary.md`、`docs/dws_tables_dictionary.md`)是否覆盖了所有表和字段
|
||||
7. WHEN 审计脚本分析 `docs/test-json-doc/` 下的 API 响应样本时,THE Doc_Alignment_Report SHALL 检查样本字段是否与 ODS 表结构和解析器(`models/parsers.py`)一致
|
||||
8. WHEN 审计脚本完成分析后,THE Doc_Alignment_Report SHALL 以 Markdown 格式输出,包含以下分区:映射关系表、过期点列表、冲突点列表、缺失点列表
|
||||
|
||||
### 需求 4:报告输出与格式规范
|
||||
|
||||
**用户故事:** 作为项目维护者,我希望审计报告以统一、可读的格式输出,以便后续逐项决策和执行。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Audit_Script SHALL 将三份报告输出到 `docs/audit/repo/` 目录下,文件名分别为 `file_inventory.md`、`flow_tree.md`、`doc_alignment.md`
|
||||
2. THE Audit_Script SHALL 在每份报告的头部包含生成时间戳和仓库根目录路径
|
||||
3. WHEN 报告引用代码标识符(类名、函数名、变量名、文件路径)时,THE Audit_Script SHALL 保留英文原文,使用行内代码格式(反引号)
|
||||
4. WHEN 报告包含说明性文字时,THE Audit_Script SHALL 使用简体中文
|
||||
5. THE Audit_Script SHALL 在文件清单报告末尾附加统计摘要:各用途分类的文件数量、各处置标签的文件数量
|
||||
6. THE Audit_Script SHALL 在流程树报告末尾附加统计摘要:入口点数量、任务数量、加载器数量、孤立模块数量
|
||||
7. THE Audit_Script SHALL 在文档对齐报告末尾附加统计摘要:过期点数量、冲突点数量、缺失点数量
|
||||
|
||||
### 需求 5:只读安全保障
|
||||
|
||||
**用户故事:** 作为项目维护者,我希望审计过程不会修改仓库中的任何文件,以确保分析阶段的安全性。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Audit_Script SHALL 仅执行文件系统的读取操作(读取文件内容、列出目录、获取文件元信息)
|
||||
2. THE Audit_Script SHALL 仅在 `docs/audit/repo/` 目录下创建新文件,该目录为报告专用输出目录
|
||||
3. IF 审计脚本在执行过程中遇到权限错误或文件读取失败,THEN THE Audit_Script SHALL 在报告中记录该错误并继续处理其余文件
|
||||
4. THE Audit_Script SHALL 在运行前检查 `docs/audit/repo/` 目录是否存在,若不存在则创建该目录
|
||||
118
.kiro/specs/repo-audit/tasks.md
Normal file
118
.kiro/specs/repo-audit/tasks.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# 实施计划:仓库治理只读审计
|
||||
|
||||
## 概述
|
||||
|
||||
将设计文档中的审计脚本拆分为增量式编码任务。每个任务构建在前一个任务之上,最终产出可运行的审计工具集。所有脚本位于 `scripts/audit/` 目录,报告输出到 `docs/audit/repo/`。
|
||||
|
||||
## 任务
|
||||
|
||||
- [x] 1. 搭建审计脚本骨架和数据模型
|
||||
- [x] 1.1 创建 `scripts/audit/__init__.py` 和数据模型定义
|
||||
- 定义 `FileEntry` dataclass(`rel_path`, `is_dir`, `size_bytes`, `extension`, `is_empty_dir`)
|
||||
- 定义 `Category` 和 `Disposition` 枚举
|
||||
- 定义 `InventoryItem` dataclass
|
||||
- 定义 `FlowNode` dataclass
|
||||
- 定义 `DocMapping` 和 `AlignmentIssue` dataclass
|
||||
- _Requirements: 1.2, 1.3, 1.4, 2.7, 3.2, 3.3_
|
||||
|
||||
- [x] 1.2 编写 classify 完整性属性测试
|
||||
- **Property 1: classify 完整性**
|
||||
- **Validates: Requirements 1.2, 1.3**
|
||||
|
||||
- [x] 2. 实现仓库扫描器
|
||||
- [x] 2.1 创建 `scripts/audit/scanner.py`
|
||||
- 实现 `EXCLUDED_PATTERNS` 常量和排除匹配逻辑
|
||||
- 实现 `scan_repo(root, exclude)` 函数:递归遍历文件系统,返回 `list[FileEntry]`
|
||||
- 处理空目录检测(`is_empty_dir`)
|
||||
- 处理文件读取权限错误(跳过并记录)
|
||||
- _Requirements: 1.1, 5.1, 5.3_
|
||||
|
||||
- [x] 2.2 编写扫描器排除规则属性测试
|
||||
- **Property 7: 扫描器排除规则**
|
||||
- **Validates: Requirements 1.1**
|
||||
|
||||
- [x] 3. 实现文件清单分析器
|
||||
- [x] 3.1 创建 `scripts/audit/inventory_analyzer.py`
|
||||
- 实现 `classify(entry: FileEntry) -> InventoryItem` 函数,包含完整分类规则表
|
||||
- 实现 `build_inventory(entries) -> list[InventoryItem]` 批量分类函数
|
||||
- 实现 `render_inventory_report(items, repo_root) -> str` Markdown 渲染函数
|
||||
- 包含统计摘要生成(各分类/标签计数)
|
||||
- 注意:需求 1.8 仅覆盖 `logs/` 和 `export/` 目录(不含 `reports/`)
|
||||
- _Requirements: 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 1.10, 4.2, 4.5_
|
||||
|
||||
- [x] 3.2 编写 classify 分类规则属性测试
|
||||
- **Property 3: 空目录标记为候选删除**
|
||||
- **Property 4: .lnk/.rar 文件标记为候选删除**
|
||||
- **Property 5: tmp/ 下文件处置范围**
|
||||
- **Property 6: 运行时产出目录标记为候选归档**(仅 `logs/`、`export/`)
|
||||
- **Validates: Requirements 1.5, 1.6, 1.7, 1.8**
|
||||
|
||||
- [x] 3.3 编写清单渲染属性测试
|
||||
- **Property 2: 清单渲染完整性**
|
||||
- **Property 8: 清单按分类分组**
|
||||
- **Validates: Requirements 1.4, 1.10**
|
||||
|
||||
- [x] 4. 检查点 - 确保文件清单模块测试通过
|
||||
- 确保所有测试通过,如有疑问请向用户确认。
|
||||
|
||||
- [x] 5. 实现流程树分析器
|
||||
- [x] 5.1 创建 `scripts/audit/flow_analyzer.py`
|
||||
- 实现 `parse_imports(filepath)` 函数:使用 `ast` 模块解析 Python 文件的 import 语句
|
||||
- 实现 `build_flow_tree(repo_root, entry_file)` 函数:从入口递归追踪 import 链
|
||||
- 实现 `find_orphan_modules(repo_root, all_entries, reachable)` 函数
|
||||
- 实现 `render_flow_report(trees, orphans, repo_root)` 函数:生成 Mermaid 图和缩进文本
|
||||
- 包含入口点识别逻辑(CLI、GUI、批处理、运维脚本)
|
||||
- 包含任务类型和加载器类型区分逻辑
|
||||
- 包含统计摘要生成
|
||||
- _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 4.6_
|
||||
|
||||
- [x] 5.2 编写流程树属性测试
|
||||
- **Property 9: 流程树节点 source_file 有效性**
|
||||
- **Property 10: 孤立模块检测正确性**
|
||||
- **Validates: Requirements 2.7, 2.8**
|
||||
|
||||
- [x] 6. 实现文档对齐分析器
|
||||
- [x] 6.1 创建 `scripts/audit/doc_alignment_analyzer.py`
|
||||
- 实现 `scan_docs(repo_root)` 函数:扫描所有文档来源
|
||||
- 实现 `extract_code_references(doc_path)` 函数:从文档提取代码引用
|
||||
- 实现 `check_reference_validity(ref, repo_root)` 函数
|
||||
- 实现 `find_undocumented_modules(repo_root, documented)` 函数
|
||||
- 实现 `check_ddl_vs_dictionary(repo_root)` 函数:DDL 与数据字典比对
|
||||
- 实现 `check_api_samples_vs_parsers(repo_root)` 函数:API 样本与解析器比对
|
||||
- 实现 `render_alignment_report(mappings, issues, repo_root)` 函数
|
||||
- 包含统计摘要生成
|
||||
- _Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 4.7_
|
||||
|
||||
- [x] 6.2 编写文档对齐属性测试
|
||||
- **Property 11: 过期引用检测**
|
||||
- **Property 12: 缺失文档检测**
|
||||
- **Property 16: 文档对齐报告分区完整性**
|
||||
- **Validates: Requirements 3.3, 3.5, 3.8**
|
||||
|
||||
- [x] 7. 检查点 - 确保流程树和文档对齐模块测试通过
|
||||
- 确保所有测试通过,如有疑问请向用户确认。
|
||||
|
||||
- [x] 8. 实现审计主入口和报告输出
|
||||
- [x] 8.1 创建 `scripts/audit/run_audit.py`
|
||||
- 实现 `run_audit(repo_root)` 主函数:依次调用扫描器和三个分析器
|
||||
- 实现 `docs/audit/repo/` 目录检查与创建逻辑
|
||||
- 实现报告头部元信息(时间戳、仓库路径)注入
|
||||
- 实现三份报告的文件写入
|
||||
- 添加 `if __name__ == "__main__"` 入口
|
||||
- _Requirements: 4.1, 4.2, 4.3, 4.4, 5.2, 5.4_
|
||||
|
||||
- [x] 8.2 编写报告输出属性测试
|
||||
- **Property 13: 统计摘要一致性**
|
||||
- **Property 14: 报告头部元信息**
|
||||
- **Property 15: 写操作仅限 docs/audit/**
|
||||
- **Validates: Requirements 4.2, 4.5, 4.6, 4.7, 5.2**
|
||||
|
||||
- [x] 9. 最终检查点 - 确保所有测试通过
|
||||
- 确保所有测试通过,如有疑问请向用户确认。
|
||||
|
||||
## 备注
|
||||
|
||||
- 标记 `*` 的子任务为可选,可跳过以加速 MVP 交付
|
||||
- 每个任务引用了具体的需求编号,便于追溯
|
||||
- 属性测试使用 `hypothesis` 库,每个测试至少 100 次迭代
|
||||
- 单元测试验证具体示例和边界情况,属性测试验证通用正确性
|
||||
1
.kiro/specs/scheduler-refactor/.config.kiro
Normal file
1
.kiro/specs/scheduler-refactor/.config.kiro
Normal file
@@ -0,0 +1 @@
|
||||
{"generationMode": "requirements-first"}
|
||||
462
.kiro/specs/scheduler-refactor/design.md
Normal file
462
.kiro/specs/scheduler-refactor/design.md
Normal file
@@ -0,0 +1,462 @@
|
||||
# 设计文档:ETL 调度器重构
|
||||
|
||||
## 概述
|
||||
|
||||
本次重构将 `ETLScheduler`(约 900 行,职责混乱的"上帝类")拆分为三层清晰的架构:
|
||||
|
||||
1. **CLI 层**(`cli/main.py`):参数解析、配置加载、资源创建与释放
|
||||
2. **PipelineRunner**(`orchestration/pipeline_runner.py`):管道定义、层→任务映射、校验编排
|
||||
3. **TaskExecutor**(`orchestration/task_executor.py`):单任务执行、游标管理、运行记录
|
||||
|
||||
核心设计原则:**单个任务是最小执行单元,管道模式只是"调度拼接"**。每层通过依赖注入接收协作对象,不自行创建资源,便于独立测试。
|
||||
|
||||
## 架构
|
||||
|
||||
### 分层架构图
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
CLI["CLI 层<br/>cli/main.py<br/>参数解析 · 配置加载 · 资源管理"]
|
||||
PR["PipelineRunner<br/>orchestration/pipeline_runner.py<br/>管道定义 · 层→任务映射 · 校验编排"]
|
||||
TE["TaskExecutor<br/>orchestration/task_executor.py<br/>单任务执行 · 游标管理 · 运行记录"]
|
||||
TR["TaskRegistry<br/>orchestration/task_registry.py<br/>任务注册 · 元数据查询"]
|
||||
CM["CursorManager"]
|
||||
RT["RunTracker"]
|
||||
DB["DatabaseConnection"]
|
||||
API["APIClient"]
|
||||
|
||||
CLI -->|"创建并注入"| PR
|
||||
CLI -->|"创建并注入"| TE
|
||||
CLI -->|"管理生命周期"| DB
|
||||
CLI -->|"管理生命周期"| API
|
||||
PR -->|"委托执行"| TE
|
||||
PR -->|"查询任务"| TR
|
||||
TE -->|"查询元数据"| TR
|
||||
TE -->|"管理游标"| CM
|
||||
TE -->|"记录运行"| RT
|
||||
TE -->|"使用"| DB
|
||||
TE -->|"使用"| API
|
||||
```
|
||||
|
||||
### 调用流程
|
||||
|
||||
**传统模式**(`--tasks`):
|
||||
```
|
||||
CLI → TaskExecutor.run_tasks([task_codes]) → TaskExecutor._run_single_task() × N
|
||||
```
|
||||
|
||||
**管道模式**(`--pipeline`):
|
||||
```
|
||||
CLI → PipelineRunner.run(pipeline, processing_mode, ...)
|
||||
→ PipelineRunner._resolve_tasks(layers)
|
||||
→ TaskExecutor.run_tasks([resolved_tasks])
|
||||
→ [可选] PipelineRunner._run_verification(layers, ...)
|
||||
```
|
||||
|
||||
## 组件与接口
|
||||
|
||||
### TaskExecutor
|
||||
|
||||
负责单任务执行的完整生命周期。从原 `ETLScheduler` 中提取 `_run_single_task`、`_execute_fetch`、`_execute_ingest`、`_execute_ods_record_and_load`、`_run_utility_task` 等方法。
|
||||
|
||||
```python
|
||||
class TaskExecutor:
|
||||
def __init__(
|
||||
self,
|
||||
config: AppConfig,
|
||||
db_ops: DatabaseOperations,
|
||||
api_client: APIClient,
|
||||
cursor_mgr: CursorManager,
|
||||
run_tracker: RunTracker,
|
||||
task_registry: TaskRegistry,
|
||||
logger: logging.Logger,
|
||||
):
|
||||
...
|
||||
|
||||
def run_tasks(
|
||||
self,
|
||||
task_codes: list[str],
|
||||
data_source: str = "hybrid", # online / offline / hybrid
|
||||
) -> list[dict[str, Any]]:
|
||||
"""批量执行任务列表,返回每个任务的结果。"""
|
||||
...
|
||||
|
||||
def run_single_task(
|
||||
self,
|
||||
task_code: str,
|
||||
run_uuid: str,
|
||||
store_id: int,
|
||||
data_source: str = "hybrid",
|
||||
) -> dict[str, Any]:
|
||||
"""执行单个任务的完整生命周期。"""
|
||||
...
|
||||
```
|
||||
|
||||
关键变化:
|
||||
- `data_source` 作为显式参数传入,不再读取 `self.pipeline_flow` 全局状态
|
||||
- 工具类任务判断通过 `TaskRegistry.get_metadata(task_code)` 查询,不再硬编码
|
||||
- 不自行创建 `DatabaseConnection` 或 `APIClient`
|
||||
|
||||
### PipelineRunner
|
||||
|
||||
负责管道编排。从原 `ETLScheduler` 中提取 `run_pipeline_with_verification`、`_run_layer_verification`、`_get_tasks_for_layers` 等方法。
|
||||
|
||||
```python
|
||||
class PipelineRunner:
|
||||
# 管道定义(从 scheduler.py 模块级常量迁移至此)
|
||||
PIPELINE_LAYERS: dict[str, list[str]] = {
|
||||
"api_ods": ["ODS"],
|
||||
"api_ods_dwd": ["ODS", "DWD"],
|
||||
"api_full": ["ODS", "DWD", "DWS", "INDEX"],
|
||||
"ods_dwd": ["DWD"],
|
||||
"dwd_dws": ["DWS"],
|
||||
"dwd_dws_index": ["DWS", "INDEX"],
|
||||
"dwd_index": ["INDEX"],
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
config: AppConfig,
|
||||
task_executor: TaskExecutor,
|
||||
task_registry: TaskRegistry,
|
||||
db_conn: DatabaseConnection,
|
||||
api_client: APIClient,
|
||||
logger: logging.Logger,
|
||||
):
|
||||
...
|
||||
|
||||
def run(
|
||||
self,
|
||||
pipeline: str,
|
||||
processing_mode: str = "increment_only",
|
||||
data_source: str = "hybrid",
|
||||
window_start: datetime | None = None,
|
||||
window_end: datetime | None = None,
|
||||
window_split: str | None = None,
|
||||
task_codes: list[str] | None = None,
|
||||
fetch_before_verify: bool = False,
|
||||
verify_tables: list[str] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""执行管道,返回汇总结果。"""
|
||||
...
|
||||
|
||||
def _resolve_tasks(self, layers: list[str]) -> list[str]:
|
||||
"""根据层列表解析任务代码,优先查询 TaskRegistry 元数据。"""
|
||||
...
|
||||
|
||||
def _run_verification(self, layers, window_start, window_end, ...):
|
||||
"""执行后置校验(从原 _run_layer_verification 迁移)。"""
|
||||
...
|
||||
```
|
||||
|
||||
### TaskRegistry(增强)
|
||||
|
||||
在现有注册功能基础上增加元数据支持。
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class TaskMeta:
|
||||
"""任务元数据"""
|
||||
task_class: type
|
||||
requires_db_config: bool = True
|
||||
layer: str | None = None # "ODS" / "DWD" / "DWS" / "INDEX" / None
|
||||
task_type: str = "etl" # "etl" / "utility" / "verification"
|
||||
|
||||
class TaskRegistry:
|
||||
def __init__(self):
|
||||
self._tasks: dict[str, TaskMeta] = {}
|
||||
|
||||
def register(
|
||||
self,
|
||||
task_code: str,
|
||||
task_class: type,
|
||||
requires_db_config: bool = True,
|
||||
layer: str | None = None,
|
||||
task_type: str = "etl",
|
||||
):
|
||||
"""注册任务类及其元数据。"""
|
||||
self._tasks[task_code.upper()] = TaskMeta(
|
||||
task_class=task_class,
|
||||
requires_db_config=requires_db_config,
|
||||
layer=layer,
|
||||
task_type=task_type,
|
||||
)
|
||||
|
||||
def create_task(self, task_code, config, db_connection, api_client, logger):
|
||||
"""创建任务实例(保持原有接口不变)。"""
|
||||
...
|
||||
|
||||
def get_metadata(self, task_code: str) -> TaskMeta | None:
|
||||
"""查询任务元数据。"""
|
||||
...
|
||||
|
||||
def get_tasks_by_layer(self, layer: str) -> list[str]:
|
||||
"""获取指定层的所有任务代码。"""
|
||||
...
|
||||
|
||||
def is_utility_task(self, task_code: str) -> bool:
|
||||
"""判断是否为工具类任务(不需要游标/运行记录)。"""
|
||||
meta = self.get_metadata(task_code)
|
||||
return meta is not None and not meta.requires_db_config
|
||||
|
||||
def get_all_task_codes(self) -> list[str]:
|
||||
"""获取所有已注册的任务代码(保持原有接口)。"""
|
||||
...
|
||||
```
|
||||
|
||||
### CLI 层重构
|
||||
|
||||
```python
|
||||
# cli/main.py 核心流程伪代码
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
config = AppConfig.load(build_cli_overrides(args))
|
||||
|
||||
# 资源创建
|
||||
db_conn = DatabaseConnection(...)
|
||||
api_client = APIClient(...)
|
||||
|
||||
try:
|
||||
# 组装依赖
|
||||
db_ops = DatabaseOperations(db_conn)
|
||||
cursor_mgr = CursorManager(db_conn)
|
||||
run_tracker = RunTracker(db_conn)
|
||||
registry = default_registry
|
||||
|
||||
executor = TaskExecutor(config, db_ops, api_client, cursor_mgr, run_tracker, registry, logger)
|
||||
|
||||
if args.pipeline:
|
||||
runner = PipelineRunner(config, executor, registry, db_conn, api_client, logger)
|
||||
runner.run(
|
||||
pipeline=args.pipeline,
|
||||
processing_mode=args.processing_mode,
|
||||
data_source=resolve_data_source(args),
|
||||
...
|
||||
)
|
||||
else:
|
||||
task_codes = config.get("run.tasks")
|
||||
data_source = resolve_data_source(args)
|
||||
executor.run_tasks(task_codes, data_source=data_source)
|
||||
finally:
|
||||
db_conn.close()
|
||||
```
|
||||
|
||||
### 参数映射
|
||||
|
||||
| 旧参数 | 旧值 | 新参数 | 新值 | 说明 |
|
||||
|--------|------|--------|------|------|
|
||||
| `--pipeline-flow` | `FULL` | `--data-source` | `hybrid` | 在线抓取 + 本地入库 |
|
||||
| `--pipeline-flow` | `FETCH_ONLY` | `--data-source` | `online` | 仅在线抓取落盘 |
|
||||
| `--pipeline-flow` | `INGEST_ONLY` | `--data-source` | `offline` | 仅本地清洗入库 |
|
||||
|
||||
### 静态方法归位
|
||||
|
||||
| 方法 | 原位置 | 新位置 | 理由 |
|
||||
|------|--------|--------|------|
|
||||
| `_map_run_status` | `ETLScheduler` | `RunTracker` | 状态映射是运行记录的职责 |
|
||||
| `_filter_verify_tables` | `ETLScheduler` | `tasks/verification/` 模块 | 校验表过滤是校验模块的职责 |
|
||||
|
||||
## 数据模型
|
||||
|
||||
### TaskMeta(新增)
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class TaskMeta:
|
||||
task_class: type # 任务类引用
|
||||
requires_db_config: bool = True # 是否需要数据库任务配置(游标/运行记录)
|
||||
layer: str | None = None # 所属层:"ODS"/"DWD"/"DWS"/"INDEX"/None
|
||||
task_type: str = "etl" # 任务类型:"etl"/"utility"/"verification"
|
||||
```
|
||||
|
||||
### DataSource 枚举
|
||||
|
||||
```python
|
||||
class DataSource(str, Enum):
|
||||
ONLINE = "online" # 仅在线抓取(原 FETCH_ONLY)
|
||||
OFFLINE = "offline" # 仅本地入库(原 INGEST_ONLY)
|
||||
HYBRID = "hybrid" # 抓取 + 入库(原 FULL)
|
||||
```
|
||||
|
||||
### 配置键映射
|
||||
|
||||
| 旧键 | 新键 | 默认值 |
|
||||
|------|------|--------|
|
||||
| `app.timezone` | `app.timezone` | `Asia/Shanghai`(原 `Asia/Shanghai`) |
|
||||
| `pipeline.flow` | `run.data_source` | `hybrid` |
|
||||
| `pipeline.fetch_root` | `io.fetch_root` | `export/JSON` |
|
||||
| `pipeline.ingest_source_dir` | `io.ingest_source_dir` | `""` |
|
||||
|
||||
### 任务执行结果(不变)
|
||||
|
||||
```python
|
||||
# 单任务结果
|
||||
{
|
||||
"task_code": str,
|
||||
"status": str, # "SUCCESS" / "FAIL" / "SKIP"
|
||||
"counts": {
|
||||
"fetched": int,
|
||||
"inserted": int,
|
||||
"updated": int,
|
||||
"skipped": int,
|
||||
"errors": int,
|
||||
},
|
||||
"window": {"start": datetime, "end": datetime, "minutes": int} | None,
|
||||
"dump_dir": str | None,
|
||||
}
|
||||
|
||||
# 管道结果
|
||||
{
|
||||
"status": str,
|
||||
"pipeline": str,
|
||||
"layers": list[str],
|
||||
"results": list[dict], # 各任务结果
|
||||
"verification_summary": dict | None, # 校验汇总
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 正确性属性
|
||||
|
||||
*正确性属性是一种在系统所有有效执行中都应成立的特征或行为——本质上是对系统应做什么的形式化陈述。属性是人类可读规格与机器可验证正确性保证之间的桥梁。*
|
||||
|
||||
### Property 1:data_source 参数决定执行路径
|
||||
|
||||
*对于任意* 任务代码和任意 `data_source` 值(online/offline/hybrid),TaskExecutor 执行该任务时,抓取阶段执行当且仅当 `data_source` 为 `online` 或 `hybrid`,入库阶段执行当且仅当 `data_source` 为 `offline` 或 `hybrid`。
|
||||
|
||||
**验证:需求 1.2**
|
||||
|
||||
### Property 2:成功任务推进游标
|
||||
|
||||
*对于任意* 非工具类任务,当任务执行成功且返回包含有效 `window`(含 `start` 和 `end`)的结果时,CursorManager.advance 应被调用且参数与返回的窗口一致。
|
||||
|
||||
**验证:需求 1.3**
|
||||
|
||||
### Property 3:失败任务标记 FAIL 并重新抛出
|
||||
|
||||
*对于任意* 非工具类任务,当任务执行过程中抛出异常时,RunTracker 应被更新为 FAIL 状态,且该异常应被重新抛出给调用方。
|
||||
|
||||
**验证:需求 1.4**
|
||||
|
||||
### Property 4:工具类任务由元数据决定
|
||||
|
||||
*对于任意* 任务代码,TaskExecutor 是否跳过游标管理和运行记录,取决于 TaskRegistry 中该任务的 `requires_db_config` 元数据。当 `requires_db_config=False` 时跳过,否则执行完整生命周期。
|
||||
|
||||
**验证:需求 1.6, 4.2**
|
||||
|
||||
### Property 5:管道名称→层列表映射
|
||||
|
||||
*对于任意* 有效的管道名称,PipelineRunner 解析出的层列表应与 `PIPELINE_LAYERS` 字典中的定义完全一致。
|
||||
|
||||
**验证:需求 2.1**
|
||||
|
||||
### Property 6:processing_mode 控制执行流程
|
||||
|
||||
*对于任意* processing_mode 值,增量 ETL 执行当且仅当模式包含 `increment`(即 `increment_only` 或 `increment_verify`),校验流程执行当且仅当模式包含 `verify`(即 `verify_only` 或 `increment_verify`)。
|
||||
|
||||
**验证:需求 2.3, 2.4**
|
||||
|
||||
### Property 7:管道结果汇总完整性
|
||||
|
||||
*对于任意* 一组任务执行结果,PipelineRunner 返回的汇总字典应包含 `status`、`pipeline`、`layers`、`results` 字段,且 `results` 列表长度等于实际执行的任务数。
|
||||
|
||||
**验证:需求 2.6**
|
||||
|
||||
### Property 8:TaskRegistry 元数据 round-trip
|
||||
|
||||
*对于任意* 任务代码、任务类和元数据组合(requires_db_config、layer、task_type),注册后通过 `get_metadata` 查询应返回相同的元数据值。
|
||||
|
||||
**验证:需求 4.1**
|
||||
|
||||
### Property 9:TaskRegistry 向后兼容默认值
|
||||
|
||||
*对于任意* 使用旧接口(仅 task_code 和 task_class)注册的任务,查询元数据应返回 `requires_db_config=True`、`layer=None`、`task_type="etl"`。
|
||||
|
||||
**验证:需求 4.4**
|
||||
|
||||
### Property 10:按层查询任务
|
||||
|
||||
*对于任意* 注册了 `layer` 元数据的任务集合,`get_tasks_by_layer(layer)` 返回的任务代码集合应等于所有 `layer` 匹配的已注册任务代码集合。
|
||||
|
||||
**验证:需求 4.3**
|
||||
|
||||
### Property 11:pipeline_flow → data_source 映射一致性
|
||||
|
||||
*对于任意* 旧 `pipeline_flow` 值(FULL/FETCH_ONLY/INGEST_ONLY),映射到 `data_source` 的结果应与预定义映射表一致:FULL→hybrid、FETCH_ONLY→online、INGEST_ONLY→offline。同样,配置键 `pipeline.flow` 应自动映射到 `run.data_source`。
|
||||
|
||||
**验证:需求 8.1, 8.2, 8.3, 5.2, 8.4**
|
||||
|
||||
## 错误处理
|
||||
|
||||
### TaskExecutor 错误处理
|
||||
|
||||
- 任务执行异常:更新 RunTracker 状态为 FAIL(含 error_message),然后重新抛出异常
|
||||
- 游标推进失败:记录错误日志,不影响任务结果(任务本身已成功)
|
||||
- 任务配置不存在:返回 `{"status": "SKIP"}` 结果,不抛异常
|
||||
|
||||
### PipelineRunner 错误处理
|
||||
|
||||
- 单个任务失败:记录错误,继续执行后续任务(与当前行为一致)
|
||||
- 校验框架未安装:返回 `{"status": "SKIPPED"}` 并记录警告
|
||||
- 无效管道名称:抛出 `ValueError`
|
||||
|
||||
### CLI 错误处理
|
||||
|
||||
- 配置加载失败:`SystemExit` 并输出错误信息
|
||||
- 资源创建失败:`SystemExit` 并输出错误信息
|
||||
- 执行过程异常:记录错误日志,`finally` 块确保资源释放,返回非零退出码
|
||||
|
||||
### 弃用警告
|
||||
|
||||
- 使用 Python `warnings.warn(DeprecationWarning)` 发出弃用警告
|
||||
- 同时在日志中记录映射详情,便于运维排查
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
|
||||
使用 `pytest` + 现有的 `FakeDB`/`FakeAPI` 测试工具(`tests/unit/task_test_utils.py`)。
|
||||
|
||||
**TaskExecutor 测试**:
|
||||
- 注入 mock 依赖(FakeDB、FakeAPI、mock CursorManager、mock RunTracker)
|
||||
- 验证成功/失败/跳过三种路径
|
||||
- 验证工具类任务不触发游标/运行记录
|
||||
- 验证 data_source 参数正确控制抓取/入库阶段
|
||||
|
||||
**PipelineRunner 测试**:
|
||||
- 注入 mock TaskExecutor
|
||||
- 验证不同 processing_mode 下的执行流程
|
||||
- 验证管道→层→任务的解析链
|
||||
|
||||
**TaskRegistry 测试**:
|
||||
- 验证元数据注册和查询
|
||||
- 验证向后兼容(无元数据注册)
|
||||
- 验证按层查询
|
||||
|
||||
**配置兼容性测试**:
|
||||
- 验证旧键→新键映射
|
||||
- 验证优先级规则
|
||||
- 验证默认值变更
|
||||
|
||||
### 属性测试
|
||||
|
||||
使用 `hypothesis` 库进行属性测试,每个属性至少运行 100 次迭代。
|
||||
|
||||
每个属性测试必须用注释标注对应的设计属性编号:
|
||||
```python
|
||||
# Feature: scheduler-refactor, Property 8: TaskRegistry 元数据 round-trip
|
||||
```
|
||||
|
||||
**属性测试覆盖**:
|
||||
- Property 1: data_source 参数决定执行路径
|
||||
- Property 2: 成功任务推进游标
|
||||
- Property 3: 失败任务标记 FAIL 并重新抛出
|
||||
- Property 4: 工具类任务由元数据决定
|
||||
- Property 5: 管道名称→层列表映射
|
||||
- Property 6: processing_mode 控制执行流程
|
||||
- Property 7: 管道结果汇总完整性
|
||||
- Property 8: TaskRegistry 元数据 round-trip
|
||||
- Property 9: TaskRegistry 向后兼容默认值
|
||||
- Property 10: 按层查询任务
|
||||
- Property 11: pipeline_flow → data_source 映射一致性
|
||||
123
.kiro/specs/scheduler-refactor/requirements.md
Normal file
123
.kiro/specs/scheduler-refactor/requirements.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# 需求文档:ETL 调度器重构
|
||||
|
||||
## 简介
|
||||
|
||||
当前 `orchestration/scheduler.py`(约 900 行)中的 `ETLScheduler` 类承担了过多职责:单任务执行、管道编排、资源管理。CLI 参数命名混乱(`--pipeline` vs `--pipeline-flow` vs `--processing-mode`),全局状态耦合严重,配置键语义重叠。本次重构将调度器拆分为三层架构(CLI → PipelineRunner → TaskExecutor),重新设计参数命名,消除全局状态依赖,使每层可独立测试。
|
||||
|
||||
## 术语表
|
||||
|
||||
- **TaskExecutor**:任务执行器,负责单个 ETL 任务的执行、游标管理和运行记录
|
||||
- **PipelineRunner**:管道运行器,负责管道定义、层→任务映射、校验编排
|
||||
- **TaskRegistry**:任务注册表,管理所有已注册的任务类及其元数据
|
||||
- **DataSource**:数据源模式,取代原 `pipeline.flow`,表示数据来自在线 API(`online`)、本地 JSON(`offline`)或混合模式(`hybrid`)
|
||||
- **ProcessingMode**:处理模式,控制 ETL 执行策略(仅增量 / 仅校验 / 增量+校验)
|
||||
- **Pipeline**:管道,定义一组按层顺序执行的 ETL 任务集合(如 `api_full` = ODS → DWD → DWS → INDEX)
|
||||
- **CursorManager**:游标管理器,管理任务的时间水位(上次处理到哪里)
|
||||
- **RunTracker**:运行记录器,在 `etl_admin` Schema 中记录每次任务执行的状态和统计
|
||||
|
||||
## 需求
|
||||
|
||||
### 需求 1:架构分层 — TaskExecutor(执行层)
|
||||
|
||||
**用户故事:** 作为开发者,我希望单任务执行逻辑独立封装在 TaskExecutor 中,以便可以脱离管道上下文独立测试和复用。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE TaskExecutor SHALL 封装单个任务的完整执行生命周期:创建运行记录、执行任务、更新游标、记录结果
|
||||
2. WHEN TaskExecutor 执行一个任务时,THE TaskExecutor SHALL 接收显式的 `data_source` 参数,而非读取全局状态
|
||||
3. WHEN 任务执行成功且返回有效时间窗口时,THE TaskExecutor SHALL 推进该任务的游标水位
|
||||
4. WHEN 任务执行过程中发生异常时,THE TaskExecutor SHALL 将运行记录状态更新为 FAIL 并重新抛出异常
|
||||
5. THE TaskExecutor SHALL 通过构造函数接收 `db_ops`、`api_client`、`cursor_manager`、`run_tracker`、`task_registry` 等依赖,而非自行创建
|
||||
6. WHEN 执行工具类任务(如 INIT_ODS_SCHEMA)时,THE TaskExecutor SHALL 跳过游标管理和运行记录,直接执行任务
|
||||
|
||||
### 需求 2:架构分层 — PipelineRunner(编排层)
|
||||
|
||||
**用户故事:** 作为开发者,我希望管道编排逻辑独立封装在 PipelineRunner 中,以便管道定义和校验流程可以独立演进。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE PipelineRunner SHALL 根据管道名称解析出需要执行的层列表(如 `api_full` → `["ODS", "DWD", "DWS", "INDEX"]`)
|
||||
2. WHEN PipelineRunner 执行管道时,THE PipelineRunner SHALL 委托 TaskExecutor 逐个执行任务,而非直接操作数据库或 API
|
||||
3. WHEN 处理模式为 `verify_only` 时,THE PipelineRunner SHALL 跳过增量 ETL,仅执行校验流程
|
||||
4. WHEN 处理模式为 `increment_verify` 时,THE PipelineRunner SHALL 先执行增量 ETL,再执行校验流程
|
||||
5. THE PipelineRunner SHALL 根据层列表自动选择对应的任务代码,支持配置覆盖
|
||||
6. WHEN 管道执行完成时,THE PipelineRunner SHALL 汇总所有任务的执行结果并返回统一的结果字典
|
||||
|
||||
### 需求 3:架构分层 — CLI 层重构
|
||||
|
||||
**用户故事:** 作为运维人员,我希望 CLI 参数命名清晰、语义无歧义,以便快速理解和正确使用各种执行模式。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE CLI SHALL 将 `--pipeline-flow`(FULL/FETCH_ONLY/INGEST_ONLY)重命名为 `--data-source`(online/offline/hybrid),并保留旧名称作为别名
|
||||
2. THE CLI SHALL 保留 `--pipeline` 参数用于管道模式,保留 `--tasks` 参数用于传统模式
|
||||
3. WHEN 用户同时指定 `--pipeline` 和 `--tasks` 时,THE CLI SHALL 将 `--tasks` 作为管道内的任务过滤器
|
||||
4. THE CLI SHALL 保留 `--processing-mode`(increment_only/verify_only/increment_verify)参数不变
|
||||
5. WHEN 用户使用旧参数名 `--pipeline-flow` 时,THE CLI SHALL 发出弃用警告并将值映射到新的 `--data-source` 参数
|
||||
6. THE CLI SHALL 仅负责参数解析和配置加载,将执行逻辑委托给 PipelineRunner 或 TaskExecutor
|
||||
|
||||
### 需求 4:任务分类元数据化
|
||||
|
||||
**用户故事:** 作为开发者,我希望任务的分类信息(是否需要数据库配置、所属层等)由任务注册表管理,而非硬编码在调度器中。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE TaskRegistry SHALL 支持在注册任务时附带元数据(`requires_db_config`、`layer`、`task_type`)
|
||||
2. WHEN TaskExecutor 需要判断任务是否为工具类任务时,THE TaskExecutor SHALL 查询 TaskRegistry 的元数据,而非检查硬编码集合
|
||||
3. WHEN PipelineRunner 需要根据层获取任务列表时,THE PipelineRunner SHALL 查询 TaskRegistry 的 `layer` 元数据
|
||||
4. THE TaskRegistry SHALL 保持向后兼容,无元数据的任务默认为 `requires_db_config=True`、`layer=None`
|
||||
|
||||
### 需求 5:配置键重构
|
||||
|
||||
**用户故事:** 作为运维人员,我希望配置键命名合理、语义清晰,以便正确配置 ETL 系统的运行参数。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE AppConfig SHALL 将 `app.timezone` 默认值从 `Asia/Shanghai` 改为 `Asia/Shanghai`
|
||||
2. THE AppConfig SHALL 将 `pipeline.flow` 配置键重命名为 `run.data_source`,并保留旧键作为兼容别名
|
||||
3. WHEN 配置中同时存在旧键 `pipeline.flow` 和新键 `run.data_source` 时,THE AppConfig SHALL 优先使用新键的值
|
||||
4. THE AppConfig SHALL 将 `pipeline.fetch_root` 和 `pipeline.ingest_source_dir` 移至 `io` 命名空间下(`io.fetch_root`、`io.ingest_source_dir`)
|
||||
|
||||
### 需求 6:资源管理与生命周期
|
||||
|
||||
**用户故事:** 作为开发者,我希望数据库连接和 API 客户端的创建与关闭由 CLI 层统一管理,以便确保资源正确释放。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE CLI SHALL 在 `finally` 块中关闭数据库连接和 API 客户端,确保异常情况下资源也能释放
|
||||
2. THE TaskExecutor SHALL 通过依赖注入接收已创建的数据库连接和 API 客户端,而非自行创建
|
||||
3. THE PipelineRunner SHALL 通过依赖注入接收已创建的数据库连接和 API 客户端,而非自行创建
|
||||
4. WHEN CLI 创建资源时,THE CLI SHALL 使用 Python 上下文管理器(`with` 语句)或 `try/finally` 模式管理生命周期
|
||||
|
||||
### 需求 7:静态方法归位
|
||||
|
||||
**用户故事:** 作为开发者,我希望与调度器无关的静态工具方法移至合适的模块,以便保持类的职责单一。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE `_map_run_status` 方法 SHALL 从 ETLScheduler 移至 RunTracker 或独立的工具模块
|
||||
2. THE `_filter_verify_tables` 方法 SHALL 从 ETLScheduler 移至校验相关模块
|
||||
3. WHEN 静态方法被移动后,THE 原调用方 SHALL 更新导入路径以引用新位置
|
||||
|
||||
### 需求 8:向后兼容与过渡
|
||||
|
||||
**用户故事:** 作为运维人员,我希望重构后的系统在过渡期内兼容旧的 CLI 参数和配置键,以便平滑迁移。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 用户使用旧参数 `--pipeline-flow FULL` 时,THE CLI SHALL 将其等价映射为 `--data-source hybrid` 并发出弃用警告
|
||||
2. WHEN 用户使用旧参数 `--pipeline-flow FETCH_ONLY` 时,THE CLI SHALL 将其等价映射为 `--data-source online` 并发出弃用警告
|
||||
3. WHEN 用户使用旧参数 `--pipeline-flow INGEST_ONLY` 时,THE CLI SHALL 将其等价映射为 `--data-source offline` 并发出弃用警告
|
||||
4. WHEN 配置文件中使用旧键 `pipeline.flow` 时,THE AppConfig SHALL 自动映射到新键 `run.data_source`
|
||||
5. THE 系统 SHALL 在日志中记录所有弃用映射,便于运维人员逐步迁移
|
||||
|
||||
### 需求 9:可测试性
|
||||
|
||||
**用户故事:** 作为开发者,我希望重构后的每一层都可以独立进行单元测试,以便快速验证逻辑正确性。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE TaskExecutor SHALL 支持通过注入 mock 依赖(FakeDB、FakeAPI)进行单元测试,无需真实数据库
|
||||
2. THE PipelineRunner SHALL 支持通过注入 mock TaskExecutor 进行单元测试,无需执行真实任务
|
||||
3. THE TaskRegistry SHALL 支持在测试中创建独立实例,不依赖全局 `default_registry`
|
||||
4. WHEN 运行单元测试时,THE 测试 SHALL 验证各层之间的交互契约(调用参数、返回值格式)
|
||||
147
.kiro/specs/scheduler-refactor/tasks.md
Normal file
147
.kiro/specs/scheduler-refactor/tasks.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# 实现计划:ETL 调度器重构
|
||||
|
||||
## 概述
|
||||
|
||||
将 `ETLScheduler`(~900 行)拆分为 TaskExecutor(执行层)、PipelineRunner(编排层)、增强版 TaskRegistry(元数据),重构 CLI 参数和配置键,保持向后兼容。采用自底向上的实现顺序:先基础组件,再上层编排,最后 CLI 集成。
|
||||
|
||||
## 任务
|
||||
|
||||
- [x] 1. 增强 TaskRegistry,支持元数据注册与查询
|
||||
- [x] 1.1 扩展 TaskRegistry 类,添加 TaskMeta 数据类和元数据相关方法
|
||||
- 在 `orchestration/task_registry.py` 中添加 `TaskMeta` dataclass(`task_class`、`requires_db_config`、`layer`、`task_type`)
|
||||
- 修改 `register()` 方法签名,增加可选的 `requires_db_config`、`layer`、`task_type` 参数
|
||||
- 添加 `get_metadata()`、`get_tasks_by_layer()`、`is_utility_task()` 方法
|
||||
- 保持 `create_task()` 和 `get_all_task_codes()` 接口不变
|
||||
- _需求: 4.1, 4.4_
|
||||
|
||||
- [x] 1.2 更新所有任务注册调用,添加元数据
|
||||
- 将原 `NO_DB_CONFIG_TASKS` 硬编码集合中的任务标记为 `requires_db_config=False`
|
||||
- 为 ODS 任务添加 `layer="ODS"`,DWD 任务添加 `layer="DWD"`,DWS 任务添加 `layer="DWS"`,INDEX 任务添加 `layer="INDEX"`
|
||||
- 工具类任务标记 `task_type="utility"`,校验类任务标记 `task_type="verification"`
|
||||
- _需求: 4.1, 4.2, 4.3_
|
||||
|
||||
- [x] 1.3 编写 TaskRegistry 属性测试
|
||||
- **Property 8: TaskRegistry 元数据 round-trip**
|
||||
- **验证: 需求 4.1**
|
||||
|
||||
- [x] 1.4 编写 TaskRegistry 向后兼容和按层查询属性测试
|
||||
- **Property 9: TaskRegistry 向后兼容默认值**
|
||||
- **Property 10: 按层查询任务**
|
||||
- **验证: 需求 4.4, 4.3**
|
||||
|
||||
- [x] 2. 配置键重构与向后兼容
|
||||
- [x] 2.1 修改 `config/defaults.py` 默认值
|
||||
- 将 `app.timezone` 默认值从 `Asia/Shanghai` 改为 `Asia/Shanghai`
|
||||
- 将 `db.session.timezone` 默认值从 `Asia/Shanghai` 改为 `Asia/Shanghai`
|
||||
- 添加 `run.data_source` 键(默认 `hybrid`)
|
||||
- 将 `pipeline.fetch_root` 和 `pipeline.ingest_source_dir` 复制到 `io.fetch_root` 和 `io.ingest_source_dir`(保留旧键兼容)
|
||||
- _需求: 5.1, 5.2, 5.4_
|
||||
|
||||
- [x] 2.2 在 `config/settings.py` 的 `_normalize()` 中添加兼容映射逻辑
|
||||
- 旧键 `pipeline.flow` → 新键 `run.data_source`(值映射:FULL→hybrid, FETCH_ONLY→online, INGEST_ONLY→offline)
|
||||
- 旧键 `pipeline.fetch_root` → `io.fetch_root`,`pipeline.ingest_source_dir` → `io.ingest_source_dir`
|
||||
- 新键优先:当新旧键同时存在时,使用新键的值
|
||||
- 记录弃用警告日志
|
||||
- _需求: 5.2, 5.3, 5.4, 8.4, 8.5_
|
||||
|
||||
- [x] 2.3 编写配置映射属性测试
|
||||
- **Property 11: pipeline_flow → data_source 映射一致性**
|
||||
- **验证: 需求 8.1, 8.2, 8.3, 5.2, 8.4**
|
||||
|
||||
- [x] 3. 静态方法归位
|
||||
- [x] 3.1 将 `_map_run_status` 移至 RunTracker
|
||||
- 在 `orchestration/run_tracker.py` 中添加 `map_run_status()` 静态方法(从 `ETLScheduler._map_run_status` 复制)
|
||||
- _需求: 7.1_
|
||||
|
||||
- [x] 3.2 将 `_filter_verify_tables` 移至校验模块
|
||||
- 在 `tasks/verification/` 下合适的模块中添加 `filter_verify_tables()` 函数
|
||||
- _需求: 7.2_
|
||||
|
||||
- [x] 4. 检查点 — 确保所有测试通过
|
||||
- 运行 `pytest tests/unit`,确保所有测试通过,如有问题请询问用户。
|
||||
|
||||
- [x] 5. 实现 TaskExecutor(执行层)
|
||||
- [x] 5.1 创建 `orchestration/task_executor.py`
|
||||
- 实现 `TaskExecutor` 类,构造函数接收 `config`、`db_ops`、`api_client`、`cursor_mgr`、`run_tracker`、`task_registry`、`logger`
|
||||
- 从 `ETLScheduler` 迁移以下方法:`run_tasks`、`_run_single_task`、`_execute_fetch`、`_execute_ingest`、`_execute_ods_record_and_load`、`_run_utility_task`、`_build_fetch_dir`、`_resolve_ingest_source`、`_counts_from_fetch`、`_load_task_config`、`_maybe_run_integrity_check`、`_attach_run_file_logger`
|
||||
- 将 `data_source` 改为方法参数(替代原 `self.pipeline_flow` 全局状态)
|
||||
- 使用 `self.task_registry.is_utility_task()` 替代硬编码的 `NO_DB_CONFIG_TASKS`
|
||||
- 使用 `RunTracker.map_run_status()` 替代 `self._map_run_status()`
|
||||
- 添加 `DataSource` 枚举类(`online`/`offline`/`hybrid`)
|
||||
- _需求: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6_
|
||||
|
||||
- [x] 5.2 编写 TaskExecutor 属性测试
|
||||
- **Property 1: data_source 参数决定执行路径**
|
||||
- **Property 2: 成功任务推进游标**
|
||||
- **Property 3: 失败任务标记 FAIL 并重新抛出**
|
||||
- **Property 4: 工具类任务由元数据决定**
|
||||
- **验证: 需求 1.2, 1.3, 1.4, 1.6, 4.2**
|
||||
|
||||
- [x] 6. 实现 PipelineRunner(编排层)
|
||||
- [x] 6.1 创建 `orchestration/pipeline_runner.py`
|
||||
- 实现 `PipelineRunner` 类,构造函数接收 `config`、`task_executor`、`task_registry`、`db_conn`、`api_client`、`logger`
|
||||
- 将 `PIPELINE_LAYERS` 常量从 `scheduler.py` 迁移至此
|
||||
- 从 `ETLScheduler` 迁移以下方法:`run_pipeline_with_verification`(重命名为 `run`)、`_run_layer_verification`(重命名为 `_run_verification`)、`_get_tasks_for_layers`(重命名为 `_resolve_tasks`)
|
||||
- 使用 `filter_verify_tables()`(已移至校验模块)替代原内联静态方法
|
||||
- 使用 `task_registry.get_tasks_by_layer()` 作为默认任务解析,配置覆盖优先
|
||||
- _需求: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6_
|
||||
|
||||
- [x] 6.2 编写 PipelineRunner 属性测试
|
||||
- **Property 5: 管道名称→层列表映射**
|
||||
- **Property 6: processing_mode 控制执行流程**
|
||||
- **Property 7: 管道结果汇总完整性**
|
||||
- **验证: 需求 2.1, 2.3, 2.4, 2.6**
|
||||
|
||||
- [x] 7. 检查点 — 确保所有测试通过
|
||||
- 运行 `pytest tests/unit`,确保所有测试通过,如有问题请询问用户。
|
||||
|
||||
- [x] 8. 重构 CLI 层
|
||||
- [x] 8.1 重构 `cli/main.py` 参数解析
|
||||
- 添加 `--data-source` 参数(choices: online/offline/hybrid,默认 hybrid)
|
||||
- 保留 `--pipeline-flow` 作为弃用别名,使用时发出 `DeprecationWarning` 并映射到 `--data-source`
|
||||
- 更新 `build_cli_overrides()` 将 `--data-source` 写入 `run.data_source` 配置键
|
||||
- _需求: 3.1, 3.5, 8.1, 8.2, 8.3_
|
||||
|
||||
- [x] 8.2 重构 `cli/main.py` 的 `main()` 函数
|
||||
- 在 `try/finally` 块中管理 `DatabaseConnection` 和 `APIClient` 的生命周期
|
||||
- 在 `try` 块内组装 `TaskExecutor` 和 `PipelineRunner`(依赖注入)
|
||||
- 管道模式委托 `PipelineRunner.run()`,传统模式委托 `TaskExecutor.run_tasks()`
|
||||
- 添加 `resolve_data_source(args)` 辅助函数处理新旧参数映射
|
||||
- _需求: 3.2, 3.3, 3.4, 3.6, 6.1, 6.4_
|
||||
|
||||
- [x] 8.3 编写 CLI 参数解析单元测试
|
||||
- 测试 `--data-source` 新参数正确解析
|
||||
- 测试 `--pipeline-flow` 旧参数弃用映射
|
||||
- 测试 `--pipeline` + `--tasks` 同时使用时的行为
|
||||
- _需求: 3.1, 3.3, 3.5_
|
||||
|
||||
- [x] 9. 清理旧代码与集成
|
||||
- [x] 9.1 重构 `orchestration/scheduler.py` 为薄包装层
|
||||
- 将 `ETLScheduler` 改为薄包装,内部委托 `TaskExecutor` 和 `PipelineRunner`
|
||||
- 保留 `ETLScheduler` 类名和 `run_tasks()`、`run_pipeline_with_verification()`、`close()` 公共接口,标记为弃用
|
||||
- 确保 GUI 层(`gui/workers/`)等现有调用方无需立即修改
|
||||
- _需求: 8.1, 8.4_
|
||||
|
||||
- [x] 9.2 更新 GUI 工作线程中的调度器引用
|
||||
- 检查 `gui/workers/` 中对 `ETLScheduler` 的使用
|
||||
- 如有直接引用内部方法,更新为使用新的公共接口
|
||||
- _需求: 7.3_
|
||||
|
||||
- [x] 9.3 编写集成测试验证端到端流程
|
||||
- 使用 FakeDB/FakeAPI 验证 CLI → PipelineRunner → TaskExecutor 完整调用链
|
||||
- 验证传统模式和管道模式均正常工作
|
||||
- _需求: 9.4_
|
||||
|
||||
- [x] 10. 最终检查点 — 确保所有测试通过
|
||||
- 运行 `pytest tests/unit`,确保所有测试通过,如有问题请询问用户。
|
||||
|
||||
|
||||
|
||||
## 备注
|
||||
|
||||
- 标记 `*` 的子任务为可选测试任务,可跳过以加速 MVP
|
||||
- 每个任务引用了具体的需求编号,确保可追溯性
|
||||
- 检查点确保增量验证,避免问题累积
|
||||
- 属性测试使用 `hypothesis` 库,验证通用正确性属性
|
||||
- 单元测试验证具体示例和边界条件
|
||||
- `ETLScheduler` 保留为薄包装层,确保 GUI 等现有调用方平滑过渡
|
||||
Reference in New Issue
Block a user