# Upload 模块业务逻辑

## 模块职责

Upload 模块负责 App 内通用文件上传能力，当前主要服务个人头像和实名认证证件图片，后续云盘、相册、任务、打卡点等模块迁移时复用同一套 OSS 上传入口。

该模块不负责业务表单提交，只负责：
- 获取阿里云 OSS STS 临时配置。
- 校验待上传文件大小和扩展名。
- 生成按业务模块隔离的 OSS objectKey。
- 调用阿里云 OSS Swift SDK 上传文件。
- 返回最终可访问的文件 URL。

## 核心对象

- `UploadAPI`：封装 `/api/app/config/get-sts-token`，只负责获取 STS 临时上传配置。
- `OSSUploadService`：统一上传服务，封装 SDK 调用和进度回调。
- `OSSUploadPolicy`：上传策略，管理大小限制、扩展名白名单、路径规则、MIME 类型和 URL 拼接。
- `AvatarImageProcessor`：头像图片处理器，上传前把图片压缩为 JPEG。
- `RealNameImageProcessor`：实名认证证件图片处理器，上传前把证件图压缩为 JPEG。
- `RemoteImage`：Kingfisher 网络图片组件，统一远程图片加载、缓存和失败占位。

## 上传流程

1. 页面或 ViewModel 将用户选择的本地图片处理成上传数据。
2. ViewModel 调用 `OSSUploadService` 的业务上传方法。
3. `OSSUploadService` 调用 `UploadAPI.aliyunOSSBucket(bucket:)` 获取 STS 配置。
4. `OSSUploadPolicy` 校验文件并生成 objectKey。
5. `OSSUploadService` 使用 `AlibabaCloudOSS` SDK 上传数据。
6. 上传成功后返回 `base_url + objectKey`。
7. 业务 ViewModel 再把 URL 提交给对应业务接口。

## 路径规则

当前模块路径：
- `user_avatar`：`avatar/yyyyMMdd/scenicId/uuid_fileName`
- `real_name`：`real_name/yyyyMMdd/scenicId/uuid_fileName`
- `task_upload`：`task_upload/yyyyMMdd/scenicId/uuid_fileName`
- `cloud_driver`：`cloud_driver/yyyyMMdd/scenicId/uuid_fileName`
- `album_upload`：`album/yyyyMMdd/scenicId/uuid_fileName`
- `punch_point`：`punch_point/yyyyMMdd/scenicId/uuid_fileName`
- `scenic_apply`：`scenic_apply/yyyyMMdd/scenicId/uuid_fileName`

文件名会清理控制字符、`/` 和 `\`，避免生成非法 objectKey。

## 缓存边界

- OSS STS token 不落盘，只在一次上传流程中临时使用。
- 原始图片 Data、压缩后图片 Data、上传进度不落盘。
- 图片展示缓存交给 Kingfisher，业务代码不自行保存网络图片文件。
- 正式登录 token 仍由 `SessionTokenStore` 使用 Keychain 保存，上传模块不直接读取或保存登录态。
