2.5 KiB
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_uploadsmetadata. - 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/jpegimage/pngimage/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_uploadsis 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.