When my good friend Renas Demir was planning his wedding, he asked if I knew of any service where guests could easily share their photos. Instead of pointing him to an existing solution, I offered to build something custom for them. The result was ayserenas.dk, a simple web app where guests could scan QR codes at their tables and instantly upload photos from their phones.

Wedding tables with QR codes allowing guests to upload photos instantly
Results
The wedding day was a complete success:
- 212 guests visited the website
- 91 memories collected
- 1 happy bridal couple
Zero downtime throughout the event, and guests aged 20 to 70 uploaded successfully without help.
Requirements
Before diving into code, I mapped out what the app needed to accomplish:
Functional requirements:
| ID | Description |
|---|---|
FR01 | Guests must be able to access via a QR code |
FR02 | Guests must input name before uploading photos |
FR03 | Guests must be able to upload multiple photos |
FR04 | The system must validate file types (JPEG, etc.) |
FR05 | The system must enforce a 5MB max per photo |
FR06 | The system must store photos securely |
FR07 | The system must show name with each photo |
FR08 | The couple must have access to a gallery |
FR09 | The couple must receive email notifications |
Most importantly, it needed to be fast, reliable and simple enough for anyone to use, whether they are 20 or 70 years old.
How it works
I built the app with Next.js 15, using React for the interface and Tailwind CSS for styling. For the backend, I used PostgreSQL to store photo information and Supabase Storage to host the actual images. This setup gave me fast loading times and the ability to handle multiple uploads at once.
The stack:
- Next.js 15 for the web framework
- React Hook Form & Zod for handling uploads and validation
- PostgreSQL & Prisma for storing and querying photo metadata
- Supabase Storage for images
- Nodemailer for sending instant email notifications
The upload flow
When a guest scans the QR code, here's what happens:
- Land on the home page
- Tap the upload button
- Enter their name
- Select photos from phone
- The app validates the files
- Photos upload in parallel
- Metadata is saved to the database
- The couple gets an instant email
- Photos appear in the gallery
The entire app runs on Vercel's serverless platform, which automatically scales to handle many uploads at once, which suited when everyone's taking photos during the wedding.
System architecture
Here's how all the pieces fit together:

Building the upload system
The heart of the app is the upload endpoint. When photos come in, the system processes them efficiently by handling multiple uploads at the same time. Each photo gets a unique name, gets stored in Supabase, and its information is saved to the database. Once everything's uploaded, an email fires off to the couple with a preview of the new photos.
This parallel processing approach means that when guests upload several photos at once, they do not have to wait for each one to finish before the next starts. Everything happens simultaneously, which makes the experience feel instant.
The user experience
I kept the interface simple and clean. The home page greets guests with a welcoming photo and a clear call-to-action button.

The upload page has just two things: a field for their name and a button to select photos. Behind the scenes, it checks that files are the right type and not too large.

For the couple, there's a private gallery showing all uploaded photos in a grid layout, with each guest's name displayed alongside their contributions.

The gallery displays all wedding photos with guest names in a responsive grid
Staying in the loop
Every time a guest uploads photos, the couple gets an email showing who uploaded, how many photos, and small preview thumbnails. This way, even during the busy wedding day, they can see the memories being captured in real-time.

Wrapping up
Building this app taught me that sometimes the best solutions are the simplest ones. By focusing on making photo uploads effortless, the app just worked - no complicated instructions needed, no technical support required on the wedding day.
The combination of Next.js, Prisma, and Supabase gave me everything I needed to build something reliable and fast. But the best part? Seeing friends celebrate their special day while my code quietly worked in the background, capturing their memories.