# 任务：桌面 App 与移动端

2026-10-14 立项。目标是在现有核心、Web API 和 React UI 之上交付 Tauri 桌面 App（macOS、Windows、Linux）以及 Android、iOS App，并补齐发布前已知的核心缺口。本页是完整计划；每步完整验证通过后单独提交，证据写入[实现记录](IMPLEMENTATION_AUDIT.md)，README 只在行为落地后更新。项目未发布，格式和 API 可为本页改变；现有测试是回归基线，不放宽旧断言。

## 现状

- 核心是纯 Rust（redb、rustls、XChaCha20-Poly1305、Iroh），能编到各平台；`cipherfs-web` 已有解锁、文件、配对、撤销、冲突、保留策略和同步的全部路由；`cipherfs-web-ui` 约四千行 React，客户端的 `baseUrl` 可配置。
- 一个仓库同一时刻只能被一个进程打开：redb 按进程持文件锁，后台同步循环活在打开仓库的进程里。第二个进程得到的是数据库层错误，CLI 与 Web、CLI 与将来的 App 不能同时使用同一仓库。
- `cipherfs-api` 是阻塞门面，主动拒绝在 tokio 运行时线程上调用；Tauri 的命令恰好跑在运行时线程上。
- S3 凭据只从 `AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY` 读取，GUI 和手机没有合适的入口。
- P2P 钉在 `iroh-net 0.28`，该 crate 已并入 `iroh` 并停止演进；手机端需要当前版本。
- 工作区从未在 Windows 上编译；`rustix`、导出的独占发布和小文件锁都只有 unix 实现。挂载只有 macOS（FUSE-T/macFUSE）和 Linux，没有 WinFsp。
- 没有明文目录监视：桌面上只能经挂载、CLI、Web 访问文件，没有"一个会同步的文件夹"。
- 配对/恢复证明和快照是单对象，上限 32 MiB，没有 multipart；百万文件、1 TB、100 GB 的规模验收没有执行；WebDAV 存放点和云盘 API 没有实现。
- 全部既有设备丢失后，凭恢复密钥加入的设备不能撤销和批准配对；这是有意限制，但对 App 用户是陷阱。

## 设计决定

