# HearBooks 运行与恢复说明

## 部署结构

HearBooks 由一个 Cloudflare Worker 兼容的 Vinext 应用组成：

- D1 逻辑绑定 `DB` 保存书籍、章节、片段、进度、上传会话和存储台账。
- R2 逻辑绑定 `STORAGE` 保存 EPUB/PDF、封面和生成的 MP3。
- `.openai/hosting.json` 只保存 Sites 项目编号与逻辑绑定名，不保存密钥。
- `drizzle/` 中的迁移随每个部署版本发布。

开发环境运行 `npm run dev`，发布前依次运行 `npm run typecheck`、`npm run lint`、`npm test` 和 `npm run test:e2e`。端到端测试使用本机 Microsoft Edge，覆盖 EPUB 导入、校对/拆分/合并、播放器与 Android 尺寸布局。生产构建是 `npm run build`；它同时生成当前版本的对应源码压缩包。

## 首次发布与迁移

通过 Codex Sites 发布时，Sites 会创建或复用项目、D1 和 R2，并把迁移与构建产物作为同一版本保存。不要在 `.openai/hosting.json` 中写真实资源 ID、账户信息或访问令牌。

修改 `db/schema.ts` 后，应生成并人工检查新的单向迁移，确认每个 `prepare()` 只包含一条 SQL 语句，再完成整套测试和发布。不要修改已经部署过的迁移文件；用新的迁移追加变化。

## 容量与免费使用边界

- 单书最大 200 MB，按 8 MiB 分片上传。
- 应用用 `storage_ledger` 统计已完成对象，并把尚未完成的上传总大小作为预留容量。
- 应用软上限是 8 GB。新增数据超过软上限时会先清理旧音频；仍不足就明确拒绝，不会删除书籍正文或源文件。
- 生成第六本书的音频前，会删除最久未收听书籍的全部缓存音频；再次收听时重新生成。
- 七天未完成的分片上传会在下一次创建上传任务时尝试中止并释放空间。
- 这些规则是应用级保护，不是付款或平台配额保证。Cloudflare/Sites 的免费政策以后可能变化，发布者仍应查看平台用量页。

## 备份

第一版没有导出整套 D1/R2 数据的管理界面，也没有自动快照。建议：

1. 永久保留本地 EPUB/PDF 原件和自定义封面。
2. 保存网站底部提供的 `source.zip`；它只包含重建应用所需的源码、迁移和锁文件，不包含用户书籍。
3. 在大规模删除或迁移前，逐本保留源文件；已知书籍 ID 时可通过 `GET /api/books/{bookId}/source` 取回原始文件。
4. 把校对后的重要文本视为云端唯一数据：第一版尚无批量导出，因此重要书籍不要只保留在这个匿名公开站点。

## 恢复

应用源码可从 `source.zip` 解压后重新安装依赖、构建并部署。空数据库会通过 `drizzle/` 迁移重建结构。随后重新上传保留的 EPUB/PDF 并再次校对。

若只丢失音频，不需要恢复：打开书籍后系统会按片段重新生成。若 D1 数据丢失，R2 中孤立对象不会自行还原章节或进度；需要平台快照或重新导入原书。第一版不承诺恢复校对记录和播放位置。

## Edge TTS 故障与替换

`lib/client/tts/edge-browser.ts` 是在线语音适配层。它负责声音名、速度换算、有限重试和统一故障分类；`lib/client/tts/audio-client.ts` 负责先复用云端音频、再生成并上传。浏览器系统朗读在 `lib/client/player/speech-fallback.ts`。

替换在线语音实现时：

1. 保持合成器输入为正文、声音和速度，输出为非空 `audio/mpeg` Blob。
2. 不把任意正文发送给本站的上传 API；服务端仍只根据数据库中的片段 ID接受音频。
3. 保留失败时抛出可回退错误的行为。
4. 不改变稳定片段 ID、文本版本和 R2 对象命名规则。
5. 更新第三方许可证说明，并运行 `tests/tts/`、播放器测试、完整测试以及 Edge 实机连通性测试。

Edge Read Aloud 接口没有可用性保证。系统朗读回退不缓存、不同设备声音可能不同，也不保证锁屏连续播放。

## 公网站点安全边界

网站没有登录或密码。所有读写 API 均按产品要求匿名开放；IP 限速、文件校验、对象键隐藏和 8 GB 软上限只降低误用，不构成访问控制。网址泄露后，第三方仍可能读取或删除所有书籍。发现滥用时，最可靠的处置是暂停站点访问或更换为带身份验证的后续版本。
