下一代基础设施架构设计
v2 数据管线的架构决策、组件关系与设计约束。
下一代中国行政区划数据基础设施架构设计
📐 历史设计稿(仅存档):本文为 v2 规划期的 RFC,其中目录结构、
source-history、§4.2 等命名/分节为早期设想,部分已被实现取代。权威的仓库结构与用法以根README.md为准。
版本:2.0 (RFC) 状态:草案 日期:2026-01-01 对应报告:《中国行政区划数据架构重构与主权数据治理深度研究报告》
1. 架构总览 (System Context)
本架构旨在解决"后统计局时代"的数据断供与仓库膨胀问题。系统从单一的"爬虫-发布"模式,转型为 "多源情报合成 -> 本地 SQLite 核心 -> NPM 分发网络 -> 客户端流式水合" 的现代数据工程链路。
1.1 核心设计原则
| 原则 | 说明 |
|---|---|
| Code-Data Decoupling (代码数据解耦) | Git 仓库不存数据,NPM 仓库不存代码(指数据包) |
| Sovereign Data Governance (主权数据治理) | 不依赖单一官方源,建立基于置信度的多源合成机制 |
| Local-First Engineering (本地优先) | 利用 SQLite 和流式处理,确保在低配置环境下的构建能力 |
| Compliance by Design (合规设计) | 严格剔除测绘坐标信息,仅维护行政代码拓扑 |
2. 工程拓扑结构 (Monorepo Topology)
采用 NPM Workspaces(或 pnpm workspace)管理子包,实现职责分离。
graph TD
Root[Monorepo Root] --> Core[@cndiv/core]
Root --> CLI[@cndiv/cli]
Root --> Crawler[@cndiv/crawler]
Root --> Protocol[@cndiv/data-protocol]
subgraph "External Data Lake (NPM Registry)"
Data2023[@cndiv/source-2023]
Data2025[@cndiv/source-2025]
end
CLI -->|Depends| Core
CLI -->|Depends| Protocol
CLI -.->|Hydrates| Data2023
Crawler -->|Depends| Protocol2.1 子包定义
| 包名 | 职责描述 | 关键依赖 |
|---|---|---|
@cndiv/core | 核心逻辑:纯计算层。包含 TS 类型定义、Luhn 校验算法、级联推导逻辑。无副作用,可在 Browser/Node/Edge 运行 | Zero Dependency |
@cndiv/cli | 编排控制:项目的大脑。负责数据下载(Hydration)、SQLite 数据库维护、CSV 流式导出、补丁应用 | Bin Alias: cndivbetter-sqlite3, cacache, tar-stream, got |
@cndiv/data-protocol | 协议定义:定义 Patch JSON Schema、数据库 Schema、置信度枚举。被 CLI 和 Crawler 共享 | zod 或 ajv |
@cndiv/crawler | 情报采集 (Dev Only):包含针对民政部 PDF、地图 API 的特定爬虫 | puppeteer, cheerio, pdf-parse |
3. 数据生产与分发流水线 (Data Pipeline)
这是架构中最复杂的部分,涵盖从"暗区"获取数据到用户使用的全过程。
3.1 数据源层 (Ingestion Layer)
面对 2024 年后的数据真空,采用多源策略:
| 数据源 | 说明 |
|---|---|
| Baseline (基准线) | 2023 年及以前的 stats.gov.cn 历史数据(已清洗存入 SQLite) |
| Official Decrees (官方公报) | 民政部发布的县级以上变更通告(PDF/HTML)。通过 crawler 解析为结构化 Patch |
| Shadow Data (影子数据) | 高德/腾讯地图 API 的 District 接口。仅用于发现新增的街道/乡镇名称,不存储坐标 |
| Community Patches (社区补丁) | 分布式贡献的 JSON 补丁文件 |
3.2 核心处理层 (Processing Layer - SQLite)
弃用原有的 LevelDB (pageCacheDB),迁移至 SQLite。
- 存储位置:
~/.cndiv/cache.db(用户本地)或 CI 环境临时构建
数据库 Schema
CREATE TABLE divisions (
code TEXT PRIMARY KEY, -- 12位代码
name TEXT NOT NULL, -- 名称
level INTEGER NOT NULL, -- 层级 (1-5)
parent_code TEXT, -- 父级代码 (索引)
year INTEGER NOT NULL, -- 数据年份
status TEXT DEFAULT 'active', -- active, deprecated
source_type TEXT, -- 'official_nbs', 'mca_decree', 'community'
confidence_score INTEGER, -- 置信度 (0-100)
UNIQUE(code, year)
);
CREATE INDEX idx_parent ON divisions(parent_code);
CREATE INDEX idx_year ON divisions(year);3.3 分发层 (Distribution Layer - NPM as Data Lake)
数据不直接进 Git,而是发布为特殊的 NPM 包。
| 项目 | 说明 |
|---|---|
| 包名规范 | @cndiv/source-<YEAR>(如 @cndiv/source-2025) |
| 包内容 | data.db.gz(压缩的 SQLite 片段)或 data.csv.gzmanifest.json(包含 SHA-512 校验和) |
| 注意 | package.json 中无 main 字段,防止被误 require |
| 发布策略 | CI 检测到 SQLite 数据变动 -> 生成 Tarball -> 发布到 NPM |
3.4 消费层 (Hydration Layer - CLI)
支持 npm, yarn, pnpm 等主流包管理器。推荐使用 pnpm 以获得最佳的磁盘空间效率。
方式一:临时运行(无需安装)
# 使用 pnpm dlx (推荐)
pnpm dlx @cndiv/cli hydrate --year 2025
# 或使用 npx
npx @cndiv/cli hydrate --year 2025方式二:项目依赖(推荐)
# 1. 安装 CLI 为开发依赖
pnpm add -D @cndiv/cli
# 2. 执行命令 (使用 bin alias 'cndiv')
pnpm exec cndiv hydrate --year 2025技术实现细节 (Stream Pipeline)
// 伪代码:流式下载与解压
pipeline(
got.stream(npmTarballUrl), // 1. 下载流
createGunzip(), // 2. 解压流
tar.extract() // 3. 解包流
.on('entry', (header, stream, next) => {
if (header.name.endsWith('.csv')) {
stream.pipe(sqliteImporter); // 4. 导入流
}
next();
})
);4. 社区治理与补丁协议 (The Patch Protocol)
为了解决"村级"数据的维护,必须建立类似于 Git 的数据版本控制机制,但作用于 SQLite 行级数据。
4.1 补丁文件结构
位于 Git 仓库的 patches/ 目录下。
// patches/2025/310115-pudong-update.json
{
"meta": {
"author": "github_user_id",
"source_url": "http://example.gov.cn/notice.pdf",
"apply_after": "2023-baseline"
},
"operations": [
{
"op": "add",
"code": "310115001002",
"name": "新设立社区居委会",
"level": 5,
"parent_code": "310115001"
},
{
"op": "update",
"code": "310115102",
"status": "deprecated",
"note": "撤销合并"
}
]
}4.2 验证流水线 (CI Pipeline)
当 Pull Request 包含 Patch 文件时,CI 触发校验:
- Schema Check:符合
@cndiv/data-protocol定义 - Logic Check:父级代码是否存在?是否存在代码冲突?
- Conflict Check:是否与同年度的其他 Patch 冲突?
5. 迁移与兼容性策略
基于对现有源码(stats.gov.cn.js, gb2260.js)的深度分析,制定以下迁移计划。
5.1 遗留系统架构分析 (Legacy Analysis)
通过分析源码,现有系统主要包含两部分存储:
| 层级 | 位置 | 技术 | 内容 | 状态 |
|---|---|---|---|---|
| 缓存层 | ../pageCacheDB/stats.gov.cn | levelup + leveldown (Google LevelDB) | 存储爬虫的 runHistory(运行记录)和原始 HTML/JSON 响应 | 这是一个二进制数据库,依赖 Node.js C++ 绑定。由于它主要用于断点续传和缓存原始请求,不适合作为数据迁移的"真理源",除非我们需要回溯原始 HTML 来修复解析错误 |
| 发布层 | data/stats.gov.cn/*.json 和 data/GB2260/*.json | 纯文本 JSON 文件 | makeCodeFile 函数生成的最终清洗数据,通常是按年份分割的树状结构或扁平列表 | 这是目前对外服务的实际数据,应以此为迁移基准 |
5.2 迁移实施方案 (Migration Plan)
我们需要编写一个一次性迁移脚本 scripts/migrate-legacy-to-sqlite.ts,执行以下步骤:
Step 1: JSON 数据摄取 (Ingestion)
遍历 data/stats.gov.cn/ 下的所有年份 JSON 文件(如 2023.json)。
解析逻辑:
- 如果由
stats.gov.cn.js生成,通常包含urban_rural_code(城乡代码) - 这部分在 2024 年后架构中被标记为 legacy 字段
- 将 JSON 树拍平为
(code, name, parent_code, level)元组
Step 2: LevelDB 应急回溯 (Fallback)
仅在 JSON 数据缺失或损坏时启用。
编写辅助脚本使用 levelup 读取 pageCacheDB 中的 Keys。
注意:由于
leveldown的原生依赖问题,此步骤建议在旧的 Docker 容器(Node 12/14)中运行,导出为中间态 JSON 后,再由主迁移脚本处理。
Step 3: SQLite 注入 (Injection)
将清洗后的数据批量插入新架构的 source-2023.db。为 2023 年及以前的数据打上:
source_type = 'official_nbs'confidence_score = 100
Step 4: 仓库清理 (Cleanup)
确认 SQLite 数据库完整性后,执行 git filter-repo。
移除:
pageCacheDB/(LevelDB 二进制文件,体积巨大)data/(旧 JSON)
保留:核心爬虫脚本(作为历史参考)和新的 Monorepo 结构
5.3 对下游的兼容
虽然内部架构巨变,但 CLI 仍需提供"传统格式导出"功能:
# 导出为旧版 JSON 结构,以便老用户无缝切换
pnpm exec cndiv export --format legacy-json --year 2023 --out ./dist