1. **仓库有唯一归属进程，其余进程是本地 API 客户端。** 不换数据库，也不让两个进程同时写索引。打开仓库的进程是"服务"，在仓库目录写 `owner.json`（pid、启动时间、本地端点、token 文件路径），关闭时删除；再次打开时先核对 pid 是否存活，陈旧文件直接覆盖，活着的归属进程返回 `Locked` 并附带端点。`cipherfs-web` 增加 Unix socket / Windows 命名管道监听和 0600 的随机 token 文件，这就是进程间接口。CLI 在仓库被占用且端点可达时改走 HTTP，命令与现有路由一一对应；否则照旧本地打开。挂载由归属进程提供：`cipherfs mount` 没有归属进程时自己成为归属进程，有则请求它挂载。Tauri 内嵌服务即归属进程；iOS 的 File Provider 扩展是归属进程，主 App 是客户端。
2. **Tauri 复用 Web API 与 UI。** Tauri 壳内嵌 Axum 监听本地端点，加载现有 React UI；不经 `cipherfs-api`。原生部分只做壳该做的：托盘、开机自启、钥匙串、系统文件对话框和拖拽、通知、签名与自动更新。
3. **凭据入口。** `cipherfs-sync` 打开存放点时通过 `CredentialProvider` 取凭据；默认实现读环境变量，Tauri 和手机用系统钥匙串，`cipherfs-api` 与各绑定可传入。凭据仍然不写入仓库和日志。
4. **升级到当前 `iroh`。** relay 配置保持可替换；手机端后台不能依赖 P2P，主力是存放点，与[已确认需求](requirements.zh.md#存放点)一致。
5. **Windows 以 `x86_64-pc-windows-msvc` 为目标。** core、sync、web、api、cli（不含 fuse）必须编译并通过测试；unix 门控的导出和锁要么补 Windows 实现，要么明确返回 Unsupported，不能编译失败。挂载用 WinFsp，作为独立步骤。需要一台 Windows 机器，登录信息由用户稍后提供。
6. **手机绑定用 UniFFI 生成 Kotlin 和 Swift**，在 `cipherfs-api` 之上；`cipherfs.h` 继续服务 Go。Android 先做：DocumentsProvider 在同一进程内运行，归属模型不受影响。iOS 后做：File Provider 扩展持有仓库，主 App 经扩展访问。手机端后台同步用系统任务（WorkManager / BGProcessingTask）定期对存放点同步，不依赖 P2P 常驻。
7. **桌面"同步明文文件夹"模式**作为挂载之外的第二种透明接入：归属进程监视一个本机目录，本机改动发布为版本，远端版本写回目录；冲突仍走共享版本模型，目录里不生成冲突副本；目录是缓存，删除目录不等于删除仓库数据。放在桌面 MVP 和挂载之后。
8. **孤儿恢复设备的管理权限**先在需求页裁决再实现；候选方案是恢复密钥加公示期：恢复设备发布管理请求，N 天内没有任何既有成员反对即生效，被撤销设备不能反对。裁决结果写入需求页。
9. **规模与存放点缺口**（multipart、WebDAV、云盘 API、规模验收）按[规模预算](scale-budget.zh.md)和需求页的实现顺序排进本计划，手机端上线前完成 multipart 与至少一种 API 存放点。

## 交付顺序

| 步骤 | 范围 | 验收 |
| --- | --- | --- |
| 1：归属进程与客户端 | Core 的 owner 文件与 `Locked` 端点；Web 的本地 socket / 命名管道监听与 token；CLI 客户端模式 | 两个进程打开同一仓库：第二个经端点完成 put/get/list/devices；归属进程退出后第二个可本地打开；陈旧 owner 文件不阻塞 |
| 2：凭据入口 | `CredentialProvider`，环境变量默认实现，API 与三套绑定的传入方式 | S3 夹具不设环境变量、只经 provider 通过；凭据不出现在仓库和日志 |
| 3：iroh 升级 | 依赖迁移，`node_addr` 文本格式不变 | 现有真实 QUIC 用例与 P2P 夹具全部通过，NodeAddr JSON 向量不变 |
| 4：Windows 编译与 CI | 目标编译、测试、CI 条目 | Windows 机器上 core/sync/web/api/cli 测试通过；unix 门控全部有 Windows 结果 |
| 5：孤儿恢复设备 | 需求裁决，实现公示期或所选方案 | 全部设备丢失后恢复设备能在规则内撤销与批准配对；既有成员反对时拒绝 |
| 6：multipart | 权限证明、快照、上传清单分片发布与认证 | 超过 32 MiB 的证明和快照在 Directory 与 S3 上发布、读取、GC 通过 |
| 7：WebDAV 存放点 | `ObjectStore` 的 WebDAV 实现，自建与云盘兼容 | 存放点契约测试在真实 WebDAV 服务上通过 |
| 8：规模验收 | 按规模预算执行百万文件、1 TB、100 GB、10 设备 | 预算表每一项有实测结果与证据 |
| 9：挂载由归属进程提供 | 归属进程内的挂载服务，CLI 与 App 请求挂载 | 已打开仓库的 App 可挂载和卸载；CLI `mount` 两种路径都通过 |
| 10：Tauri 桌面 MVP | 壳、内嵌服务、现有 UI、托盘、自启动、钥匙串、文件对话框与拖拽，macOS 打包 | 解锁、浏览、上传下载、配对、撤销、同步状态、挂载开关在 App 内可用；UI 测试沿用现有 Node 用例 |
| 11：Windows 挂载 | WinFsp 适配 | Windows 上挂载读写、冲突视图、卸载通过 |
| 12：Windows 与 Linux 打包 | Tauri 打包、签名、自动更新通道 | 三平台安装包可安装、升级、卸载 |
| 13：同步明文文件夹 | 目录监视、双向同步、冲突与删除语义、忽略规则 | 本机改动与远端版本双向收敛；冲突只出现在冲突视图；离线改动重连后发布 |
| 14：UniFFI 绑定 | Kotlin/Swift 生成，覆盖 `cipherfs-api` 全部门面 | 与 C/Python/Go 相同的生命周期断言在 Kotlin/Swift 测试通过 |
| 15：Android App | 解锁、浏览、按需读取、固定目录、DocumentsProvider、存放点后台同步 | 真机或模拟器上 Partial 角色按需读取、缓存预算与后台同步验收 |
| 16：云盘 API 存放点 | OneDrive、Dropbox、Google Drive 的 `ObjectStore` 实现与授权 | 各存放点契约测试通过；令牌只存钥匙串 |
| 17：iOS App | File Provider 扩展持有仓库，主 App 客户端，存放点后台同步 | 文件 App 内浏览与按需下载；扩展内存上限内通过 |
| 18：发布准备 | 格式冻结、版本号、变更记录、首个发布 | README、架构、实现记录与本页收尾；发布包和文档一致 |

依赖关系：1、2、3、5、6、7 彼此独立，可并行；4 等 Windows 机器；8 依赖 6；9 依赖 1；10 依赖 1、2、9；11 依赖 4、9；12 依赖 4、10；13 依赖 9；14 依赖 2、3；15 依赖 14、6；16 依赖 2；17 依赖 14、15、16 中至少一种 API 存放点；18 最后。

## 验收要求

- 每步宿主 `scripts/projects.sh format --check`、`check`、`clippy` 零警告，`scripts/projects.sh test` 在固定容器完整通过；不在宿主安装工具、包或工具链。Tauri CLI、Android SDK/NDK、iOS 目标与 Windows 工具链需要各自的构建环境，放在哪台机器或容器由用户决定后再开始对应步骤。
- 新增能力只在 Core 和 Sync 实现一次，壳层不复制规则、不把未实现操作报告为成功。
- 每步的失败与取消记录独立归档，不计入完整通过。
