Files
wedding-website/plans/milestone-06-minio-uploads.md
Raul Lugo 4ced446c9c
Build & Deployment / Build & Deploy (push) Failing after 5s
initial commit
2026-08-10 17:55:26 +02:00

2.5 KiB

Milestone 06 — MinIO Photo Uploads

Reference

Read plans/wedding-bootstrap-plan.md first. This milestone depends on Milestones 01, 03, and 04.

Goal

Add one-photo-per-invitation upload support using MinIO through S3-compatible presigned URLs.

Scope

Implement only:

  • S3/MinIO client.
  • Presigned upload endpoint.
  • Upload completion endpoint.
  • Guest-facing photo upload UI.
  • One-current-photo-per-invitation behavior.
  • Replacement until deadline.
  • Admin signed preview/download URL.
  • Upload validation.

Non-goals

Do not implement:

  • Multiple photos per invitation.
  • Public unauthenticated photo browsing.
  • Image processing/resizing unless explicitly requested later.
  • Complex gallery UI.
  • Another storage provider.

Required constraints

  • Use MinIO via S3-compatible AWS SDK APIs.
  • One image per invitation/group.
  • Replacing the image is allowed until RSVP_DEADLINE.
  • After the deadline, guest upload is read-only/disabled.
  • Validate invitation token before presigning upload.
  • Admin UI must use shadcn/ui components only.
  • Guest-facing copy must use invitations.language.

Implementation tasks

  • Add lib/storage/s3.ts.
  • Add upload helper functions in lib/storage/uploads.ts.
  • Add validation schema for presign/complete requests.
  • Add app/api/uploads/presign/route.ts.
  • Add app/api/uploads/complete/route.ts.
  • Generate object keys like:
invitations/{invitationId}/{uuid}-{safeFilename}
  • Upsert photo_uploads metadata.
  • Optionally delete old object when replacing.
  • Add guest upload component/section.
  • Add localized upload copy.
  • Add admin preview/download via short-lived signed GET URL.

Validation rules

  • Allowed MIME types:
    • image/jpeg
    • image/png
    • image/webp
  • Enforce a maximum file size.
  • Require valid invitation token.
  • Require deadline not passed for guest upload/replace.

Verification

Run:

docker compose up -d postgres minio minio-init
npm run lint
npm run build

Manual checks:

  • Guest can upload one valid image.
  • Admin can preview/download the image.
  • Guest can replace image before deadline.
  • Metadata in photo_uploads is updated on replace.
  • Invalid MIME type is rejected.
  • Oversized file is rejected.
  • Invalid token cannot presign upload.
  • After deadline, upload/replace is disabled.
  • Admin pages use shadcn/ui only.

Acceptance criteria

  • MinIO upload flow works end-to-end.
  • Exactly one current photo is associated with each invitation.
  • Uploads are secured by invitation token and deadline.
  • Admin can access uploaded photo previews/downloads.