This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
# 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:
|
||||
|
||||
```txt
|
||||
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:
|
||||
|
||||
```bash
|
||||
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.
|
||||
Reference in New Issue
Block a user