docs: 更新方案文档
This commit is contained in:
@@ -0,0 +1,172 @@
|
|||||||
|
# 财报图表项目数据架构改造方案
|
||||||
|
|
||||||
|
> 状态:建议实施
|
||||||
|
>
|
||||||
|
> 目标:保持静态图表站点的低复杂度,同时建立可追溯、可重复生成的数据链路。
|
||||||
|
|
||||||
|
## 1. 决策
|
||||||
|
|
||||||
|
当前不建设在线数据库和后端 API。
|
||||||
|
|
||||||
|
本项目目前是静态数据展示工具:浏览器按需读取 CSV,数据量很小,没有多人并发写入、权限控制、运行时查询或服务端计算的需求。此时引入 Postgres、API、鉴权和迁移机制会增加运维成本,但不能解决当前的数据正确性与可维护性问题。
|
||||||
|
|
||||||
|
CSV 保留为图表的运行时交付格式;需要改造的是 CSV 之前的数据生产链路。
|
||||||
|
|
||||||
|
## 2. 当前问题
|
||||||
|
|
||||||
|
### 2.1 权威数据源不一致
|
||||||
|
|
||||||
|
设计文档和 `data/ppmt/rawData/README.md` 将 `财报分析底稿.xlsx` 定义为唯一维护入口,但 `scripts/normalize_ppmt_financials.mjs` 实际读取的是 `data/ppmt/raw/*.csv`。底稿更新不会稳定地传递到图表。
|
||||||
|
|
||||||
|
### 2.2 派生产物被当作输入
|
||||||
|
|
||||||
|
归一化脚本的一部分通过 `readRuntimeRows()` 读取 `data/ppmt/*.csv`,再生成年度、半年等视图。IP、品类、资产等数据不能完全从上游重新构建;运行时 CSV 被删除、手改或过期时,会影响后续结果。
|
||||||
|
|
||||||
|
### 2.3 数据更新不完整
|
||||||
|
|
||||||
|
已出现底稿含有新期间、但相应图表 CSV 尚未更新的情况。问题不在某个数值,而在于链路没有可重复的全量构建保证。
|
||||||
|
|
||||||
|
### 2.4 发布边界不清晰
|
||||||
|
|
||||||
|
Vite 目前递归复制 `data/` 下的全部 CSV,因此原始披露 CSV 也会进入 `dist/`。原始证据、维护输入和公开运行时数据应有物理边界。
|
||||||
|
|
||||||
|
### 2.5 现有测试只验证展示
|
||||||
|
|
||||||
|
`pnpm test` 已能验证 manifest、CSV 可读性、图表渲染和部分视觉规范;还没有验证期间、单位、勾稽、同比口径、来源定位或派生逻辑。
|
||||||
|
|
||||||
|
## 3. 目标架构
|
||||||
|
|
||||||
|
```text
|
||||||
|
原始披露文件(PDF / XLSX / 原始导出 CSV,只读证据)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
人工录入与复核的规范化基础事实层(唯一权威)
|
||||||
|
│ 数据构建:映射、同比、期间拆分、勾稽、图表数据整形
|
||||||
|
▼
|
||||||
|
图表运行时 CSV(完全可重建,不允许手工修改)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
静态站点:manifest + Vanilla JS + ECharts
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.1 各层职责
|
||||||
|
|
||||||
|
| 层 | 内容 | 是否人工编辑 | 发布到网站 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 原始证据 | 财报 PDF、公司 XLSX、原始导出 CSV、截图 | 否 | 否 |
|
||||||
|
| 基础事实层 | 直接披露的数值、期间、单位、来源定位、科目映射 | 是,受控编辑 | 否 |
|
||||||
|
| 派生层 | H2、同比、利润率、分类汇总、年度/半年视图 | 否,脚本生成 | 否 |
|
||||||
|
| 图表 CSV | 仅包含图表需要的字段和布局 | 否,脚本生成 | 是 |
|
||||||
|
|
||||||
|
## 4. 基础事实层如何维护
|
||||||
|
|
||||||
|
基础事实层需要人工维护,但人工只编辑直接披露且可追溯的事实。
|
||||||
|
|
||||||
|
允许人工编辑的内容:
|
||||||
|
|
||||||
|
- 原始财报直接披露的金额、门店数等基础数值;
|
||||||
|
- 期间、币种、单位、合并口径;
|
||||||
|
- 来源文件、页码、表格、行号或单元格定位;
|
||||||
|
- 科目映射与分类规则,例如“类现金”“投资资产”“经营资产”。
|
||||||
|
|
||||||
|
禁止人工编辑的内容:
|
||||||
|
|
||||||
|
- 同比、环比、占比、利润率;
|
||||||
|
- `H2 = FY - H1` 等期间拆分;
|
||||||
|
- 分析分类小计;
|
||||||
|
- 任何图表运行时 CSV。
|
||||||
|
|
||||||
|
现有 `财报分析底稿.xlsx` 可以继续作为人工录入界面。改造后的要求是:构建脚本必须从这份工作簿或其一次性导出的规范化输入文件读取,不再并行从其他位置读取同一事实。工作簿是编辑器,不是与其他 CSV 并列的第二权威来源。
|
||||||
|
|
||||||
|
基础事实建议采用“长表”结构,便于复用、校验和未来接入多家公司:
|
||||||
|
|
||||||
|
| company_id | metric_id | period_end | period_type | value | unit | source_file | source_locator | revision |
|
||||||
|
| --- | --- | --- | --- | ---: | --- | --- | --- | --- |
|
||||||
|
| ppmt | revenue | 2026-06-30 | H1_YTD | 171.73 | CNY_100M | 2026H1.pdf | p.12 / 利润表 / 营业收入 | 1 |
|
||||||
|
|
||||||
|
运营类事实可使用相同结构,或按需要增加 `dimension_type`、`dimension_value`,例如地区、渠道、IP 和品类。
|
||||||
|
|
||||||
|
## 5. 目录与构建边界
|
||||||
|
|
||||||
|
建议将数据目录拆分,避免将证据文件误发布:
|
||||||
|
|
||||||
|
```text
|
||||||
|
data/
|
||||||
|
ppmt/
|
||||||
|
evidence/ # 原始披露文件,只读,不发布
|
||||||
|
input/ # 基础事实与映射规则,受控维护,不发布
|
||||||
|
generated/ # 构建中间产物,可删除并重建,不发布
|
||||||
|
public/
|
||||||
|
data/
|
||||||
|
ppmt/ # 仅图表运行时 CSV,发布
|
||||||
|
scripts/
|
||||||
|
import_ppmt_facts.* # 从 XLSX 或受控输入导入基础事实
|
||||||
|
build_ppmt_datasets.* # 从基础事实完整生成图表 CSV
|
||||||
|
check_ppmt_data.* # 质量与勾稽校验
|
||||||
|
```
|
||||||
|
|
||||||
|
Vite 仅复制 `public/`;不再以“复制整个 `data/` 再过滤扩展名”的方式发布文件。
|
||||||
|
|
||||||
|
## 6. 数据构建与校验
|
||||||
|
|
||||||
|
推荐提供三个明确命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm data:import # 可选:从人工维护的 XLSX 导出/读取基础事实
|
||||||
|
pnpm data:build # 从唯一权威源全量生成 generated 与 public/data
|
||||||
|
pnpm data:check # 校验输入、派生结果与勾稽关系
|
||||||
|
pnpm test # 图表渲染和展示回归
|
||||||
|
pnpm build # 静态站点构建
|
||||||
|
```
|
||||||
|
|
||||||
|
`data:build` 必须满足幂等性:在清空 `generated/` 和 `public/data/` 后,仍能只凭 `input/` 与 `evidence/` 完整生成相同的图表数据。构建脚本不得读取自身输出目录作为输入。
|
||||||
|
|
||||||
|
`data:check` 至少覆盖:
|
||||||
|
|
||||||
|
- 必填字段、数值类型、单位和币种;
|
||||||
|
- 期间格式、排序、重复与缺失;
|
||||||
|
- 流量类 `H2 = FY - H1`,时点类 H2/年末口径;
|
||||||
|
- 同比仅比较同口径上一年期间;
|
||||||
|
- 资产 = 负债 + 权益、现金流勾稽等适用检查;
|
||||||
|
- 图表字段 schema、空值约束和合理数值范围;
|
||||||
|
- 每条人工事实都有来源定位。
|
||||||
|
|
||||||
|
## 7. 分阶段实施
|
||||||
|
|
||||||
|
### P0:先恢复单一真相源
|
||||||
|
|
||||||
|
1. 决定以现有底稿 XLSX 作为人工维护入口。
|
||||||
|
2. 为底稿建立稳定导入器,输出规范化基础事实;或将其导出为版本化输入 CSV。
|
||||||
|
3. 将现有脚本中读取运行时 CSV 的逻辑改为读取基础事实。
|
||||||
|
4. 将图表 CSV 移到仅发布目录,原始证据移出发布路径。
|
||||||
|
5. 增加 `data:check` 的最小校验与全量重建测试。
|
||||||
|
|
||||||
|
完成标准:删除全部图表 CSV 后,仍能从唯一输入源重建所有图表;底稿新增期间后,数据检查能明确指出哪些图表应更新。
|
||||||
|
|
||||||
|
### P1:第二家公司接入后抽象共性
|
||||||
|
|
||||||
|
1. 固化跨公司通用的基础事实 schema、期间模型、来源定位格式和校验规则。
|
||||||
|
2. 仅在两个公司确实复用同一字段映射与口径时,抽取通用图表或数据模板。
|
||||||
|
3. 为 manifest 增加可选的数据契约版本,避免图表代码默默依赖 CSV 列名。
|
||||||
|
|
||||||
|
### P2:需要分析型查询时引入本地数据库
|
||||||
|
|
||||||
|
当需要跨公司指标筛选、较多事实数据查询、复杂聚合或批量分析时,引入 DuckDB + Parquet 作为本地构建和分析层。它可以替代或补强 `generated/`,但前端仍然发布静态 CSV 或预聚合 JSON。
|
||||||
|
|
||||||
|
### P3:满足以下条件才建设在线数据库
|
||||||
|
|
||||||
|
仅在出现多人在线录入、权限分级、审计版本、自动数据抓取、实时更新或面向用户的任意组合查询时,再建设 Postgres + 后端 API。
|
||||||
|
|
||||||
|
在线数据库只替换“基础事实层的存储与协作方式”;图表运行时仍应优先使用缓存后的静态数据集或受版本控制的 API 响应,不应让每张图直接查询底层事实表。
|
||||||
|
|
||||||
|
## 8. 数据库选择原则
|
||||||
|
|
||||||
|
“使用数据库”不是替代数据治理的方案。无论存储介质是 XLSX、CSV、DuckDB 还是 Postgres,都必须先满足:
|
||||||
|
|
||||||
|
1. 只有一个权威输入源;
|
||||||
|
2. 派生产物可从该输入源完整重建;
|
||||||
|
3. 每个数值可回溯到披露来源;
|
||||||
|
4. 口径、单位和期间语义经过自动校验;
|
||||||
|
5. 前端只消费稳定的数据契约。
|
||||||
|
|
||||||
|
在当前规模下,最优路线是“XLSX 受控人工录入 + 规范化事实 + 自动生成 CSV + 静态发布”,而不是立即迁移在线数据库。
|
||||||
Reference in New Issue
Block a user