Files
brainwave/docs/decisions.md
T

164 lines
11 KiB
Markdown
Raw 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.
# 架构决策与未决问题
> 状态:持续维护
> 规则:已接受决定不得被实现者静默推翻;变更需新增记录并说明迁移影响
## 决策状态
- `Accepted`:当前实现必须遵守。
- `Proposed`:有推荐默认值,但仍允许产品确认前调整。
- `Superseded`:已被后续决策替代,保留历史原因。
- `Rejected`:明确不采用,避免重复讨论。
## ADR-001:使用原生 Android Kotlin + Jetpack Compose
- 状态:`Accepted`
- 日期:2026-08-04
- 决定:Android 首版采用 Kotlin、Jetpack Compose、Material 3 和单 Activity。
- 原因:产品只要求 Android;Compose 支持自定义主题、Canvas 卦象、状态驱动界面、无障碍和自适应布局,且符合官方新应用方向。
- 后果:不建立 Flutter、React Native 或 WebView 双栈;UI 测试使用 Compose 工具链。
## ADR-002:以官方单模块 Architecture Template 为骨架
- 状态:`Accepted`
- 日期:2026-08-04
- 决定:从 `android/architecture-templates` 的 `base` 分支起步,保留单 Gradle module,按层和 feature 分包。
- 原因:模板包含 Compose、Room、Hilt、ViewModel、Navigation、Flow 和测试基础;MVP 规模不足以抵消多模块复杂度。
- 后果:满足[系统架构](architecture.md#11-多模块化触发条件)后才能提出多模块 ADR。
## ADR-003:起卦是本地确定性纯领域逻辑
- 状态:`Accepted`
- 日期:2026-08-04
- 决定:`CastEngine` 为纯 Kotlin,无随机、时间、网络、存储和问题文本依赖。
- 原因:原始需求明确 AI 不参与起卦;纯函数最容易穷举验证和复现。
- 后果:任何“个性化卦象”“AI 校正”“服务器起卦”均违反架构。
## ADR-004:用户真实投币并手动录入
- 状态:`Accepted`
- 日期:2026-08-04
- 决定:MVP 不提供随机起卦、摇手机起卦或 AI 代投;每轮录入三枚“字/背”。
- 原因:保留用户亲手完成过程的产品核心,并避免将流程游戏化。
- 后果:可以改进录入控件,但不能增加默认随机按钮。
## ADR-005:固定 coin-v1 计值和 bottom-up 顺序
- 状态:`Accepted`
- 日期:2026-08-04
- 决定:字=2、背=3;第一次为初爻;6/9 动、7/8 静;数据标准顺序 bottom-up。
- 原因:传统资料在币面称呼上并不完全一致,项目需要可见且可复现的单一约定。
- 后果:界面始终显示计值;改变约定必须增加方法版本,不能修改旧记录。
## ADR-006:东方文化采用内容优先的纸墨朱砂设计
- 状态:`Accepted`
- 日期:2026-08-04
- 决定:以暖纸、墨色、克制朱砂、宋/黑体搭配和留白建立文化气质,同时保留原生 Android 交互语义。
- 原因:流程和文字比装饰符号更能表达文化,也更利于阅读和无障碍。
- 后果:拒绝龙凤祥云、金色发光、正文毛笔字、旋转太极和抽卡式动效。
## ADR-007:本地内容是核心,AI 是可关闭增强
- 状态:`Accepted`
- 日期:2026-08-04
- 决定:64 卦、卦辞、爻辞和基础解释本地可用;AI 通过独立接口和功能开关接入。
- 原因:核心流程要离线可靠,模型故障和成本不能阻塞产品。
- 后果:P4 本地版可独立发布;AI 关闭时 UI 不能出现断裂占位。
## ADR-008:正式 AI 密钥只放后端
- 状态:`Accepted`
- 日期:2026-08-04
- 决定:正式版经自有后端代理模型服务,不将开发者密钥打入 APK。
- 原因:客户端秘密可以被提取;后端也承担限流、schema 校验、安全策略和版本控制。
- 后果:没有后端之前只实现本地版或 mock,不用临时硬编码密钥“先跑起来”。
## ADR-009:历史记录采用明确保存、本机优先
- 状态:`Superseded by ADR-012`
- 日期:2026-08-04
- 关联:FR-H-001~006、原 TBD-007、2026-08-04 用户确认
- 决定:用户完成后明确点击保存才进入 Room;固定保存可复核的起卦快照,问题原文和当前解释分别使用默认关闭的独立选项;默认无账号和云同步。
- 原因:问题可能高度敏感,自动永久保存不是安全默认值。
- 后果:首页在存在记录时显示“最近一次 / 问卦簿”次级入口,但“开始一问”仍是唯一主操作;没有记录时提供说明和开始入口,不显示空白列表。历史功能不能成为完成起卦的前置条件。
- 取代原因:用户进一步确认“用户写的内容与解读默认完整保存在 App 内”,并要求在首页显式说明、在设置中可关闭;现行规则见 ADR-012。
## ADR-010:多动爻全部透明展示
- 状态:`Accepted`
- 日期:2026-08-04
- 决定:显示所有实际动爻及其文本,不采用未经产品确认的规则隐藏或只选一条“主爻”。
- 原因:不同解释传统存在差异,产品不应把一种裁决算法伪装成唯一事实。
- 后果:AI 可以组织内容,但输入和界面保留全部动爻。
## ADR-011:先确认可点击原型,再固化 Compose 页面
- 状态:`Accepted`
- 日期:2026-08-04
- 关联:[移动端交互原型](prototype.md)、[实施计划 P-1](implementation-plan.md#2-p-1可点击原型与视觉确认)
- 决定:Android 工程初始化前先产出可点击高保真原型和关键状态截图,由用户确认视觉与流程后再实现 Compose 页面。
- 原因:手动录入、结果层级、AI 同意门和东方文化表达都具有较高体验返工成本,先在无构建成本的原型中验证更易调整。
- 备选:Android 骨架初始化后直接实现 Compose;低保真线框图。
- 后果:原型是体验契约与评审证据,但不是生产领域代码;P1 必须独立实现和穷举验证算法,P3 复用已确认的设计令牌与状态关系。
- 复审条件:用户否定当前流程或目标平台发生变化。
## ADR-012:完整记录默认在本机自动保存,可配置关闭
- 状态:`Accepted`
- 日期:2026-08-04
- 关联:FR-H-001~008、取代 ADR-009、解决原 TBD-008、2026-08-04 用户确认
- 决定:
1. 第六爻确认并锁定 `CastResult` 后,只要“自动保存完整记录”开启,就立即在 Room 创建可复核的会话快照;未完成的问题与投币草稿仍只用于会话恢复,不进入长期历史。
2. `autoSaveHistory`、`saveQuestionText`、`saveExplanationContent` 和 `saveActionNote` 默认均为开启。关闭总开关后不再自动写入历史,三个内容开关同步停用;用户仍可在当次结果页选择“保存本次”。
3. 当次随后生成的本地或 AI 解读,在对应设置开启时关联到同一会话;重新解读不得静默覆盖已保存内容,必须新增版本或由用户明确确认替换。
4. 首页固定显示“起卦与历史默认保存在本机,不主动上传。只有你选择 AI 解读时,本次所需内容才会发送。”,并提供设置入口。结果页提供明确的自动保存状态和“本次不保存/删除本次记录”。
5. 问卦簿支持单条删除和清空全部;删除会级联移除会话、解读和行动记录。
6. 历史数据库及其问题、解读和行动数据默认排除 Android Auto Backup、设备到设备迁移的数据提取规则和任何云备份;MVP 不提供账号或云同步。未来备份、导出或同步必须另立决策并取得单独、明确的用户选择。
7. 本地自动保存与 AI 数据发送授权完全独立。自动保存开启、历史中已有内容或用户曾同意旧请求,都不能触发网络调用;每次 AI 调用仍须满足 AI 调用门。
- 原因:完整的起卦、问题、解读与行动记录共同构成可回顾的个人反思日志;默认保存能避免用户遗漏,但必须通过首页透明告知、设置和单次退出能力保留控制权。
- 未采用:继续要求每次手动保存会频繁丢失预期记录;默认只保存卦象快照会让问卦簿缺少上下文,削弱回顾价值。
- 后果:P4 必须实现保存策略、事务关联、设置、单次退出、删除、迁移和备份排除测试;ADR-012 是生产事实源,决策时尚未同步的 v0.2 原型只能作为旧流程评审材料,现行 v0.3 已完成同步。
- 复审触发:引入账号、导出、云同步、系统备份、跨设备迁移或新的隐私/合规要求。
## ADR-013:仓库门禁采用无外部依赖脚本并由 Gradle 聚合
- 状态:`Accepted`
- 日期:2026-08-04
- 关联:解决 TBD-012、P0/P1/P2/P6
- 决定:在 Android application 壳建立前,使用仓库内 Node 脚本执行格式、文档链接、高置信 secret scan、domain 依赖边界、原型语法和内容完整性检查;Gradle 8.2 的 `verifyLocal` 聚合这些检查与 JVM 测试,CI 调用同一入口。
- 原因:当前系统已实测 Node 22、JDK 17 和 Gradle 8.2,且无需新增全局工具或把个人路径写进工程;门禁错误能够给出可修复的文件位置。
- 后果:`spotlessCheck` 当前是仓库内的无依赖格式兼容入口,不表示已引入 Spotless 插件。Android 壳建立后必须把 lint/debug build 加入 `verifyLocal`;将来若采用维护良好的专用插件,应保留命令兼容或同步更新 CI 与文档。
- 复审触发:Android 工具链启用、现有脚本无法表达新边界,或专用工具能以可接受成本提供明显更强的检查。
## 未决问题
| ID | 问题 | 推荐默认 | 阻塞阶段 |
|---|---|---|---|
| TBD-001 | 正式产品名与应用图标 | Brainwave 仅作代码代号 | P0 商店配置 |
| TBD-002 | application ID | 使用组织所有的反向域名 | P0 |
| TBD-003 | minSdk | 26;创建工程时复核覆盖率和依赖要求 | P0 |
| TBD-004 | 问题是否允许留空 | 允许选择“不写具体内容”,但需显式操作 | P3 |
| TBD-005 | 经典原文、现代白话的版本与授权 | 自有白话 + 可核验公版原文 | P2,发布阻塞 |
| TBD-006 | 乾用九、坤用六是否纳入 MVP | 内容具备时展示 | P2/P3 |
| TBD-009 | AI 模型供应商与自有后端 | 供应商无关接口;先交付本地版 | P5 |
| TBD-010 | 服务端问题/回复保留期 | 最小化且明确披露,优先不持久化正文 | P5,发布阻塞 |
| TBD-011 | 高风险本地资源表覆盖地区 | 首发市场确认后维护,不让模型编号码 | P5 |
## 新增决策模板
```markdown
## ADR-NNN:标题
- 状态:Proposed | Accepted | Superseded | Rejected
- 日期:YYYY-MM-DD
- 关联:需求、issue 或旧 ADR
- 决定:一句可执行结论
- 原因:为什么现在这样选择
- 备选:认真考虑过什么
- 后果:实现、迁移、测试和文档影响
- 复审条件:何时重新评估
```
不要直接改写旧 ADR 来隐藏历史。需要反转时新增 ADR,并把旧记录标为 `Superseded by ADR-NNN`。