Feat: Proxy image content through the API instead of redirecting to MinIO
Replace the presigned-URL redirect (302) in GET /api/v1/images/{id}/file
with a direct proxy that fetches bytes from S3 server-side and returns them
to the client. The browser never contacts the storage backend, eliminating
the /etc/hosts workaround needed in local development.
- StorageBackend: swap get_presigned_url for get(key) -> bytes
- S3StorageBackend: implement get() via aiobotocore get_object
- serve_image_file: return Response with ETag + Cache-Control: immutable
- test_serving: assert 200 + content-type + ETag; add no-storage-details test
- Spec Kit artifacts for feature 002-api-image-proxy
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
25
specs/002-api-image-proxy/data-model.md
Normal file
25
specs/002-api-image-proxy/data-model.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Data Model: API Image Proxy
|
||||
|
||||
**Branch**: `002-api-image-proxy` | **Date**: 2026-05-03
|
||||
|
||||
## Summary
|
||||
|
||||
This feature introduces no new entities and no database schema changes.
|
||||
|
||||
The change is entirely in the *retrieval path* for image file content:
|
||||
- The `Image` entity's `storage_key` field is used as the S3 object key to fetch content from storage.
|
||||
- The `mime_type` field is used to set the `Content-Type` response header.
|
||||
- The `hash` field (SHA-256) is used to set the `ETag` response header.
|
||||
|
||||
All three fields are already present on the `Image` entity per the existing data model in `specs/001-reaction-image-board/plan.md`.
|
||||
|
||||
## StorageBackend interface change
|
||||
|
||||
The `StorageBackend` abstract interface (`api/app/storage/backend.py`) gains one method and loses one:
|
||||
|
||||
| Method | Change | Notes |
|
||||
|--------|--------|-------|
|
||||
| `get_presigned_url(key, expires_in_seconds)` | **Removed** | No callers remain after this feature |
|
||||
| `get(key: str) -> bytes` | **Added** | Returns full object content as bytes |
|
||||
|
||||
This is an interface change, not a data model change. The database schema is unaffected.
|
||||
Reference in New Issue
Block a user