Files
Crussell/README.md
T
popertots a5a2ffd83e Security: add rate limiting, input validation, and filter category
validation
Backend:
- Add rate limiting middleware (mw/ratelimit.go) - in-memory per-IP
  limiter
- Apply rate limits per endpoint group:
  - Public read-only: 120/min
  - Registration: 10/min
  - Portfolio filters: 60/min
  - Authenticated users: 120/min
  - Admin: none (trusted)
- Add 256 char input length validation on portfolio endpoints
- Validate filter categories exist in DB before querying
- Secure GetImage endpoint: only allow UUID or numeric timestamp (15-20
  digits)
- Remove pattern-based image lookup to prevent enumeration
- Add services validation: name (100), duration (1-480), patch test
  (0-168)
  Frontend:
- Add maxlength=256 to portfolio tag/search inputs
- Add maxlength to registration: name (50), email (255), phone (20),
  password (72)
- Add maxlength=100 to service name input
2026-02-20 12:03:14 +00:00

377 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Crussell
Crussell is a **fullstack application** that powers a nailbar / salon booking service. The repository is split into a **Go** backend and a **SvelteKit** frontend, 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 reverseproxy for HTTP & HTTPS
├─ init-scripts/ # PostgreSQL init SQL
├─ compose.yml # DockerCompose 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 & DockerCompose | ≥ 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.
```
### DockerCompose
The simplest way to bring the whole stack up is with DockerCompose.
```bash
docker compose up --build -d
```
> `postgres` PostgreSQL 17
> `backend` Go API (exposed on `:8080`)
> `sabredav` PHPbased WebDAV (served by Nginx)
> `nginx` Reverseproxy (HTTP on `:80` and HTTPS on `:443`)
After the containers are running, the frontend 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 PHPFPM and Composer. The Docker image installs dependencies automatically during the container startup.
## 📂 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 nailbar 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 |
| Portfolio System | ✅ | ✅ | S3/R2 storage abstraction, tag-based filtering, category filters, admin upload, ?img= featured image param |
### ⚠️ 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 |
### 🚧 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 |
---
## 🔄 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:**
- RequestID, RealIP, Logger, Recoverer, Timeout(15s)
- Security headers (X-Content-Type-Options, X-Frame-Options, X-XSS-Protection)
- Rate limiting (per-endpoint):
- Public read-only: 120/min
- Registration: 10/min
- Portfolio filters: 60/min
- Portfolio single image: 120/min
- Portfolio admin: 60/min
- Authenticated users: 120/min
- Admin search: 60/min
- Admin-only routes: none (trusted)
**Input Validation:**
- Backend validates all inputs against DB schema constraints
- Frontend adds maxlength attributes matching DB limits
- Registration: name (1-50), email (255), phone (20), password (72)
- Services: name (100), price (>0), duration (1-480), patch test (0-168), age (0-100)
- Portfolio: tags/filters (256 char max)
```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!**