# Crussell Crussell is a **full‑stack application** that powers a nail‑bar / salon booking service. The repository is split into a **Go** backend and a **SvelteKit** front‑end, both of which are containerised with Docker. A lightweight **SabreDAV** instance is also exposed so that the salon can offer WebDAV access to clients. ## 📦 Project Structure ``` Crussell/ ├─ backend/ # Go 1.22 + chi router API ├─ frontend/ # SvelteKit 5 SPA (static build) ├─ sabredav/ # PHP + Composer for DAV ├─ nginx/ # Nginx reverse‑proxy for HTTP & HTTPS ├─ init-scripts/ # PostgreSQL init SQL ├─ compose.yml # Docker‑Compose definition ├─ local-dev.sh # Development helper using tmux ├─ local-dev-2.sh # Enhanced seeding script with more test data └─ README.md ``` ## ⚙️ Prerequisites | Tool | Version | |------|---------| | Docker & Docker‑Compose | ≥ 20.10 | | Go | ≥ 1.22 | | Node | ≥ 18 (npm) | | tmux | ≥ 3.0 | > **Tip**: If you already have Docker Desktop or Docker Engine installed, you are good to go. ## 📥 Getting Started ```bash # Clone the repository git clone http://git.popertots.com/popertots/Crussell.git cd Crussell # Copy the example environment file and edit it cp .env.example .env # Open .env and provide values for POSTGRES_*, JWT_SECRET_KEY, etc. ``` ### Docker‑Compose The simplest way to bring the whole stack up is with Docker‑Compose. ```bash docker compose up --build -d ``` > `postgres` – PostgreSQL 17 > `backend` – Go API (exposed on `:8080`) > `sabredav` – PHP‑based WebDAV (served by Nginx) > `nginx` – Reverse‑proxy (HTTP on `:80` and HTTPS on `:443`) After the containers are running, the front‑end is reachable at `http://localhost`. The API is available at `http://localhost/api`. SabreDAV can be accessed via `http://localhost/dav`. ### Development with `local-dev.sh` For a more interactive dev experience the repository ships a small helper script that launches Docker, starts a tmux session with three panes (PostgreSQL console, Go dev server, Svelte dev server) and seeds the database with an admin and a regular user plus a handful of sample services. ```bash chmod +x local-dev.sh ./local-dev.sh ``` The script performs the following steps: 1. **Docker checks** – starts Docker if it isn't already running. 2. **PostgreSQL reset** – removes the old volume and starts a fresh container. 3. **tmux session** – creates `crussell-dev` with panes: * `psql` console * Go server (`go run -tags dev ./main.go`) * Svelte dev server (`npm run dev -- --host`) 4. **Seeding** – creates an admin (`admin@example.com`) and a regular user (`user@example.com`), updates the admin role, and registers six example services. > **Note**: The script uses a temporary shell script to perform the HTTP calls, so no external tooling like `jq` is required. ## 🔧 Building & Testing ### Backend ```bash cd backend # Build the binary go build -o bin/backend ./main.go ``` The binary is then copied into the Docker image via the `Dockerfile`. ### Frontend ```bash cd frontend npm ci npm run build # Production build (static) npm run dev # Development server ``` ### SabreDAV SabreDAV is bundled with PHP‑FPM and Composer. The Docker image installs dependencies automatically during the container start‑up. ## 📂 Environment Variables | Variable | Purpose | Example | |----------|---------|---------| | `POSTGRES_USER` | DB username | `myuser` | | `POSTGRES_PASSWORD` | DB password | `mysecret` | | `POSTGRES_DB` | DB name | `mydb` | | `JWT_SECRET_KEY` | HMAC key for JWT (HS256) | `supersecret` | | `SABRE_DAV_*` | Optional SabreDAV overrides | – | Create a `.env` file in the project root based on the provided `.env.example`. > **Note**: JWT tokens expire after 30 days. Login is rate-limited to 1 attempt per 5 seconds. ## 📊 Seeding Data The `local-dev.sh` script automatically seeds: * Admin user (`admin@example.com` / `password`) * Regular user (`user@example.com` / `password`) * Six example nail‑bar services The enhanced `local-dev-2.sh` script provides additional test data including: * Multiple users with different roles and account types * Working hours configurations * Exceptional working hours groups (holiday schedules) * Sample bookings with various statuses * Payment records * Admin notifications * User referrals If you want to seed manually, use the provided `init-scripts/init-script.sql` and your favourite Postgres client. ## 📌 Useful Commands ```bash # Show Docker containers docker ps # Rebuild the Go binary and restart containers make build-backend docker compose up -d backend # Tail logs docker compose logs -f # Open a shell inside the backend container docker compose exec backend sh ``` --- ## 🏗️ Implementation Status ### ✅ Complete | Feature | Backend | Frontend | Notes | |---------|---------|----------|-------| | 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 | | Holiday Hours | ✅ | ✅ | Integrated in all 3 booking flows | | 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 | Feature | Status | Details | |---------|--------|---------| | Notifications | Backend only | Admin notifications wired; acknowledgment on confirm/cancel; no frontend panel, no push (email/SMS), no regular user notifications | | User Notification Preferences | DB ready | Table `user_notification_preferences` exists; waiting on user notification system | | GDPR Compliance | DELETE only | `anonymize_user()`, `export_all_user_data()` exist but only DELETE is wired to endpoint | | Analytics | Handler exists | `handlers/admin/analytics.go` exists but NOT wired in router | ### ❌ Not Wired (Handlers Exist) | Handler | File | Notes | |---------|------|-------| | 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 | ### 🚧 Critical TODOs | Location | Issue | Priority | |----------|-------|----------| | `BookingFlow.svelte:600` | `submitBooking()` only logs, needs POST implementation | High | | `BookingCreateModal.svelte:224` | Remove `console.log(users)` debug statement | Low | | `/api/users/guest` | Guest endpoint for walk-ins not implemented | Medium | | GDPR Export | Need endpoint for `export_all_user_data()` | Medium | | Tax Export | Endpoint for VAT return data export | Medium | ### 📋 Feature Requests | Feature | Description | |---------|-------------| | One-off Custom Services | Allow creating single-use services not in regular catalog | | One-off Exceptional Hours | Single-day overrides without creating a group | | S3/R2 Image Hosting | Portfolio image storage with admin upload | --- ## 🔄 Booking Flows Crussell supports **three distinct booking flows**: | Flow | User | Entry Point | Status | |------|------|-------------|--------| | Self-Service | Customer | `BookingFlow.svelte` → `/api/bookings` | ⚠️ Stub submit | | Walk-In | Admin | Admin panel → walk-in modal | ✅ | | Call/Message-In | Admin | Admin panel → booking modal | ✅ | All three flows integrate with the **holiday/exceptional hours** system to prevent bookings during closed periods. --- ## 🔍 Helpful Greps ### All Three Booking Flows **Backend - All Booking Creation Endpoints:** ```bash grep -rn "func.*Create.*Booking\|func.*WalkIn\|func.*Walk.*In\|POST.*booking" backend/handlers/ --include="*.go" ``` **Frontend - All Booking Flow Components:** ```bash grep -rln "BookingFlow\|WalkIn\|walk-in\|call.*in\|message.*in" frontend/src/lib/components/ --include="*.svelte" ``` **Combined - Single View of All Booking Flows:** ```bash grep -rn "CreateBooking\|CreateWalkIn\|BookingFlow\|submitBooking" backend/ frontend/ --include="*.go" --include="*.svelte" ``` ### Database Schema **All Enums:** ```bash grep -n "CREATE TYPE" init-scripts/init-script.sql ``` **All Tables:** ```bash grep -n "CREATE TABLE" init-scripts/init-script.sql ``` **All Functions:** ```bash grep -n "CREATE OR REPLACE FUNCTION" init-scripts/init-script.sql ``` ### Router Endpoints **All Wired Routes:** ```bash grep -n "r\.\(Get\|Post\|Put\|Delete\|Patch\)" backend/main.go ``` **Middleware Chain:** ```bash grep -n "r\.Use\|r\.Group" backend/main.go ``` ### Authentication **JWT Middleware:** ```bash grep -rn "JWTMiddleware\|VerifyToken\|ParseToken" backend/ --include="*.go" ``` **Protected Routes:** ```bash grep -n "r\.Group.*Auth" backend/main.go ``` ### Holiday/Exceptional Hours **Usage Across All Flows:** ```bash grep -rn "exceptional.*hours\|holiday.*hours\|getExceptional\|getHoliday" backend/handlers/ frontend/src/ --include="*.go" --include="*.svelte" ``` ### Notifications **Admin Notifications:** ```bash grep -rn "admin_notifications\|AdminNotification" backend/ --include="*.go" ``` **Notification Reasons (Enum Values):** ```bash grep -A10 "admin_notification_reason" init-scripts/init-script.sql ``` ### GDPR Functions **Data Export/Anonymization:** ```bash grep -rn "anonymize_user\|export_all_user_data\|delete_guest_user" backend/ --include="*.go" init-scripts/ ``` ### Frontend Debug Artifacts **Console Logs to Remove:** ```bash grep -rn "console\.log" frontend/src/ --include="*.svelte" --include="*.ts" ``` --- ## 🗄️ Database Schema Overview ### Enums | Enum | Values | |------|--------| | `account_role` | `user`, `admin` | | `account_type` | `standard`, `vip`, `guest` | | `booking_status` | `pending`, `confirmed`, `in_progress`, `completed`, `cancelled`, `no_show` | | `payment_type` | `deposit`, `full`, `refund` | | `payment_method` | `cash`, `card`, `bank_transfer`, `square` | | `payment_status` | `pending`, `completed`, `failed`, `refunded` | | `admin_notification_reason` | `pending_booking`, `cancelled_booking`, `rescheduled_booking`, `1_week_no_pay`, `1_month_no_pay`, `affiliate_claim` | ### Key Tables | Table | Purpose | |-------|---------| | `users` | Customer and admin accounts | | `services` | Salon service catalog | | `bookings` | Appointment records | | `booking_services` | Services per booking (many-to-many) | | `payments` | Payment transactions | | `working_hours` | Default weekly schedule | | `exceptional_working_hours_groups` | Holiday/special schedules | | `admin_notifications` | Admin alerts | | `user_notification_preferences` | User notification preferences (email/sms/push) | | `user_referrals` | Referral tracking | ### Validation Rules | Field | Rules | |-------|-------| | Names | 1-50 chars, unicode letters/spaces/hyphen/apostrophe/dot | | Phone | UK format → E.164 (+44...) | | Age | Must be 16+ years | | Login Rate Limit | 1 attempt per 5 seconds | --- **Happy coding!**