Your Capture Awards
A contest platform for photographers - entries, judging and results, at photograph file sizes. I owned the backend, the storage pipeline and the deployment. The interesting part was never the CRUD; it was that a contest deadline creates a traffic shape most systems never see.
- Year
- 2024
- Role
- Backend, API integration, deployment
- Context
- Client product
- Category
- Marketplace

The contest homepage.
Photographers submit at the last possible minute, at full resolution. That produces a sharp upload spike against the deadline, with each request an order of magnitude larger than a typical API call. Routing those bytes through the application server would have made the deadline the outage.
Uploads go directly to Amazon S3 rather than through the API, so the application handles metadata while S3 handles bytes. Email - entry confirmations, judging notices, results - runs through an Agenda-backed queue so a slow mail provider cannot stall a request. Socket.IO pushes contest and judging updates live, and the client uses RTK Query so repeated gallery views are served from cache instead of re-fetching.
How the pieces fit.
API
Express.js services for contests, entries and judging.
Storage
Amazon S3 for contest image uploads, keeping large objects off the app servers.
Queue
Agenda scheduling the email pipeline so delivery is decoupled from the request.
Realtime
Socket.IO for contest and judging notifications.
Client data
RTK Query for cache-aware fetching on the Next.js frontend.
Edge
Nginx reverse proxy on DigitalOcean, deployed via GitHub Actions.
Deployment
- GitHub Actions for CI/CD pipelines
- Hosted on DigitalOcean, domain registered with Namecheap
- Nginx as reverse proxy, TMUX for session management
- Direct-to-S3 uploads for full-resolution contest entries
- Agenda-backed email queue for confirmations, judging notices and results
- Real-time notifications keeping entrants updated during judging
- RTK Query caching to keep gallery browsing cheap
The parts that were not obvious at the start.
- 01
The deadline spike
Submission traffic is not uniform - it is nearly all in the final hours. Moving uploads off the application path meant the spike hit object storage, which is built for it, instead of Node processes, which are not.
- 02
Email that cannot block a request
Contest emails go out in bursts to large recipient lists. Sending inline would have tied request latency to a third-party mail provider's worst day. Queueing through Agenda made delivery a background concern with retries.
- Live at yourcaptureawards.com
- Handles full-resolution submission bursts against contest deadlines
- Automated deploys through GitHub Actions
- Never let user file bytes travel through your application server if object storage can take them directly.
- Anything that talks to a third party belongs in a queue, not in the request.