From d43d7ebc5e13b84c268eb7b88aa31bcce1e7f952 Mon Sep 17 00:00:00 2001 From: Stephen Adamson Date: Tue, 17 Feb 2026 22:38:22 +0000 Subject: [PATCH] readme --- README.md | 6 +- llms.txt | 243 ---------------------------- obsidian/Crussell/Crussell Nails.md | 5 +- 3 files changed, 5 insertions(+), 249 deletions(-) delete mode 100644 llms.txt diff --git a/README.md b/README.md index c7d022b..2d19eb2 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ docker compose exec backend sh | Feature | Backend | Frontend | Notes | |---------|---------|----------|-------| -| JWT Authentication | ✅ | ✅ | Login, register, middleware; HS256, 30-day expiry | +| JWT Authentication | ✅ | ✅ | Login, register, refresh, middleware; HS256, 30-day expiry, auto-refresh | | Booking CRUD | ✅ | ⚠️ | Backend complete; frontend submit is stub (logs only) | | Admin Endpoints | ✅ | ✅ | Services, users, today view, notifications | | Scheduling System | ✅ | ✅ | Default hours, exceptional hours, working/available hours | @@ -168,6 +168,7 @@ docker compose exec backend sh | Loyalty Backend | ✅ | ❌ | DB schema ready, no frontend component | | VAT System | ✅ | ❌ | `get_vat_return_data()`, `calculate_vat()` functions exist | | User Referrals | ✅ | ❌ | `user_referrals` table, backend logic exists | +| Token Refresh | ✅ | ✅ | POST /api/refresh-token, auto-refresh in auth store | ### ⚠️ Partially Complete @@ -185,7 +186,6 @@ docker compose exec backend sh | Social Auth | `handlers/auth/social.go` | OAuth integration placeholder | | Analytics | `handlers/admin/analytics.go` | Statistics/dashboard endpoint | | Portfolio Images | `handlers/portfolio/images.go` | Gallery management | -| RefreshTokenHandler | `handlers/auth/local.go:322` | Token refresh endpoint | ### 🚧 Critical TODOs @@ -203,7 +203,7 @@ docker compose exec backend sh |---------|-------------| | One-off Custom Services | Allow creating single-use services not in regular catalog | | One-off Exceptional Hours | Single-day overrides without creating a group | -| Auto Lunch Protection | Prevent booking during lunch hours automatically | +| S3/R2 Image Hosting | Portfolio image storage with admin upload | --- diff --git a/llms.txt b/llms.txt deleted file mode 100644 index e2833a8..0000000 --- a/llms.txt +++ /dev/null @@ -1,243 +0,0 @@ -# Crussell - Beauty Salon Booking System - -Stack: Go (Chi) backend | SvelteKit 5 static frontend | PostgreSQL | SabreDAV | Docker - -## Dev Startup -```bash -./local-dev-2.sh # Creates tmux session 'crussell-dev' with 3 panes: -# Pane 0: psql interactive -# Pane 1: backend (go run -tags dev ./main.go) -# Pane 2: frontend (npm run dev -- --host) -``` - -## Architecture - -``` -nginx:80/443 → static frontend build + /api/* → go:8080 → postgres:5432 + sabredav -``` - -Frontend is built static (no SSR). API calls go directly to Go backend in production. Local dev uses SvelteKit proxy for CORS. - -## Project Structure - -``` -Crussell/ -├── backend/ -│ ├── main.go # Router, all routes defined here -│ ├── auth/jwt.go # JWT init, signing -│ ├── auth/password.go # bcrypt hashing -│ ├── mw/auth.go # RequireAuth, RequireAdmin middleware -│ ├── db/db.go # Connection pooling -│ ├── db/db_dev.go # Dev-specific DB config -│ ├── handlers/ -│ │ ├── auth/local.go # Login, register, refresh-token -│ │ ├── auth/social.go # NOT WIRED -│ │ ├── bookings/ # User + admin booking CRUD -│ │ ├── admin/ # Users, analytics (analytics NOT WIRED) -│ │ ├── scheduling/ # Default + exceptional hours -│ │ ├── services/ # Service management -│ │ ├── user/ # Profile, loyalty, account -│ │ ├── notifications/ # NOT WIRED -│ │ ├── portfolio/ # NOT WIRED -│ │ └── today/ # Current/next appointments -│ └── internal/dav/ # CardDAV/CalDAV client -├── frontend/ -│ └── src/ -│ ├── routes/ -│ │ ├── admin/+page.svelte # Admin dashboard -│ │ ├── today/+page.svelte # Today view -│ │ ├── book/+page.svelte # Booking wizard -│ │ ├── login/+page.svelte # Auth -│ │ └── api/[...path]/+server.ts # Dev proxy only -│ └── lib/ -│ ├── components/ -│ │ ├── admin/ # 13 components -│ │ ├── booking/ # 8 components -│ │ └── today/ # 3 components -│ ├── stores/auth.svelte.ts # Auth state -│ └── types/booking.ts # TS interfaces -├── init-scripts/init-script.sql # Full schema + functions -├── compose.yml # Docker stack -├── nginx/conf.d/ # nginx config -├── sabredav/ # DAV server -└── local-dev-2.sh # Dev environment + seeding -``` - -## Helpful Greps - -```bash -# Find all API routes -grep -n "r\.\(Get\|Post\|Put\|Delete\|Route\)" backend/main.go - -# Find TODOs/FIXMEs in code -grep -rn "TODO\|FIXME" backend/ frontend/src/ --include="*.go" --include="*.svelte" - -# Find unwired handlers (imported in main.go?) -grep -n "import.*handlers" backend/main.go - -# Shows all three booking creation handlers: user self-booking, admin walk-in, admin call/message-in -grep -rn "func.*Create.*Booking\|func.*WalkIn\|func.*Walk.*In\|POST.*booking" backend/handlers/ --include="*.go" - -# Shows all three frontend booking flows: customer BookingFlow, admin walk-in modal, admin booking modal -grep -rln "BookingFlow\|WalkIn\|walk-in\|call.*in\|message.*in" frontend/src/lib/components/ --include="*.svelte" -F -# Find where each booking flow starts - API routes and page loads -grep -rn "booking.*create\|/api/bookings\|booking/POST\|booking/new" backend/ frontend/ --include="*.go" --include="*.ts" - -# Find all booking status handling -grep -rn "booking_status\|in_progress\|confirmed\|pending" backend/handlers/ - -# Find frontend API calls -grep -rn "fetch.*\/api\/" frontend/src/ --include="*.svelte" --include="*.ts" - -# Find auth-protected routes -grep -n "RequireAuth\|RequireAdmin" backend/main.go - -# Find Svelte 5 reactive state -grep -n "\$state\|\$derived\|\$effect" frontend/src/ -r --include="*.svelte" - -# Find SQL function definitions -grep -n "CREATE.*FUNCTION" init-scripts/init-script.sql - -# Find specific handler implementation -grep -l "func.*Handler" backend/handlers/**/*.go - -# Find transaction patterns -grep -rn "tx, err := db.DB.Begin" backend/handlers/ - -# Find refresh token handler (exists but not wired) -grep -n "RefreshTokenHandler" backend/handlers/auth/local.go - -# Find notification handler (exists but not wired) -grep -n "func.*Notification" backend/handlers/notifications/notifications.go - -# Find guest booking TODO in frontend -grep -n "TODO.*guest\|guest.*TODO" frontend/src/lib/components/admin/WalkInCreateModal.svelte - -# Find console.logs to remove -grep -rn "console\.log" frontend/src/ --include="*.svelte" | grep -v node_modules -``` - -## Auth Flow - -JWT in localStorage → decoded for role/user_id → profile fetch from `/api/user/profile`. Refresh logic exists but endpoint not wired. Roles: `unverified_email | verified_email | admin | guest | affiliate` - -**Admin promotion**: Direct SQL only, no API endpoint: `UPDATE users SET account_role = 'admin' WHERE email = '...'` - -**Validation rules**: -- Names: 1-50 chars, unicode letters/spaces/hyphen/apostrophe/dot only -- Phone: UK format, converted to E.164 (+44...) -- Email: standard format validation -- Age: Must be 16+ years old -- Login rate limit: 1 attempt per 5 seconds - -## Booking Status Flow - -``` -pending → confirmed → in_progress → completed - ↘ client_cancelled | we_cancelled | no_show | re-schedule -``` - -TODO: `in_progress` should auto-infer by time OR manual "Begin" button (gray if >3hrs away). - -## Scheduling - -- `/api/scheduling/default-hours` - Weekly template -- `/api/scheduling/exceptional-groups` - Recurring exceptions (holidays) -- `/api/scheduling/working-hours` - Merged result (default + applied exceptions) -- `/api/scheduling/available-hours` - Slots minus bookings - -All 3 booking flows (customer, call-in, walk-in) correctly use merged hours. - -## Critical TODOs - -**HIGH:** -- `BookingFlow.svelte:600` - `submitBooking()` logs only, needs `POST /api/bookings` -- `BookingCreateModal.svelte:224` - Remove `console.log(users)` debug -- `/api/users/guest` - Guest endpoint for walk-ins -- One-off custom services (single booking, no list add) -- One-off exceptional hours (single day, not recurring) -- Auto lunch protection (block if removes 1h lunch, 30min admin with warning) -- Walk-in slot blocking during intake -- Square payment integration -- GDPR export endpoint (`export_all_user_data()` SQL exists) -- Tax data export (admin, software-compatible format) - -**MEDIUM:** -- Notifications UI (frontend panel for admin notifications) -- Notifications push (WebSocket/polling mechanism) -- User notifications (booking confirmations, reminders for customers) -- Refresh token endpoint (handler exists, not wired) -- Loyalty display component -- S3/R2 for portfolio images -- Prometheus metrics -- CI/CD (Gitea) - -**NOT WIRED:** -- `handlers/auth/social.go` -- `handlers/admin/analytics.go` -- `handlers/portfolio/images.go` - -## Dev Build Tag -Backend uses `go run -tags dev ./main.go` - check for dev-specific behavior. - -## API JSON Examples - -**Booking:** `{"start_time":"2025-01-15T10:00:00+00:00","service_ids":["abc123def456"],"notes":"optional"}` - -**Service:** `{"name":"Classic Manicure","description":"...","price":25.00,"duration_minutes":45,"patch_test_duration_hours":0,"minimum_age_required":0}` - -**Confirm booking:** `POST /api/admin/bookings/{id}/confirm` with body `{"serviceOverrides":[]}` - -**Exceptional group:** `{"name":"Holiday","description":"...","hours":[{"weekday":0,"startTime":"00:00:00","endTime":"00:00:00","isOpen":false},...],"weekStarts":["2025-12-22"]}` - -## Database Enums - -```sql -account_role, account_type, booking_status, payment_type, payment_method, payment_status, admin_notification_reason -``` - -**Current `admin_notification_reason`**: `pending_booking | cancelled_booking | rescheduled_booking | 1_week_no_pay | 1_month_no_pay | affiliate_claim` - -**Suggested additions**: `no_show`, `payment_failed`, `patch_test_due`, `loyalty_milestone`, `first_time_customer`, `vip_booking`, `inactive_customer`, `birthday_this_week`, `special_request`, `schedule_conflict` - -## Key SQL Functions - -`anonymize_user()`, `export_all_user_data()`, `delete_guest_user()`, `get_vat_return_data()`, `calculate_vat()`, `get_receipt_data()` - -## Env Required - -`JWT_SECRET_KEY`, `DATABASE_URL`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB` - -## Conventions - -- IDs: 12-char generated strings (not UUIDs) -- Timezone: UK local throughout (`TZ=Europe/London`) -- Frontend: Svelte 5 runes (`$state`, `$derived`, `$effect`) -- Auth header: `Authorization: Bearer ${token}` -- All times in ISO format with timezone: `YYYY-MM-DDTHH:MM:SS±HH:MM` - -## Seed Data (local-dev-2.sh) -- 18 users (1 admin, 17 regular) -- 6 services (manicure, gel, pedicure, express, removal, nail-art) -- 45 bookings (8 past, 3 today, 4 tomorrow, 30 future spread over 15 days) -- ~50% of upcoming bookings auto-confirmed -- 2 exceptional groups (November Break, Christmas Holiday) - -## Code Patterns - -**Transaction pattern** (used throughout): -```go -tx, err := db.DB.Begin(r.Context()) -if err != nil { ... } -defer tx.Rollback(r.Context()) -// ... queries using tx instead of db.DB ... -if err := tx.Commit(r.Context()); err != nil { ... } -``` - -**CardDAV sync**: -- On registration: creates vCard in SabreDAV -- On profile update: updates existing vCard via `updateCardDAV()` helper -- Uses internal HTTP calls to DAV server - -**Role change detection**: `RefreshTokenHandler` checks if role changed since token issued - forces re-login if so. diff --git a/obsidian/Crussell/Crussell Nails.md b/obsidian/Crussell/Crussell Nails.md index 07c7e28..d597464 100644 --- a/obsidian/Crussell/Crussell Nails.md +++ b/obsidian/Crussell/Crussell Nails.md @@ -17,7 +17,7 @@ - [x] Password hashing with bcrypt - [x] Middleware for auth/roles (`mw.RequireAuth`, `mw.RequireAdmin`) - [x] DB connection pooling -- [ ] **Refresh token endpoint** - `RefreshTokenHandler` exists at `local.go:322`, NOT wired in router +- [x] Refresh token endpoint - Wired to `POST /api/refresh-token`, auto-refresh in frontend - [x] Login rate limiting (1 attempt per 5 seconds) #### Booking System @@ -333,7 +333,6 @@ admin_notification_reason: pending_booking | cancelled_booking | rescheduled_boo | **User notifications** | Notification system for regular users (booking confirmations, reminders) | | **Remove debug logs** | `console.log` in BookingFlow.svelte:600 and BookingCreateModal.svelte:224 | | **S3/R2 image hosting** | Portfolio image storage with admin upload | -| **Refresh token endpoint** | Wire existing `RefreshTokenHandler` to router | | **Loyalty display component** | Show stamps in account/bookings | | **Email/SMS reminders** | Scheduled notification jobs | | **Prometheus metrics** | Monitoring integration | @@ -556,4 +555,4 @@ if err := tx.Commit(r.Context()); err != nil { /* handle error */ } ### Build Tags - `db_dev.go` - Used with `-tags dev` for local development (localhost connection) - `db.go` - Production build (uses env var for host) -- `internal/dav/service_dev.go` / `service_prod.go` - Same pattern for DAV service \ No newline at end of file +- `internal/dav/service_dev.go` / `service_prod.go` - Same pattern for DAV service