style: fix indentation in notification preferences section and backlog table formatting
This commit is contained in:
@@ -33,45 +33,45 @@ No external dependencies. No paid services. No API keys needed.
|
||||
|
||||
## P2 — Medium
|
||||
|
||||
| # | Gap | Effort | Area | Notes |
|
||||
|---|-----|--------|------|-------|
|
||||
| 14 | ~~`delete_guest_user()` SQL function missing~~ ✅ | S (1h) | DB | Created next to `anonymize_user()` in init-script.sql. Called by `DeleteAccountHandler` for guest users. |
|
||||
| ~~15~~ | ~~**User notification preferences UI**~~ ✅ | ~~S (2-3h)~~ | ~~Frontend~~ | ~~DB table `user_notification_preferences` exists with email/sms/push flags. No settings page to toggle them.~~ GET/PUT endpoints wired. Toggle section in /account Admin tab. Email, SMS, Browser push channels. Auto-save on toggle. |
|
||||
| 16 | **One-off custom services** | M (1-2d) | Full-stack | Admin can't create single-use services outside the catalog. Every custom job (bridal party, special request) must be added to permanent service list. |
|
||||
| 17 | **One-off exceptional hours** | M (1d) | Full-stack | Single-day overrides (dentist appointment, afternoon off) require creating a full exceptional group. Should support one-off date blocks without group overhead. |
|
||||
| 18 | ~~**HSTS header**~~ ✅ | XS (15min) | Backend | Added as a TODO-comment in the security headers middleware. Will be uncommented when HTTPS is enabled in production. |
|
||||
| 19 | ~~**Referrer-Policy header**~~ ✅ | XS (15min) | Backend | Added as a TODO-comment in the security headers middleware. Will be uncommented when ready for production. |
|
||||
| 20 | **Business settings management UI** | M (1-2d) | Full-stack | `business_settings` table exists (VAT registration, business name, etc.). No admin page to configure. Changes require direct SQL. |
|
||||
| 21 | **Referral system UI** | M (1-2d) | Full-stack | `user_referrals` table exists. Users can't see their referral code or track uses. Admin can't manage referral campaigns. |
|
||||
| 22 | **Analytics endpoints** | M (1-2d) | Backend | `handlers/admin/analytics.go` is 1 line. `get_monthly_business_summary()`, `get_sales_totals()` SQL functions exist. No admin dashboard stats. |
|
||||
| 23 | ~~**console.log debug statements**~~ ✅ | XS (15min) | Frontend | Removed from BookingFlow.svelte and ImageUpload.svelte. |
|
||||
| 24 | ~~**Alert-based prototype UX**~~ ✅ | XS (30min) | Frontend | Replaced all `alert()` calls with `toast.success/error/info` from svelte-sonner. |
|
||||
| ~~25~~ | ~~**No customer relationship view**~~ ✅ | M (1-2d) | Frontend | **Implemented May 2026.** New `GET /api/admin/users/{id}/relationship` endpoint returns: total spend (from completed payments), total visits, first/last visit dates, avg visits/month, top 5 most booked services, notes history. New `user_notes_history` table tracks note changes. UserModal shows "Customer Relationship" section between Loyalty & Referrals and Privacy & Consent. |
|
||||
| 26 | **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 as CSV. |
|
||||
| 27 | ~~**Graceful shutdown**~~ ✅ | S (1h) | Backend | Added signal handling for SIGTERM/SIGINT with 15-second shutdown timeout in main.go. |
|
||||
| 28 | ~~**Health check endpoint**~~ ✅ | XS (15min) | Backend | Added `GET /api/health` returning overall status plus DB, S3, Square, and frontend service statuses. |
|
||||
| 29 | **API documentation** | M (1-2d) | Backend | No OpenAPI/Swagger spec. No generated docs. New developers must read code to understand endpoints. |
|
||||
| 30 | **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. |
|
||||
| 31 | **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. |
|
||||
| 32 | **CSRF protection** | S (2-3h) | Backend | SvelteKit handles some CSRF for its own forms, but direct API calls to `/api/*` bypass it. Consider double-submit cookie or SameSite cookies. |
|
||||
| 33 | **Begin button (Today page)** | S (2-3h) | Full-stack | Manual start for early arrivals. Gray out if >3hrs away. Currently auto-infer only. |
|
||||
| 34 | **Auto lunch protection** | M (1d) | Backend | Block bookings that remove lunch break. 1h customer auto-block, 30min admin with warning. |
|
||||
| 35 | ~~**Walk-in slot blocking**~~ ✅ | S (1-2h) | Frontend | **Resolved May 2026.** `WalkInBooking.svelte` reserves slot via `POST /api/admin/bookings/reserve` (15-min TTL) before opening `WalkInCreateModal`. Backend `AdminReserveSlotHandler` creates `time_blocker` entry with `RESERVATION:admin:walkin:*` description, blocking concurrent bookings. Minor gap: reservation time_blocker not deleted after booking creation (relies on TTL expiry via `CleanupOldReservations`). |
|
||||
| ~~36~~ | ~~**No idempotency keys for bookings**~~ ✅ | S (2-3h) | Full-stack | **Implemented May 2026.** `idempotency_key VARCHAR(64) UNIQUE` column added to bookings table. Both `POST /api/bookings` and `POST /api/admin/bookings` extract `Idempotency-Key` header, check for existing booking with that key, return existing booking with 200 if found (no duplicate). Frontend BookingFlow.svelte and WalkInCreateModal.svelte generate UUID via `crypto.randomUUID()`, reuse same key on retry. |
|
||||
| 37 | **No booking conflict detection for users** | S (2-3h) | Backend | Users can theoretically double-book themselves if they open two tabs. Reservation system helps but doesn't fully prevent. |
|
||||
| 38 | **Service category/tag management** | M (1-2d) | Full-stack | Services have no category field. Hard to organize (manicure vs pedicure vs nail art). Admin must scroll through flat list. |
|
||||
| 39 | ~~**No customer-facing cancellation policy display**~~ ✅ | XS (30min) | Frontend | Added cancellation policy text block in BookingFlow Step 3 below the terms & conditions line. |
|
||||
| 40 | **No no-show tracking dashboard** | S (2-3h) | Frontend | Admin can't see which users have accumulated no-shows. `forgiven_no_shows` table exists but no UI. |
|
||||
| 41 | ~~**No timezone handling for international customers**~~ ✅ | XS (15min) | Frontend | **Intentionally not implemented.** Crussell is UK-only; Cloudflare blocks non-UK traffic. Added explanatory comments in BookingFlow.svelte and README.md so this stops being flagged. |
|
||||
| 42 | **Dark mode** | M (1-2d) | Frontend | SvelteKit + Tailwind supports it easily. No dark mode toggle or `prefers-color-scheme` support. |
|
||||
| 43 | **PWA support** | L (3-5d) | Frontend | No service worker, no manifest.json, no offline support. Customers can't "install" the booking app. |
|
||||
| 44 | **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. |
|
||||
| 45 | **Loyalty stamp redemption + discount system** | XL (5-7d) | Full-stack | **Plan written** (`.sisyphus/plans/45-loyalty-discount-system.md`). **Design:** (1) Auto-redeem: when stamps hit 10, create pending `loyalty_redemption`. (2) Discount applied at booking *completion* (not creation) — avoids cancellation edge cases. (3) 10% loyalty discount creates `discount` payment_method record, deducts 10 stamps. (4) Campaign system: `discount_campaigns` table for time-based sales (Easter 5% off, opening week 10% off first appointment). (5) Customer UI shows "next completed appointment gets 10% off" — NO exact prices. (6) Email notification TODO where SMTP will go. (7) `booking_discounts` table tracks all discounts applied. Priority: loyalty > campaign, one discount per booking. DB: 3 new tables + 2 new enums + 1 column alter. |
|
||||
| ~~46~~ | ~~**Staff management**~~ 🗑️ | — | — | Removed — single employee sole trader business, no multi-staff needed. |
|
||||
| 47 | **Recurring bookings** | L (3-5d) | Full-stack | Customers can't book the same slot weekly/monthly. Would need a `recurring_bookings` table + background job to materialize instances. |
|
||||
| ~~48~~ | ~~**Waitlist functionality**~~ 🗑️ | — | — | Removed — not desired for this business. |
|
||||
| ~~49~~ | ~~**Image optimization for portfolio**~~ ✅ | XS (30min) | Frontend | **Complete May 2026.** AVIF full-size (0.72 quality, 1500px max), WebP thumbnails (250x250), lazy loading all implemented. No srcset/picture needed — business decision. |
|
||||
| ~~51~~ | ~~**Test DB optimization**~~ ✅ | M (1d) | Backend | **Complete May 2026.** TestMain per package (schema migration runs once per package, not per test). Per-test setup changed to TRUNCATE-only (~60% faster). 3 missing tables added to TruncateTables. discount_test.go moved to package bookings. Dead code removed. Flaky time-of-day tests fixed. Test output streamed in real-time via tee in local-dev-2.sh. **286/288 tests passing** (was 222/224). |
|
||||
| # | Gap | Effort | Area | Notes |
|
||||
| ------ | ---------------------------------------------------------- | ------------ | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 14 | ~~`delete_guest_user()` SQL function missing~~ ✅ | S (1h) | DB | Created next to `anonymize_user()` in init-script.sql. Called by `DeleteAccountHandler` for guest users. |
|
||||
| ~~15~~ | ~~**User notification preferences UI**~~ ✅ | ~~S (2-3h)~~ | ~~Frontend~~ | ~~DB table `user_notification_preferences` exists with email/sms/push flags. No settings page to toggle them.~~ GET/PUT endpoints wired. Toggle section in /account Admin tab. Email, SMS, Browser push channels. Auto-save on toggle. |
|
||||
| 16 | **One-off custom services** | M (1-2d) | Full-stack | Admin can't create single-use services outside the catalog. Every custom job (bridal party, special request) must be added to permanent service list. |
|
||||
| 17 | **One-off exceptional hours** | M (1d) | Full-stack | Single-day overrides (dentist appointment, afternoon off) require creating a full exceptional group. Should support one-off date blocks without group overhead. |
|
||||
| 18 | ~~**HSTS header**~~ ✅ | XS (15min) | Backend | Added as a TODO-comment in the security headers middleware. Will be uncommented when HTTPS is enabled in production. |
|
||||
| 19 | ~~**Referrer-Policy header**~~ ✅ | XS (15min) | Backend | Added as a TODO-comment in the security headers middleware. Will be uncommented when ready for production. |
|
||||
| 20 | **Business settings management UI** | M (1-2d) | Full-stack | `business_settings` table exists (VAT registration, business name, etc.). No admin page to configure. Changes require direct SQL. |
|
||||
| 21 | **Referral system UI** | M (1-2d) | Full-stack | `user_referrals` table exists. Users can't see their referral code or track uses. Admin can't manage referral campaigns. |
|
||||
| 22 | **Analytics endpoints** | M (1-2d) | Backend | `handlers/admin/analytics.go` is 1 line. `get_monthly_business_summary()`, `get_sales_totals()` SQL functions exist. No admin dashboard stats. |
|
||||
| 23 | ~~**console.log debug statements**~~ ✅ | XS (15min) | Frontend | Removed from BookingFlow.svelte and ImageUpload.svelte. |
|
||||
| 24 | ~~**Alert-based prototype UX**~~ ✅ | XS (30min) | Frontend | Replaced all `alert()` calls with `toast.success/error/info` from svelte-sonner. |
|
||||
| ~~25~~ | ~~**No customer relationship view**~~ ✅ | M (1-2d) | Frontend | **Implemented May 2026.** New `GET /api/admin/users/{id}/relationship` endpoint returns: total spend (from completed payments), total visits, first/last visit dates, avg visits/month, top 5 most booked services, notes history. New `user_notes_history` table tracks note changes. UserModal shows "Customer Relationship" section between Loyalty & Referrals and Privacy & Consent. |
|
||||
| 26 | **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 as CSV. |
|
||||
| 27 | ~~**Graceful shutdown**~~ ✅ | S (1h) | Backend | Added signal handling for SIGTERM/SIGINT with 15-second shutdown timeout in main.go. |
|
||||
| 28 | ~~**Health check endpoint**~~ ✅ | XS (15min) | Backend | Added `GET /api/health` returning overall status plus DB, S3, Square, and frontend service statuses. |
|
||||
| 29 | **API documentation** | M (1-2d) | Backend | No OpenAPI/Swagger spec. No generated docs. New developers must read code to understand endpoints. |
|
||||
| 30 | **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. |
|
||||
| 31 | **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. |
|
||||
| 32 | **CSRF protection** | S (2-3h) | Backend | SvelteKit handles some CSRF for its own forms, but direct API calls to `/api/*` bypass it. Consider double-submit cookie or SameSite cookies. |
|
||||
| 33 | **Begin button (Today page)** | S (2-3h) | Full-stack | Manual start for early arrivals. Gray out if >3hrs away. Currently auto-infer only. |
|
||||
| 34 | **Auto lunch protection** | M (1d) | Backend | Block bookings that remove lunch break. 1h customer auto-block, 30min admin with warning. |
|
||||
| 35 | ~~**Walk-in slot blocking**~~ ✅ | S (1-2h) | Frontend | **Resolved May 2026.** `WalkInBooking.svelte` reserves slot via `POST /api/admin/bookings/reserve` (15-min TTL) before opening `WalkInCreateModal`. Backend `AdminReserveSlotHandler` creates `time_blocker` entry with `RESERVATION:admin:walkin:*` description, blocking concurrent bookings. Minor gap: reservation time_blocker not deleted after booking creation (relies on TTL expiry via `CleanupOldReservations`). |
|
||||
| ~~36~~ | ~~**No idempotency keys for bookings**~~ ✅ | S (2-3h) | Full-stack | **Implemented May 2026.** `idempotency_key VARCHAR(64) UNIQUE` column added to bookings table. Both `POST /api/bookings` and `POST /api/admin/bookings` extract `Idempotency-Key` header, check for existing booking with that key, return existing booking with 200 if found (no duplicate). Frontend BookingFlow.svelte and WalkInCreateModal.svelte generate UUID via `crypto.randomUUID()`, reuse same key on retry. |
|
||||
| 37 | **No booking conflict detection for users** | S (2-3h) | Backend | Users can theoretically double-book themselves if they open two tabs. Reservation system helps but doesn't fully prevent. |
|
||||
| 38 | **Service category/tag management** | M (1-2d) | Full-stack | Services have no category field. Hard to organize (manicure vs pedicure vs nail art). Admin must scroll through flat list. |
|
||||
| 39 | ~~**No customer-facing cancellation policy display**~~ ✅ | XS (30min) | Frontend | Added cancellation policy text block in BookingFlow Step 3 below the terms & conditions line. |
|
||||
| 40 | **No no-show tracking dashboard** | S (2-3h) | Frontend | Admin can't see which users have accumulated no-shows. `forgiven_no_shows` table exists but no UI. |
|
||||
| 41 | ~~**No timezone handling for international customers**~~ ✅ | XS (15min) | Frontend | **Intentionally not implemented.** Crussell is UK-only; Cloudflare blocks non-UK traffic. Added explanatory comments in BookingFlow.svelte and README.md so this stops being flagged. |
|
||||
| 42 | **Dark mode** | M (1-2d) | Frontend | SvelteKit + Tailwind supports it easily. No dark mode toggle or `prefers-color-scheme` support. |
|
||||
| 43 | **PWA support** | L (3-5d) | Frontend | No service worker, no manifest.json, no offline support. Customers can't "install" the booking app. |
|
||||
| 44 | **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. |
|
||||
| 45 | **Loyalty stamp redemption + discount system** | XL (5-7d) | Full-stack | **Plan written** (`.sisyphus/plans/45-loyalty-discount-system.md`). **Design:** (1) Auto-redeem: when stamps hit 10, create pending `loyalty_redemption`. (2) Discount applied at booking *completion* (not creation) — avoids cancellation edge cases. (3) 10% loyalty discount creates `discount` payment_method record, deducts 10 stamps. (4) Campaign system: `discount_campaigns` table for time-based sales (Easter 5% off, opening week 10% off first appointment). (5) Customer UI shows "next completed appointment gets 10% off" — NO exact prices. (6) Email notification TODO where SMTP will go. (7) `booking_discounts` table tracks all discounts applied. Priority: loyalty > campaign, one discount per booking. DB: 3 new tables + 2 new enums + 1 column alter. |
|
||||
| ~~46~~ | ~~**Staff management**~~ 🗑️ | — | — | Removed — single employee sole trader business, no multi-staff needed. |
|
||||
| 47 | **Recurring bookings** | L (3-5d) | Full-stack | Customers can't book the same slot weekly/monthly. Would need a `recurring_bookings` table + background job to materialize instances. |
|
||||
| ~~48~~ | ~~**Waitlist functionality**~~ 🗑️ | — | — | Removed — not desired for this business. |
|
||||
| ~~49~~ | ~~**Image optimization for portfolio**~~ ✅ | XS (30min) | Frontend | **Complete May 2026.** AVIF full-size (0.72 quality, 1500px max), WebP thumbnails (250x250), lazy loading all implemented. No srcset/picture needed — business decision. |
|
||||
| ~~51~~ | ~~**Test DB optimization**~~ ✅ | M (1d) | Backend | **Complete May 2026.** TestMain per package (schema migration runs once per package, not per test). Per-test setup changed to TRUNCATE-only (~60% faster). 3 missing tables added to TruncateTables. discount_test.go moved to package bookings. Dead code removed. Flaky time-of-day tests fixed. Test output streamed in real-time via tee in local-dev-2.sh. **286/288 tests passing** (was 222/224). |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user