# Future Work — Gap Backlog

**Last Updated:** June 2026
**Status:** Living backlog — add to this as gaps are discovered

This document is two lists: **MVP** (must do before launch) and **Stretch** (nice-to-have after launch). Items are numbered sequentially. All done items are removed — not crossed out, not tracked. If you need to know what was done, check the git history.

---

## MVP — Must Do Before Launch

These are blockers: missing functionality that prevents daily operations, legal compliance, or basic security. No external dependencies. Each is local, can be implemented today.

| # | Gap | Effort | Area | Notes |
|---|---|---|---|---|
| 1 | **CurrentAppointment action stubs** | M (1d) | Frontend | `Extend` and `Cancel` buttons on Today page are dead. Staff cannot cancel or extend an in-progress appointment from the Today page. Edit, Take Payment, and Reschedule are already wired. |
| 2 | **~~Reservation/cleanup background cron~~** | S (3h) | Backend | **DONE**: All cleanup functions migrated to `backend/internal/jobs/` — centralised cron scheduler. 20 jobs registered with staggered schedules: cleanup-reservations (5min), cleanup-expired-deposits (5min), cleanup-rate-limiters (5min), cleanup-gdpr-export-cache (5min), cleanup-progressive-rate-limiter (1min), cleanup-expired-loyalty-redemptions (hourly), cleanup-old-idempotency-keys (hourly), cleanup-revoked-jtis (hourly), cleanup-stale-login-entries (hourly), transition-discount-campaigns (hourly), notify-unpaid-1-week (7am daily), notify-unpaid-1-month (7am daily), cleanup-verification-codes (2am daily), cleanup-refresh-tokens (2am daily), anonymize-stale-guest-accounts (3am daily), cleanup-idle-accounts (3:30am daily), cleanup-expired-financial-records (4am daily), cleanup-old-name-history (4:30am daily), cleanup-expired-gift-cards (5am daily). |
| 3 | **VAT/Tax export endpoints** | M (1-2d) | Backend | `get_vat_return_data()` and `export_sales_transactions()` SQL functions exist. No admin API to trigger them. Needed for HMRC Making Tax Digital compliance. |
| 4 | **Password reset flow** | S (2-3h) | Frontend | Backend has `/api/verify/generate` and `/api/verify/check`. Login page has no "forgot password" link or form. Customers who forget their password must call the salon. |
| 5 | **Email verification flow** | S (2-3h) | Frontend | Users register with `unverified_email` role. No UI to enter verification code or resend. `+layout.svelte` has an alert-based prototype that needs to be wired properly. |
| 6 | **Booking cancellation from user account** | S (2-3h) | Frontend | `UserBookingModal` shows booking details but no cancel button. Users must call/email to cancel. Backend endpoint `DELETE /api/bookings/{id}` exists. |
| 7 | **Business settings management UI** | M (1-2d) | Frontend | `GET/PUT /api/admin/settings` backend endpoints exist (VAT, business name, gift card expiry months, voucher type SPV/MPV). No admin page. Staff must use `curl` or direct SQL. |
| 8 | **CSV/Excel export for bookings/payments** | M (1d) | Backend | Admin can't export data for accounting software. SQL functions exist but no endpoint to download CSV. |
| 9 | **XSS input sanitization** | S (2-3h) | Backend | Backend validates format (regex, length) but doesn't sanitize HTML entities. Stored XSS risk in `notes`, `name`, `description` fields. **Partially addressed June 2026:** toast.error() messages now escape HTML. `{@html statusBadge()` replaced with proper component. ICS injection sanitized. Error messages no longer reflect user input. CSP header added. Remaining: backend-level HTML sanitization of stored fields. |
| 10 | **CSRF protection** | S (2-3h) | Backend | SvelteKit handles CSRF for its own forms, but direct API calls to `/api/*` bypass it. Consider double-submit cookie or SameSite cookies. |
| 11 | **Automated database backups** | M (1d) | Infrastructure | No backup strategy. PostgreSQL volume is persistent but no automated dumps, no point-in-time recovery. Can use `pg_dump` cron on the host — no external service needed. |
| 12 | **Square webhook production verification** | S (2-3h) | Backend | Current handler skips signature check if `SQUARE_WEBHOOK_SIGNATURE_KEY` is empty. Production must ALWAYS verify. See `TODO(PROD)` in `handlers/webhooks/square.go` for detailed implementation guide including Go SDK usage, base64 HMAC-SHA256, and notification URL matching. |

### External MVP (Requires Third-Party Access)

