# 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 §六): 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 追加迁移(本期不预留迁移负担)。 ## Related ADRs - ADR-001(Express 5) - ADR-004(zod 运行时校验——数据来自 JSON 文件的关键保障) - ADR-005(monorepo)