gwy-exam/deliverables/architecture/decisions/ADR-003-json-datastore.md
2026-08-26 16:20:55 +08:00

3.1 KiB
Raw Blame History

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_DIRDocker volume 挂载点)。

核心设计(见 architecture.md §六):

  1. 每实体一个文件 + 顶层索引结构{ version, updatedAt, index: {id→下标}, items: [] }
  2. 数据形状:全部由 packages/shared/src/schemas/*.schema.ts 的 zod schema 定义,经 z.infer 产出强类型,无 any状态用字符串字面量联合。
  3. 原子写入:临时文件 + fs.rename 原子替换(同文件系统 rename 原子)。
  4. 写队列串行:单进程内所有写操作入 Promise 队列逐条执行,杜绝并发写坏文件。
  5. 防抖批写:高频写(刷题每道题)合并落盘,内存立即生效。
  6. zod 运行时校验:文件是可变外部输入,读入后过 schema 收窄为强类型实体。
  7. 统计用内存聚合 + 快照:不每次全量扫描文件。
  8. 数据资产能力:预留一键导出 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 追加迁移(本期不预留迁移负担)。
  • ADR-001Express 5
  • ADR-004zod 运行时校验——数据来自 JSON 文件的关键保障)
  • ADR-005monorepo