Files
caiwuzongzhang/docs/decisions/002-persistence.md
腾讯WorkBuddy 763a940683 B-39: 数据库持久化与不可变导入
- 版本化 SQLite 迁移(向前/回滚)与连接助手。
- 导入管线:上传文件按 SHA-256 内容哈希不可变保存,文件/行/批次
  幂等;重复上传返回 duplicate 并复用已有批次,不产生第二份事实。
- 每条规范化源行反查文件、工作表、原始行号与模板版本。
- 解析失败保留 exception/failed 批次与诊断,不产生已确认交易。
- 决策记录见 docs/decisions/002-persistence.md。
2026-08-16 01:48:53 +08:00

45 lines
2.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 002 持久化层技术决策
对应 IssueB-39`docs/issues/002-p0-persistence-and-immutable-imports.md`)。
## 数据库:SQLitePython 标准库 `sqlite3`
- 单文件、事务完整、零新增依赖,与当前标准库服务器和离线内网部署环境匹配。
- 外键约束、CHECK 约束、唯一约束和触发器均可用,足以承载不可变证据模型。
- 金额以 `TEXT` 保存 `Decimal` 的原始字符串,读取时还原为 `Decimal`
绝不经过二进制浮点。
- 后续若并发写入成为瓶颈,可开启 WAL 或平迁 PostgreSQL;迁移版本表
`schema_migrations` 不绑定具体引擎方言之外的特性。
## 迁移工具:仓库内置版本化迁移器(`src/bank_importer/db.py`
- 每条迁移包含 `up` / `down` 两段 SQL,按版本号顺序执行并记录在
`schema_migrations` 表中;重复执行无副作用。
- 不引入 Alembic 等外部工具:当前模型规模小,内置迁移器保持零依赖,
且回滚路径明确(`python -m bank_importer.db <db路径> --rollback-to <版本>`)。
- 服务启动时自动执行 `migrate`,空数据库即可完整建表。
## 文件存储:内容寻址的本地文件系统(`data/files/`
- 上传文件先计算 SHA-256,再写入 `data/files/<哈希前两位>/<完整哈希>.<扩展名>`
- 发布采用临时文件 + 硬链接:目标要么完整出现、要么不存在,且永不覆盖。
- 相同内容(即使文件名不同)只保存一份文件、一条 `source_files` 记录。
- `data/` 已加入 `.gitignore`,真实流水不进入版本库。
## 幂等与状态机
- 文件级幂等:`source_files.sha256` 唯一约束。重复上传插入一条
`status='duplicate'` 的批次审计记录,指向首个批次,不产生第二份事实。
- 行级幂等:`source_rows``UNIQUE (sheet_batch_id, source_row)`
- 批次状态:`parsing → parsed | exception | failed`,另有 `duplicate`
失败/异常批次保留 `import_exceptions` 诊断(阶段、消息、原始文件名),
不产生任何已确认源行。
- 事务边界:文件落盘后,`source_files` + 批次 + 工作表批次 + 源行在单个
SQLite 事务内提交;解析失败时批次状态与异常记录同样在事务内落库。
## 不可变性
- `source_files``sheet_batches``source_rows` 三张表由数据库触发器禁止
`UPDATE``DELETE`,任何修改只能走后续阶段的冲销/审计调整流程。
- 该约束由 `tests/test_persistence.py` 自动化验证。