Creative
Client galleries and proofing for a photographer
A photographer uploads a shoot, the client opens a private gallery, marks the photos they want retouched, and approves the final set. Downloads are watermarked until the invoice is paid. Each gallery expires after ninety days.
Automatically generated draft
Written by machine against our own engineering playbook. The company is invented; the decisions are the ones we would make on a real build. A reviewed blueprint goes further — nine sections, agreed line by line, and it is what the build is tested against.
Section 01 · What has to work
The core loop is the client selecting photos for retouching from a private gallery and gaining access to unwatermarked downloads upon payment.
Section 03 · Screens
Every screen, and what it is for.
- ›Photographer Dashboard — Photographer sees all shoots. Loading the list must be instant.
- ›Shoot Upload — Photographer creates a gallery and uploads photos. Upload progress must be instant.
- ›Client Gallery — Client views thumbnails and makes selections. Thumbnails loading must be instant.
- ›Selection Review — Photographer views client's selected photos. Seeing selections must be instant.
- ›Final Approval — Client views retouched photos to approve the set. Approval status change must feel instant.
- ›Invoice & Download — Client pays invoice and downloads photos. Download appearing after payment must be instant.
Anything not on this list is not in version one. That is what keeps a fixed price fixed.
Section 04 · The data model
What it stores, and who can read a row.
user
id uuid, email text, name text, role enum('photographer', 'client'), created_at timestamptz
Access · A user can read their own row.
shoot
id uuid, photographer_id uuid, client_email text, name text, status enum('proofing', 'retouching', 'approval', 'paid', 'archived'), expires_at date, created_at timestamptz
Access · Photographer can read their own shoots; client can read their assigned shoot.
photo
id uuid, shoot_id uuid, storage_key text, status enum('uploaded', 'selected', 'retouched', 'approved'), uploaded_at timestamptz
Access · Users with access to the parent shoot can read its photos.
invoice
id uuid, shoot_id uuid, amount_cents int, status enum('pending', 'paid', 'failed'), created_at timestamptz, paid_at timestamptz
Access · Photographer or assigned client can read the invoice for their shoot.
Those access rules belong in the database, not in the screens. Someone who edits the address bar still cannot read a row that is not theirs — and the test that proves it blocks delivery if it fails.
Section 05 · States
proofing → retouching → final_approval → pending_payment → complete | expired
Most scope arguments three weeks into a build are really arguments about a state nobody named at the start.
Section 06 · Where this breaks
What bites products like this one.
On-the-fly watermarking causes slow downloads and high server load, especially for large photos.
Pre-generate watermarked versions on upload and store them separately; serve the pre-generated file.
The 90-day expiration job fails, leaving paid or unpaid galleries open indefinitely.
Enforce expiration at the access-check level, not just via a background job.
Large, high-resolution photo uploads from mobile devices can fail on unstable connections.
Implement chunked, resumable uploads to handle network interruptions gracefully.
Section 08 · Deliberately left out
What version one does not do.
- ×Automated gallery archiving after 90 days — it requires a background worker, which adds complexity. Photographer can manually archive for v1.
- ×In-app re-upload and versioning for retouched photos — photographer can replace original files and handle communication externally for v1.
This is the section that protects the date, and the only place in the document where somebody says no. It is also why clients trust the rest of it.
Still open
What we would ask before quoting.
- How are clients created or invited? Is it via an email link sent by the photographer?
- What payment processor will be used for invoices? This determines the integration work required.
- Are there different prices or retouching rules per-photo, or is it one invoice for the entire approved set?
Your product, not this one
Get this written for what you are actually building.
Describe it in a sentence and the generator returns the same sections for your own product. Free, no email, nothing saved to a list.
Next step
Find out if your idea fits in 10 working days.
Tell us what you want to build. We reply the same day with a straight yes, no, or here is what we would cut.