| # | Gap | Effort | Area | Blocked On | Notes |
|---|---|---|---|---|---|
| E5 | **Email/SMS notification system** | XL (5-7d) | Backend | SMTP provider (Resend, SendGrid, Twilio) | `user_notification_preferences` table exists but no delivery system. Blocks: booking reminders, password reset emails, deposit reduction notifications. |
| E8 | **S3/R2 production storage** | M (1d) | Backend | Cloudflare R2 or AWS S3 credentials | `s3.go` (`!dev` build tag) returns "not implemented". Prod builds cannot store portfolio images. Need AWS SDK v2 + credentials. |

---

## Stretch — Post-Launch

These improve the experience or add features, but the business can operate without them.

| #   | Gap                                      | Effort   | Area       | Notes                                                                                                                                                                                                                        |
| --- | ---------------------------------------- | -------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 12  | **One-off custom services**              | M (1-2d) | Full-stack | Admin can't create single-use services. Every custom job (bridal party, special request) must be added to the permanent catalog.                                                                                             |
| 13  | **One-off exceptional hours**            | M (1d)   | Full-stack | Single-day overrides (dentist appointment, afternoon off) require creating a full exceptional group. Time blockers handle unavailable periods; one-off *open* hours (e.g., "open Sunday 2pm-5pm") still need simplification. |
| 14  | **Referral system UI**                   | M (1-2d) | Full-stack | Backend complete — registration validates codes, relationships recorded. Users can't see their referral code or track uses. Admin can't manage referral campaigns.                                                           |
| 15  | **Analytics endpoints**                  | M (1-2d) | Backend    | `handlers/admin/analytics.go` is 1 line. `get_monthly_business_summary()`, `get_sales_totals()` SQL functions exist but not wired.                                                                                           |
| 16  | **API documentation**                    | M (1-2d) | Backend    | No OpenAPI/Swagger spec. No generated docs. New developers must read code.                                                                                                                                                   |
| 17 | **Per-user rate limiting** | M (1d) | Backend | Rate limiter is IP-based. Authenticated users could abuse from multiple IPs. Should track by user ID + IP. Pure Go — no Redis needed for single-instance. **Partially addressed June 2026:** L3 ProgressiveRateLimit added for login/register (per-IP dual-window: 30 req/5s burst + 120 req/60s sustained). Account lockout added (5+ failures → progressive 15min→2h). Remaining: user-ID tracking for authenticated endpoints. |
| 18  | **Begin button (Today page)**            | S (2-3h) | Full-stack | Manual start for early arrivals. Currently auto-inferred only. Gray out if >3 hours away.                                                                                                                                    |
| 19  | **Booking conflict detection for users** | S (2-3h) | Backend    | Users can theoretically double-book themselves in two tabs. Reservation system helps but doesn't fully prevent.                                                                                                              |
| 20  | **Service category/tag management**      | M (1-2d) | Full-stack | Services have no category field. Admin scrolls through a flat list. No way to group (manicure vs pedicure vs nail art).                                                                                                      |
| 21  | **No-show tracking dashboard**           | S (2-3h) | Frontend   | `forgiven_no_shows` table exists but no UI. Admin can't see which users have accumulated no-shows.                                                                                                                           |
| 22  | **Dark mode**                            | M (1-2d) | Frontend   | SvelteKit + Tailwind supports it. No toggle or `prefers-color-scheme` support.                                                                                                                                               |
| 23  | **PWA support**                          | L (3-5d) | Frontend   | No service worker, no manifest.json, no offline support. Customers can't "install" the app.                                                                                                                                  |
| 24  | **Recurring bookings**                   | L (3-5d) | Full-stack | Customers can't book the same slot weekly/monthly. Would need `recurring_bookings` table + background job.                                                                                                                   |
| 25  | **Idempotency key cleanup**              | S (1h)   | Backend    | `idempotency_key` columns added to `bookings`, `payments`, `till_sales` with unique constraints. No retention policy — keys accumulate indefinitely.                                                                         |
| 26  | **Gift card self-service portal**        | M (1d)   | Frontend   | Users can see gift card balance on Account page but can't independently redeem to balance without admin.                                                                                                                     |

### External Stretch (Requires Third-Party Access)

| # | Gap | Effort | Area | Blocked On | Notes |
|---|---|---|---|---|---|
| E9 | **Social auth (Google/Microsoft/Facebook)** | L (2-3d) | Backend | OAuth app registrations + client secrets | `handlers/auth/social.go` is 1 line. |
| E10 | **Error tracking / monitoring** | M (1-2d) | Backend | Sentry DSN or equivalent | `log.Printf()` only. No alerting on 5xx. |

---

## Dependency Map

```
E5 Email/SMS → E6 deposit reduction notifications
             → booking reminders
             → password reset emails

E8 S3/R2 → portfolio images in production
E9 OAuth → social login flow
E10 Sentry → error tracking, 5xx alerting
```

All local (MVP + Stretch) items have zero external dependencies.
