feat: media 域最小闭环——存储适配层 + MinIO 预签名两步上传(ADR-016/017,T3-03)

- ObjectStorage 适配层(供应商唯一缝)+ S3ObjectStorage(AWS SDK v2,
  path-style,内网/公网双端点分离签发);endpoint 未配置时服务可启动、
  media 端点 500(沿 JWT 公钥先例)
- POST /api/v1/media/uploads:白名单校验(purpose/mime/byteSize 全配置项)
  → uploading 行(objectKey 服务端生成不含用户输入)→ 预签名 PUT 凭据
  (requiredHeaders 定型仅 Content-Type,TTL 10m)
- complete:HEAD 校验存在性/大小/类型 → uploading→ready(guarded UPDATE
  并发幂等);对象缺失保持 uploading 可重试,内容不符置 failed 终态;
  防枚举 40405;新错误码 40405/42205
- 读取侧预签名 GET(TTL 1h),桶保持私有
- compose 纳入 minio 第六容器(镜像与 Testcontainer 同 tag,桶初始化走
  应用启动 ensureBucket,三环境零分叉);init-secrets.sh 幂等追加 MinIO
  根凭证到 .env(凭证零入库,ADR-021)
- MediaUploadIntegrationTest 12 例:MinIO Testcontainer 全链路直传取回 +
  六类失败路径 + 库层约束一致性;uploading 超时清理只记方案(报告 13 §6)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-08 17:11:44 +08:00
parent 8330885b06
commit 10a43f876c
17 changed files with 1248 additions and 0 deletions
+11
View File
@@ -20,6 +20,17 @@ if [ ! -f .env ]; then
echo "已生成 .env(随机 DB 口令与内部令牌)"
fi
# M3ADR-016/021):MinIO 根凭证。按键幂等追加,兼容已有 .env;
# 凭证只存在于被 gitignore 的 .env 中,绝不入库。
if ! grep -q '^PATBOND_MINIO_ROOT_USER=' .env; then
echo "PATBOND_MINIO_ROOT_USER=patbond-minio-$(openssl rand -hex 4)" >> .env
echo "已追加 PATBOND_MINIO_ROOT_USER 到 .env"
fi
if ! grep -q '^PATBOND_MINIO_ROOT_PASSWORD=' .env; then
echo "PATBOND_MINIO_ROOT_PASSWORD=$(openssl rand -hex 16)" >> .env
echo "已追加 PATBOND_MINIO_ROOT_PASSWORD 到 .env"
fi
# 容器内以 uid 10001 运行,密钥需可读
chmod 644 deploy/keys/jwt-public.pem deploy/keys/jwt-private.pem
echo "OKdeploy/keys/ 与 .env 就绪(均已被 .gitignore 忽略)"