Case study
Milk & Henny Sharing
Work on the tools around the archive: event-night check-in, voting, uploads, private transfers, downloads, auth, cleanup, and cost controls.
Tension
The product problem beneath the work.
The product came from a simple repeated friction: I would take photos at parties, while travelling, and on film/digital cameras, then people would ask for them afterwards. Milk & Henny makes that exchange cleaner: an event can have tools, a gallery can have filters and downloads, and large media can stay cheap instead of becoming a chain of temporary transfer links.
Threads
Three contracts behind sharing without the chase.
Owned
What I was responsible for, and what it changed.
| Thread | Work | Signal |
|---|---|---|
| Event operations | Built the party hub, guest-list check-in, admin management, best-dressed voting, vote-code controls, multi-device sync, and album download paths. | The site supports the whole event loop: guests arrive, participate, find photos, and leave with a way to get what they need. |
| Photo sharing | Built private transfer links, R2 storage, presigned uploads, delete tokens, media previews, optimized galleries, and batch download paths. | People can browse and download their own photos from an owned surface instead of repeatedly asking for files after the event. |
| Operational control | Implemented httpOnly role cookies, token revocation/versioning, admin step-up, cron cleanup, R2 lifecycle guidance, worker fallbacks, and CLI diagnostics. | The archive can stay inexpensive and recoverable: sessions can be revoked, files can expire, credentials can rotate, and costs have guardrails. |
Mechanism
The technical layers behind those responsibilities.
| Layer | Detail |
|---|---|
| Guest list | Door-staff check-in uses server-readable auth, optimistic UI, multi-device polling, CSV import, plus-one handling, and conservative fetch gaps. |
| Best dressed | Voting uses staff-minted one-time codes, optional voting windows, per-device identity, server validation against the guest list, and admin resets. |
| Upload path | Browser uploads use presigned PUT URLs so large photo and video files go directly to Cloudflare R2 instead of through serverless request bodies. |
| Lifecycle | Transfer metadata lives in Redis with TTL, pages are noindexed, delete tokens are separate from recipient links, and cron/R2 lifecycle cleanup catches residue. |
| Heavy media | Hybrid processing handles RAW previews, video posters, browser HEIC/HIF conversion, and ZIP fallback for multi-file downloads. |
| Auth model | Role JWTs live in httpOnly cookies; API bearer auth remains available for CLI and tools; admin actions use step-up tokens and revocation checks. |
| Cost guardrails | CDN caching, direct R2 media delivery, polling budgets, retry rules, rate limits, and documented rotation paths reduce expensive surprises. |
Shape
How event media becomes self-serve.
- Event tools define the role first: guest, staff, or admin.
- Live state stays lightweight so check-in and voting remain usable during the night.
- Uploads go straight to R2 while metadata records expiry, ownership, and deletion paths.
- Galleries and transfer pages expose previews, filters, sorting, and downloads so recipients can self-serve.
- Auth, cleanup, budgets, and rate limits keep the archive private, cheap, and recoverable.
Reflection
What the project clarified about sharing.
The nicest sharing experience is often the one where nobody has to ask twice. People can find themselves, choose the quality they need, and download from a place that feels like mine rather than a temporary workaround.