Files
brainwave/docs/data-content.md
T

184 lines
8.2 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.
# 数据、内容与隐私契约
> 状态:结构已定义,内容来源与授权仍为发布阻塞项
> 适用范围:卦库 assets、Room、DataStore、导入脚本和内容审核
## 1. 数据分类
| 数据 | 来源 | 默认位置 | 敏感性 | 是否参与起卦 |
|---|---|---|---|---|
| 十八枚币面/六爻结果 | 用户输入/本地计算 | 会话状态;结果锁定后默认 Room | 低至中 | 是 |
| 用户问题 | 用户输入 | 会话状态;按默认开启的设置进入 Room | 高 | 否 |
| 64 卦与爻辞 | 经审核的内容包 | assets 或预置 Room | 低,关注版权 | 仅用于查表 |
| 本地解释 | 编辑内容 | assets | 低,关注版权 | 否 |
| AI 请求与回复 | 用户主动请求 | 请求在内存;回复按默认开启的设置进入 Room | 高 | 否 |
| 偏好与同意版本 | 用户设置 | DataStore | 中 | 否 |
任何“否”的数据都不能成为 `CastEngine` 输入。
## 2. 本地内容包
建议使用带清单的版本化 JSON:
```json
{
"schemaVersion": 1,
"contentVersion": "zh-Hans-2026.1",
"sources": [
{
"id": "source-id",
"title": "来源名称",
"edition": "版本说明",
"license": "许可证或公版依据",
"url": "https://example.invalid"
}
],
"hexagrams": [
{
"kingWenNumber": 1,
"name": "乾",
"symbol": "䷀",
"lowerTrigram": "QIAN",
"upperTrigram": "QIAN",
"patternBottomUp": ["YANG", "YANG", "YANG", "YANG", "YANG", "YANG"],
"judgmentOriginal": "…",
"judgmentPlain": "…",
"lineTextsBottomUp": ["…", "…", "…", "…", "…", "…"],
"linePlainBottomUp": ["…", "…", "…", "…", "…", "…"],
"specialUsageText": "…",
"sourceRefs": ["source-id"]
}
]
}
```
示例中的省略号不是可发布内容。禁止由 AI 在构建时临时补齐缺失卦辞或爻辞。
## 3. 内容完整性门禁
内容包进入应用前必须自动验证:
- `schemaVersion` 为客户端支持值;
- 64 个条目数量准确;
- 文王卦号 1–64 各出现且只出现一次;
- 64 个 `patternBottomUp` 各不重复,且与上下卦一致;
- 每卦恰有六条 bottom-up 爻辞;
- 名称、卦辞、来源引用和许可证字段非空;
- 乾、坤特殊文本是否存在与内容版本声明一致;
- 所有文本为有效 UTF-8,无 HTML/Markdown 脚本或不可见控制字符;
- 生成内容校验摘要,便于安装包与内容版本对应。
运行时若内容包校验失败,应用应显示数据完整性错误并禁用结果查表,不能使用错误卦、相邻数组项或 AI 猜测作为降级。
## 4. 来源与授权
- 古代原文、公版翻译、现代译注和编辑改写必须分栏记录,不能把“古籍公版”错误外推到现代译本。
- 每段可发布文本必须能追踪到 `sourceRefs` 和授权依据。
- 现代白话建议由项目自行撰写并审核,或使用明确允许再分发和修改的来源。
- 字体、纹理、插画和音效同样进入许可证清单。
- 发布包内提供“内容来源”页面;用户能查看版本和来源。
内容负责人确认来源前,64 卦内容任务不可标记完成。
## 5. Room 数据模型提案
历史记录不是起卦事实源,但应保存可复核的快照:
```text
CastingSessionEntity
- id: UUID string, primary key
- createdAt: Instant/epoch millis
- methodVersion: string
- contentVersion: string
- coinConvention: enum string
- roundsJson: validated JSON
- lineValues: compact validated representation
- primaryHexagramId: 1..64
- transformedHexagramId: 1..64
- movingPositions: validated representation
- questionText: nullable
- questionSaved: boolean
ExplanationEntity
- id: UUID string, primary key
- sessionId: foreign key
- source: LOCAL | AI
- contractVersion: string
- content: validated structured JSON
- createdAt
- supersedesExplanationId: nullable foreign key
ActionNoteEntity
- sessionId: foreign key
- actionText: nullable
- timeboxText: nullable
- completedState: NOT_SET | PLANNED | DONE | ABANDONED
```
约束:
- 数据库存储原始 18 枚币面和确定结果,读取时可重新计算并进行一致性检查。
- `questionText` 默认可为空;用户不保存问题时不能偷偷复制到其他表。
- 第六爻锁定时读取一次 `HistorySavePolicy` 快照;总开关开启时,在单个事务中创建 `CastingSessionEntity`,并按默认开启的内容开关写入 `questionText`。关闭总开关或选择“本次不保存”时不得产生长期记录。
- 同一流程随后生成的本地或 AI 解读按策略写入关联的 `ExplanationEntity`;重新解读新增实体并通过 `supersedesExplanationId` 保留版本关系,不得静默覆写旧正文。
- 行动记录按策略关联到同一 session;没有实际行动内容时不创建空 `ActionNoteEntity`。
- 删除 session 应级联删除解释和行动记录。
- enum 使用稳定字符串或显式转换,不依赖 Kotlin ordinal。
- 每次 schema 迁移必须有 migration test;禁止发布构建使用 destructive migration。
## 6. DataStore 范围
DataStore 仅保存少量偏好:
- onboarding 版本是否已读;
- 主题:系统/浅色/深色;
- 减少应用内非必要动画;
- AI 同意文本版本和同意时间;
- 默认解释方式;
- `autoSaveHistory`:默认 `true`;
- `saveQuestionText`:默认 `true`;
- `saveExplanationContent`:默认 `true`;
- `saveActionNote`:默认 `true`。
总开关关闭时,后三项不参与自动写入,但保留用户上次选择;再次开启后恢复。DataStore 中的本地保存偏好与 AI 同意版本是独立字段,不得相互推导。
不要把六爻历史、完整内容包或 AI 长文本塞入 DataStore。
## 7. 隐私规则
- 问题文本被视为敏感用户内容。
- 本地核心流程不需要网络权限之外的危险权限。
- 未点击 AI 解读时,问题和卦象不得离开设备。
- AI 请求前展示准确的数据清单和服务方类别。
- 日志、分析、崩溃报告、截图测试夹具不得使用真实用户问题。
- 调试日志使用固定脱敏样例;发布构建关闭网络 body logging。
- `CastingSessionEntity`、`ExplanationEntity`、`ActionNoteEntity` 所在的 Room 数据库及其 `-wal`、`-shm` 等辅助文件必须通过 Android backup/data-extraction 规则排除,不参与 Auto Backup、设备到设备迁移或厂商云备份。
- MVP 不提供历史导出、账号或云同步。未来任何导出、备份或同步都必须新增决策、展示准确范围并取得单独的明确选择。
## 8. 数据生命周期
```text
草稿问题/未完成投币:SavedStateHandle + 内存
↓ 第六爻确认并锁定
不可变 CastResult:结果页内存
├─ autoSaveHistory=true → Room 会话快照 + 按设置保存问题
└─ autoSaveHistory=false → 不写 Room,可由用户选择“保存本次”
AI 请求:请求期间内存 → 服务端按已披露策略处理
本地/AI 回复:结果页内存 → 按设置关联到同一 Room 会话
└─ 会话不存在或解释保存关闭 → 不长期保存,可由用户选择保存本次
```
“最近一次”不是独立复制的数据,而是按 `createdAt` 从 Room 查询得到的最新已保存会话。首页不得缓存另一份问题或解释正文;删除该会话后,最近记录区域必须随查询结果一起更新为空态或下一条记录。
中止的未完成草稿只按 SavedState 恢复策略存在,不进入问卦簿;无论如何都不能把草稿作为遥测发送。用户选择“本次不保存/删除本次记录”后,应删除已经自动创建的 session 及其关联内容,但不改写全局设置。
## 9. 内容变更规则
- 修正文案:提升 `contentVersion`,记录来源和审校人。
- 修改 schema:提升 `schemaVersion`,提供向后兼容或明确迁移。
- 修改领域算法:提升 `methodVersion`,不得通过内容版本掩盖。
- 历史页必须按记录中的内容/方法版本解释旧结果,或明确提示当前展示使用了新版内容;不能静默伪装成原始解释。
Android 存储选择参考:[数据与文件概览](https://developer.android.com/training/data-storage/)、[Room 预置数据库](https://developer.android.com/training/data-storage/room/prepopulate)。