Context
Editors need to attach media without putting large binary files in the application database. The public website also needs predictable image dimensions and useful descriptions.
The constraint
An extension or browser-supplied MIME type does not establish that an upload contains a valid image. Retrying completion should not replace an already published object.
The approach
The API signs a bounded staging upload and a completion claim. Completion verifies the stored object size and type, bounds streamed bytes, decodes the image, rejects unsupported or animated inputs, strips metadata and emits a separate WebP asset.
Architecture
- 01Editor selects an image
- 02Signed upload to a private staging key
- 03API verifies object and decodes pixels
- 04Immutable WebP asset and metadata
- 05Responsive public rendering
Decisions and tradeoffs
Original staging objects remain private. Only the optimized asset path is intended for the public asset origin.
Metadata removal is soft deletion. Reference checks protect used assets, while physical retention and cleanup remain an explicit operations task.
Implementation
Supported inputs are PNG, JPEG, WebP and AVIF. The decoder caps input pixels and limits output dimensions; the object is stored under a distinct immutable key.
Evidence and outcomes
A local integration test performs a real signed POST against an S3-compatible emulator, completes the upload and verifies decoded WebP output. Production bucket policy and CORS require deployment configuration.
Stack
NestJS
PostgreSQL
Prisma
Next.js