Skip to main content

Gallery approval

The photographer uploads photographs to a private gallery, publishes the gallery, and then approves customer access. Those are different actions. A customer can view or download a photograph only when the gallery is published and access is approved.

Publication can be PUBLISHED while access is still PENDING_APPROVAL. That gallery is private.

Sequence​

Authorization check​

Every view and every download runs this check in Express. Next.js does not sign URLs.

CheckRequired value
SessionAuthenticated customer, from the access token.
Ownershipgalleries.customer_id equals the access token subject.
PublicationPUBLISHED.
AccessAPPROVED.
PhotoREADY and belongs to that gallery.

Failure returns no bytes and no URL. An administrator preview uses an admin route, requires MFA, and writes an audit row. It does not reuse the customer route with a skipped check.

Approval history​

galleries.access_status is the value the check reads. Each decision also inserts gallery_access_reviews:

DecisionAccess statusReview row
ApproveAPPROVEDAPPROVED, reviewer, optional reason, timestamp.
Reject before approvalREVOKEDREJECTED. The customer still cannot download.
Revoke after approvalREVOKEDREVOKED.

Review rows are append-only. The latest decision is also copied onto galleries.approved_by and galleries.approved_at when the status becomes APPROVED. Clearing approval on revoke does not delete the review history. approved_by may remain as the last approver; access_status is what authorization uses. A revoke sets access_status to REVOKED even if approved_by is still populated. The check requires APPROVED, so a leftover approver id does not grant access.

Signed URLs​

The API signs a URL only after the check passes. The lifetime is 5 minutes. Revocation stops new signatures. A URL that was issued earlier remains usable until it expires. That window is accepted so the storage service does not need a revocation list. The short lifetime is the control.

Originals and thumbnails stay in a private bucket. The database stores storage_key and thumbnail_key.

Uploads​

The API accepts JPEG, PNG, and WebP after checking the file signature, not only the extension. The initial size limit is 50 MB per original. A passing file is stored as PROCESSING. The worker writes the thumbnail and sets READY. Customers cannot request a photo that is not READY.

Ratings​

The gallery owner can rate a ready photo once, with an integer from 1 to 5 and optional feedback. The unique key is (photo_id, customer_id). The insert queues a notification to the photographer. Ratings are refused when access is not approved.