3.1 KiB
3.1 KiB
ADR-003: 使用本地 JSON 文件作为数据层(非 SQLite)
Status: Accepted (2026-08-26)
Background
「备考中枢」是个人单用户、自用型工具,数据是用户的长期备考资产(题库/错题本/作答记录/模考/申论/计划/统计)。用户已明确选 JSON 文件存储(非 SQLite)。需要数据可读、可迁移、可备份,并支持 Docker volume 挂载持久化。
Decision
采用本地 JSON 文件作为数据层:每实体一个 JSON 文件(questions.json / wrong-questions.json / mock-exams.json / tasks.json / shenlun.json / answer-records.json / stats.json / settings.json / meta.json),存放在可配置数据目录 APP_DATA_DIR(Docker volume 挂载点)。
核心设计(见 architecture.md §六):
- 每实体一个文件 + 顶层索引结构:
{ version, updatedAt, index: {id→下标}, items: [] }。 - 数据形状:全部由
packages/shared/src/schemas/*.schema.ts的 zod schema 定义,经z.infer产出强类型,无 any;状态用字符串字面量联合。 - 原子写入:临时文件 +
fs.rename原子替换(同文件系统 rename 原子)。 - 写队列串行:单进程内所有写操作入 Promise 队列逐条执行,杜绝并发写坏文件。
- 防抖批写:高频写(刷题每道题)合并落盘,内存立即生效。
- zod 运行时校验:文件是可变外部输入,读入后过 schema 收窄为强类型实体。
- 统计用内存聚合 + 快照:不每次全量扫描文件。
- 数据资产能力:预留一键导出 JSON/CSV + 备份/还原接口。
为什么对个人工具合理(正面)
| 维度 | 说明 |
|---|---|
| 单机低运维 | 零安装、零连接、零迁移脚本,Docker 一个容器即用 |
| 数据资产可读可迁移 | 纯文件可 cat/jq 直读、可 git 跟踪、可一键备份,跨设备无锁定 |
| 开发快 | 无 ORM/迁移/连接池,data/store.ts 单点 fs 读写,MVP 工作量最小 |
| DevOps 极简 | Docker volume 挂载即持久化,备份即拷贝目录 |
代价与规避(已正视)
| 代价 | 规避 |
|---|---|
| 并发写 | 写队列串行(互斥) |
| 写入非原子 | 临时文件 + rename 原子替换 |
| 无事务 | 单文件原子 + 组合操作分解为最小写单元 + 统计可重算(不强一致) |
| 体积增长 | 按需惰性加载 + 作答记录归档分片(按月切文件) |
| 统计 O(n) | 内存聚合 + 快照持久化 |
Consequences
- 正面:数据资产感强、运维极简、开发快、零基础设施成本。
- 负面:无事务、无查询索引、并发写入需手动防护、数据量大后需归档分片。
- 权衡:对个人单用户量级(年 1-2 万题,约 10-20 MB JSON)完全无压力。本期不需要 SQLite/PostgreSQL。若未来出现多设备协作 / 超百万条 / 复杂关系查询,再以新 ADR 追加迁移(本期不预留迁移负担)。
Related ADRs
- ADR-001(Express 5)
- ADR-004(zod 运行时校验——数据来自 JSON 文件的关键保障)
- ADR-005(monorepo)