Files
MichilisandCursor c9a600b6d6 Add photo galleries API and frontend for public and admin viewing.
Introduces the Go photo-api service, nginx/systemd deploy wiring, and Next.js gallery/lightbox pages so event photos can be managed and browsed.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-25 17:32:23 +00:00

4.2 KiB

photo-api

Standalone Go service for event photo galleries: admins upload photos from past events, group them into galleries, and share them with the community. Lives in this monorepo but is its own module, binary, and deployable unit. Design/decisions: PLAN.md.

What it does

  • Galleries with four visibility modes: public (listed on /photos), private (admins only), link (share-token URL), ticket (logged-in users with a confirmed ticket for the linked event — any confirmed ticket when the event is free).
  • Originals are stored byte-identical for download; a worker generates JPEG variants (thumb 512px q78, preview 2048px q85, EXIF stripped/orientation applied) queued in the DB with retries.
  • Storage: local disk (STORAGE_PATH) or S3/Garage/MinIO (set S3_ENDPOINT
    • S3_BUCKET), same selection convention as the backend. S3 downloads use short-lived presigned URLs; nothing in the bucket is public.
  • Auth: validates the backend's HS256 JWTs with the shared JWT_SECRET (issuer spanglish, audience spanglish-app) including the DB-backed tokenVersion/account-status revocation check. Admin surface is admin/organizer only.
  • Database: the same Postgres or SQLite database as the backend (DB_TYPE, DATABASE_URL). This service owns only the photos_* tables via its own embedded migrations (photo-api migrate); drizzle-kit never sees them. Reads of backend tables are confined to internal/store/access.go and sanity-checked at startup.

Develop

cp .env.example .env       # set JWT_SECRET + DATABASE_URL to match backend/.env
go run ./cmd/photo-api migrate
go run ./cmd/photo-api     # serves on :3003 (dev)
go test ./...              # SQLite; add PHOTO_TEST_PG=<url> to also run on Postgres

From the repo root: npm run dev:photos, npm run build:photos, npm run test:photos. The Next dev server rewrites /api/photos/* to PHOTO_API_URL (default http://localhost:3003), so the frontend needs no extra config in dev.

HEIC uploads require a converter CLI on the host: apt install libvips-tools (or libheif-examples). Without one, HEIC uploads are rejected with a clear message and a startup warning is logged.

API

Everything under /api/photos. Errors are {"error": string}.

Admin (Bearer token, role admin/organizer):

Method Path Purpose
POST /api/photos/galleries create gallery
GET /api/photos/galleries list all (?eventId=)
GET /api/photos/galleries/:id gallery + photos (all statuses)
PATCH /api/photos/galleries/:id update title/visibility/event/cover
DELETE /api/photos/galleries/:id delete gallery + objects
POST /api/photos/galleries/:id/photos multipart upload (files)
PATCH /api/photos/galleries/:id/order reorder ({photoIds})
POST /api/photos/galleries/:id/share-token rotate share token
DELETE /api/photos/photos/:photoId delete photo
POST /api/photos/photos/:photoId/retry requeue failed photo

Viewer (anonymous or member token; ?token= carries the share token):

Method Path Purpose
GET /api/photos/public/galleries public index
GET /api/photos/public/galleries/:slug gallery view (access-checked)
GET /api/photos/public/events/:eventSlug/gallery newest gallery of an event (access-checked)
GET /api/photos/files/:photoId/:variant bytes; thumb|preview|original
GET /api/photos/health liveness

Deploy (systemd, primary)

cd photo-api && go build -o bin/photo-api ./cmd/photo-api
sudo apt install libvips-tools
sudo cp ../deploy/spanglish-photos.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable --now spanglish-photos
sudo nginx -t && sudo systemctl reload nginx   # after installing the updated confs

nginx routes location ^~ /api/photos/127.0.0.1:3020 (see deploy/front-end_nginx.conf, deploy/back-end_nginx.conf, deploy/spanglish_upstreams.conf). The frontend's production .env should set PHOTO_API_URL=http://127.0.0.1:3020 for server-side rendering of the public gallery pages. A Dockerfile is included as a secondary path for the compose-scale setup.