# 02 — 缩略图 API 读路径 + 占位图 **What to build:** 缩略图读取端点和按状态返回的行为。新增 `FileApi.getThumbnail(String fileId)` 方法返回 `byte[]`,`FileController` 新增 `GET /api/file/thumbnail?fileId=xxx` 端点(信封例外:成功返回 `image/jpeg` 二进制流,失败返回 JSON 信封)。新建 `ThumbnailPlaceholderService`,按文件扩展名返回预置的文件类型图标占位图。`getThumbnail` 行为:查 `FileInfo`(查无/已删除 → 40401)→ `thumbnail_status = READY` 时从 MinIO 拉 `thumbnails/{fileId}.jpg` 返回二进制 + `Cache-Control: max-age=86400`;`UNSUPPORTED`/`FAILED`/`PENDING` 返回占位图 + `Cache-Control: no-cache`。`FileInfoDTO` 新增 `thumbnailStatus` 字段(nullable,向后兼容)。可手动往 MinIO 塞缩略图并把状态设成 READY 来验证端到端。 **Blocked by:** 01 — 基础设施(prefactor) **Status:** ready-for-agent - [x] `FileApi` 接口新增 `ThumbnailDTO getThumbnail(String fileId)` 方法声明(原设计 `byte[]`,实现时改为 DTO 以承载 202 与缓存语义,见 spec §7.1) - [x] `FileApiImpl` 实现 `getThumbnail`:查 FileInfo → READY 拉缩略图对象返回 + max-age=86400;UNSUPPORTED/FAILED/PENDING 返回占位图 + no-cache - [x] `ThumbnailPlaceholderService` 新建,按扩展名返回文件类型占位图(原设计预置静态资源,实现改为运行时 Graphics2D 绘制 PNG + 扩展名文字,见 spec §7.1) - [x] `FileController` 新增 `GET /api/file/thumbnail` 端点,返回 `ResponseEntity`(信封例外) - [x] `FileInfoDTO` 新增 `thumbnailStatus` 字段,`from()` 方法补充映射 - [x] 测试:READY 状态返回 MinIO 缩略图二进制 + max-age=86400 - [x] 测试:UNSUPPORTED 状态返回占位图 + no-cache,不触碰 MinIO 缩略图路径 - [x] 测试:FAILED 状态返回占位图 + no-cache - [x] 测试:PENDING 状态返回占位图 + no-cache(本票不含同步生成) - [x] 测试:文件查无/已删除 → 40401 - [x] 测试:fileId 非法格式 → 40401