feat: add email verification, profile pictures, deposits, and calendar
export Backend: - Add email verification code generation and verification endpoints - Add profile picture upload with S3 storage and image processing - Add deposit_required field to users with 48h advance booking requirement - Add loyalty stamps that accumulate on completed bookings - Auto-transition bookings: confirmed → in_progress → completed - Add booking cancellation handler with no-show detection - Add ICS calendar file download endpoint for bookings - Sync bookings to CalDAV on confirmation Frontend: - Add schedule page route - Add avatar and image-cropper UI components - Update shadcn-svelte components (button, dialog) - Add "Add to Calendar" button in booking modal Database: - Add verification_codes table - Add profile_pic_url, loyalty_stamps, deposits_required to users - Various schema updates
This commit is contained in:
@@ -46,8 +46,8 @@
|
||||
- [x] `/api/admin/bookings/{id}/progress` - Progress booking status
|
||||
- [x] `/api/admin/bookings/{id}/confirm` - Confirm booking
|
||||
- [x] `/api/admin/bookings/{id}/cancel` - Cancel booking
|
||||
- [ ] **In-progress auto-infer** - Status should auto-set based on time
|
||||
- [ ] **Begin button on Today** - Manual start for early arrivals (gray out if >3hrs away)
|
||||
- [x] **In-progress auto-infer** - Status auto-sets based on time (confirmed → in_progress → completed)
|
||||
- [x] **Auto-complete** - Bookings auto-complete when duration elapses
|
||||
|
||||
#### Admin Endpoints
|
||||
- [x] `/api/admin/services` - Create, delete, list, toggle
|
||||
@@ -69,11 +69,24 @@
|
||||
|
||||
#### User Endpoints
|
||||
- [x] `/api/user/profile` - GET, PUT
|
||||
- [x] `/api/user/profile-picture` - POST upload profile picture (separate bucket)
|
||||
- [x] `/api/user/account` - DELETE (GDPR compliant)
|
||||
- [x] `/api/user/loyalty` - GET loyalty stamps
|
||||
- [x] `/api/contact` - Public endpoint returning first admin's contact info (name, phone, email, profilePicUrl)
|
||||
- [ ] **GDPR data export** - `export_all_user_data()` exists but not wired to endpoint
|
||||
- [ ] **Tax data export** - Admin endpoint for tax-software-compatible format
|
||||
|
||||
#### Deposits System (Simplified)
|
||||
- [x] `users.deposits_required` INT DEFAULT 3
|
||||
- [x] 48h notice required when `deposits_required > 0`
|
||||
- [x] Reduces by 1 when booking completes with payment
|
||||
- [x] Increases by 3 on <12h cancellation (bad behavior)
|
||||
- [ ] Frontend display of deposits_required
|
||||
|
||||
#### CalDAV Contact Sync
|
||||
- [x] Profile photos synced to CardDAV contacts (PHOTO field in vCard)
|
||||
- [x] Auto-updates when profile is changed
|
||||
|
||||
#### Not Yet Wired
|
||||
- [ ] Social auth (`handlers/auth/social.go` exists, not imported)
|
||||
- [ ] Analytics (`handlers/admin/analytics.go` exists, not imported)
|
||||
@@ -91,13 +104,15 @@
|
||||
#### Core Pages
|
||||
- [x] Home (`/`)
|
||||
- [x] Prices (`/prices`)
|
||||
- [x] Contact (`/contact`)
|
||||
- [x] Contact (`/contact`) - Dynamic, fetches from `/api/contact`
|
||||
- [x] Book (`/book`) - Full wizard with service selection, date/time, customer details
|
||||
- [x] Portfolio (`/portfolio`) - S3/R2 storage with tag filtering, category filters, pagination, ?img= featured image, admin upload
|
||||
- [x] Today (`/today`) - Admin only, real-time schedule view
|
||||
- [x] Account (`/account`)
|
||||
- [x] Today (`/today`) - Admin only, real-time schedule view with auto-status transitions
|
||||
- [x] Schedule (`/schedule`) - User's upcoming bookings with .ics export
|
||||
- [x] Account (`/account`) - Profile management, profile picture upload with cropper
|
||||
- [x] Login (`/login`)
|
||||
- [x] Manage (`/manage`)
|
||||
- [x] Manage (`/manage`)
|
||||
|
||||
#### Admin Dashboard (`/admin`)
|
||||
- [x] Auth guard with role check
|
||||
@@ -149,6 +164,7 @@
|
||||
|
||||
- [x] CardDAV sync for contacts (SabreDAV)
|
||||
- [x] CalDAV ready
|
||||
- [x] Profile pics bucket - separate bucket `crussell-profile-pics` for user profile pictures
|
||||
- [ ] Email/SMS reminders - not yet implemented
|
||||
- [ ] Square payment - placeholder only
|
||||
- [x] S3/R2 image hosting - Rustfs for dev, Cloudflare R2 for prod via build tags
|
||||
@@ -356,17 +372,21 @@ admin_notification_reason: pending_booking | cancelled_booking | rescheduled_boo
|
||||
| Task | Description | Files Affected |
|
||||
| ------------------------------ | ------------------------------------------------------------------------------ | -------------------------------------------------------- |
|
||||
| **Customer booking submit** | `submitBooking()` at line 600 only logs, needs `POST /api/bookings` | `frontend/src/lib/components/booking/BookingFlow.svelte` |
|
||||
| **Remove console.logs** | Debug logs left in: `BookingFlow.svelte:600`, `BookingCreateModal.svelte:224` | Frontend components |
|
||||
| **Remove console.logs** | Debug logs left in: `BookingFlow.svelte:600` | Frontend components |
|
||||
| **Guest user endpoint** | Create `/api/users/guest` for walk-in bookings | `backend/handlers/user/` (new file) |
|
||||
| **In-progress auto-infer** | Auto-set `in_progress` status based on time | Backend booking logic |
|
||||
| ~~In-progress auto-infer~~ | ~~Auto-set `in_progress` status based on time~~ DONE | Backend booking logic |
|
||||
| ~~Auto-complete~~ | ~~Auto-complete bookings when duration elapses~~ DONE | Backend today handlers |
|
||||
| ~~Profile picture upload~~ | ~~Upload with cropper to separate bucket, sync to CalDAV~~ DONE | Backend + Account page |
|
||||
| ~~Contact page dynamic~~ | ~~Fetch from `/api/contact` using first admin~~ DONE | Backend + Contact page |
|
||||
| ~~Simplified deposits~~ | ~~`deposits_required` INT on users, 48h check, reduce on payment~~ DONE | Backend booking logic |
|
||||
| **Begin button (Today)** | Manual start for early arrivals, gray out if >3hrs away | `CurrentAppointment.svelte` + backend |
|
||||
| **One-off custom services** | Admin creates custom service for single booking without adding to main list | Backend + frontend booking modals |
|
||||
| **One-off exceptional hours** | Single-day exceptions (dentist, afternoon off) - not yearly/weekly | Backend scheduling + frontend HolidayHours |
|
||||
| **Auto lunch protection** | Block bookings that remove lunch break (1h customer, 30min admin with warning) | Backend `available-hours` logic |
|
||||
| **Walk-in slot blocking** | Properly block next available slot during walk-in intake | `WalkInCreateModal.svelte` |
|
||||
| **Square payment integration** | Full Square SDK integration | Backend payment handlers + frontend payment step |
|
||||
| **GDPR data export** | User button for "give me my data" using `export_all_user_data()` | Backend endpoint + account page |
|
||||
| **Tax data export** | Admin button for tax-software-compatible format | Backend endpoint + admin page |
|
||||
| **One-off custom services** | Admin creates custom service for single booking without adding to main list | Backend + frontend booking modals |
|
||||
| **One-off exceptional hours** | Single-day exceptions (dentist, afternoon off) - not yearly/weekly | Backend scheduling + frontend HolidayHours |
|
||||
| **Auto lunch protection** | Block bookings that remove lunch break (1h customer, 30min admin with warning) | Backend `available-hours` logic |
|
||||
| **Walk-in slot blocking** | Properly block next available slot during walk-in intake | `WalkInCreateModal.svelte` |
|
||||
| **Square payment integration** | Full Square SDK integration | Backend payment handlers + frontend payment step |
|
||||
| **GDPR data export** | User button for "give me my data" using `export_all_user_data()` | Backend endpoint + account page |
|
||||
| **Tax data export** | Admin button for tax-software-compatible format | Backend endpoint + admin page |
|
||||
|
||||
### Medium Priority
|
||||
|
||||
@@ -402,6 +422,17 @@ admin_notification_reason: pending_booking | cancelled_booking | rescheduled_boo
|
||||
| `POSTGRES_USER` | Database username | Docker |
|
||||
| `POSTGRES_PASSWORD` | Database password | Docker |
|
||||
| `POSTGRES_DB` | Database name | Docker |
|
||||
| `S3_BUCKET` | Main image bucket (portfolio) | No (default: crussell) |
|
||||
| `S3_PROFILE_PICS_BUCKET` | Profile pictures bucket | No (default: crussell-profile-pics) |
|
||||
| `S3_ENDPOINT` | S3/Rustfs endpoint | Dev |
|
||||
| `S3_PUBLIC_URL` | Public URL for S3 bucket | Dev |
|
||||
| `S3_ACCESS_KEY` | S3 access key | Dev |
|
||||
| `S3_SECRET_KEY` | S3 secret key | Dev |
|
||||
| `R2_ENDPOINT` | Cloudflare R2 endpoint | Prod |
|
||||
| `R2_BUCKET` | R2 bucket name | Prod |
|
||||
| `R2_PUBLIC_URL` | R2 public URL | Prod |
|
||||
| `R2_ACCESS_KEY` | R2 access key | Prod |
|
||||
| `R2_SECRET_KEY` | R2 secret key | Prod |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user