# CameraTransfer

## 职责

编排相机照片从下载到上传的通用流程，通过 `CameraAssetUploadSink` 与业务层解耦。

## 核心组件

| 组件 | 说明 |
| --- | --- |
| `CameraTransferPipeline` | 监听 `onNewAsset`、管理任务队列与上传 |
| `CameraTransferTask` | 单条传输任务及状态 |
| `CameraAssetUploadSink` | 上传协议，由业务模块实现 |
| `CameraDownloadStorage.Scope` | 账号 + 相册维度的本地文件隔离作用域 |

## 业务流程

1. 相机服务回调 `onNewAsset`。
2. Pipeline 下载文件到当前 scope 的 `originals` 目录并更新任务状态。
3. 若照片是在开启自动上传时由 `onNewAsset` 新发现，加入自动上传资格队列并调用 `CameraAssetUploadSink.upload`。
4. 上传成功后任务状态变为 `uploaded`。

`syncExistingPhotos()` 仅同步相机历史照片到本地任务列表，不授予自动上传资格。拍后传输模式下已下载的 `downloaded` 任务，切换到边拍边传后仍保持待上传，只有业务层显式调用 `uploadAssets(withIDs:)` 或 `retryUpload(...)` 时才会上传。

本地文件路径按 `Documents/CameraDownloads/<accountKey>/<albumID>/originals/` 存放原图，缩略图由业务层生成到同 scope 的 `thumbnails/`。持久化只记录相对 Documents 的 scoped 路径，不保留未上线旧目录兼容。

## 与业务层关系

- 旅拍相册通过 `TravelAlbumMaterialUploader` 实现 Sink：OSS 上传 + `upload-material` 登记。
- Pipeline 不依赖任何 HTTP 或 OSS 具体实现。
