diff --git a/docs/tasks/T-240.md b/docs/tasks/T-240.md new file mode 100644 index 0000000..b887ad5 --- /dev/null +++ b/docs/tasks/T-240.md @@ -0,0 +1,79 @@ +--- +id: T-240 +title: 缓存并鉴权提供顺运宝货运商品图片 +phase: 2 +deps: + - T-239 +status: TODO +created: 2026-07-29 +context_ref: 3bd9726 +work_branch: null +write_paths: + - docs/tasks/T-240.md + - docs/api.md + - docs/current-state.md + - backend-api/migrations/00016_freight_item_images.sql + - backend-api/cmd/api/** + - backend-api/internal/domain/freight.go + - backend-api/internal/platform/shunyunbao/** + - backend-api/internal/usecase/freight_* + - backend-api/internal/repository/sqlite/freight_* + - backend-api/internal/transport/httpapi/** + - backend-api/internal/transport/webui/** +--- + +## 问题 / 背景 + +货运商品已保存来自 ERP `productThumb` 的正整数引用,但 Admin 只能看到引用文本。浏览器直接 +拼接或热链 ERP 地址会泄露外部资源标识、绕过本系统鉴权,并依赖手机或浏览器是否持有 ERP +会话;把货运图片写成 `TASK_REFERENCE` 又会混淆资产所有权和用途。 + +图片 endpoint 已知为 `/api/p/file?id=`。查询参数必须取商品 `productThumb`, +不能取货运单 ID 或商品明细 ID;是否需要 Cookie/Token 必须通过与现有 ERP 查询相同的会话 +客户端兼容。 + +## 关联需求与交互 + +- 单号或日期同步取得商品引用后,由 Go 后端从固定 ERP endpoint 下载图片并保存到本地。 +- 货运列表和详情只使用本系统的同源鉴权 URL,不向浏览器暴露 ERP URL 或文件路径。 +- 图片失败不得回滚已经成功导入的货运头和商品明细;页面显示明确占位状态并允许后续同步重试。 +- 重复同步且 `productThumb` 未变化时复用本地文件,引用变化时下载新文件并清理被替换文件。 + +## 方案 + +1. 新增 `freight_item_images`,按货运商品保存 `product_thumb_ref`、`READY/MISSING/FAILED` + 状态、规范化 JPEG 元数据、稳定错误码、尝试次数和更新时间。缺少记录但商品有引用视为 + `PENDING`。 +2. `SessionManager` 使用配置的 ERP origin、固定 `/api/p/file` 和 `url.Values` 构造请求; + 复用 Cookie jar、固定请求头、HTTPS、禁止重定向及超时,只接受 2xx 图片响应。401/403 + 使会话失效,404 映射为 `MISSING`,其他错误映射为 `FAILED`。 +3. 复用现有图片文件存储完成 20 MiB、尺寸、像素、解码格式、白底合成、最长边 2048 px 和 + JPEG 规范化,不在日志输出图片字节、Cookie、查询参数或本地路径。 +4. 货运事务先提交并标记同步成功,再在调用方剩余预算内执行有界 best-effort 缓存;单图失败 + 仅保存状态。同步重放或下一次同步重试未就绪图片,不重复下载相同引用的 `READY` 图片。 +5. 增加受 Admin 会话保护的 + `GET /api/v1/freight-items/{item_id}/image`,仅从本地存储返回 JPEG,带 + `nosniff`、ETag、长度和私有缓存头;不存在、未完成或无权限统一返回 404。 + +## 验收要点 + +- [ ] 图片请求固定为配置 ERP origin 的 `/api/p/file?id=`,不接受任意 URL。 +- [ ] 请求复用现有 ERP Cookie jar,禁止重定向;401/403、404、错误类型和无效图片稳定分类。 +- [ ] 有效 JPEG/PNG/WebP 规范化保存为本地 JPEG,大小和像素限制不回归。 +- [ ] 货运元数据先成功提交;单图失败不改变同步 `SUCCEEDED`,状态可审计并在后续同步重试。 +- [ ] 相同 READY 引用不重复下载;引用变化替换关联并 best-effort 删除旧文件。 +- [ ] Admin 图片接口只返回当前商品本地 READY 图片,未授权及其他状态不泄露存在性。 +- [ ] 自动测试不访问真实 ERP,覆盖 Cookie、URL、重定向、状态、去重、替换和内容响应头。 +- [ ] 标准 Go 测试、race、vet 和三个入口构建通过。 + +## 边界 + +- 本任务不修改货运列表和详情的视觉布局;页面引用图片 URL 和占位视觉在 T-241 完成。 +- 不建立通用媒体库、不向浏览器返回 ERP URL、不持久化 ERP Cookie/Token。 +- 不保证每张外部图片都成功;网络、会话和上游文件错误按商品隔离。 +- 不提交或记录真实 ERP 图片、订单、商品、收件人、账号或会话数据。 + +## 执行记录 + +- 2026-07-29:创建任务。采用货运商品专属图片元数据表并复用安全文件编码管线;先提交货运 + 元数据,再 best-effort 缓存图片,避免单个外部文件阻塞或回滚完整订单。