feat(booking): add service eligibility based on age and patch tests

- Add eligibility filtering to /api/services: exclude services below
  user's
  age, gray out services requiring patch tests that are missing/expired
- Add new endpoint /api/services/eligible-for/{user_id} for admin
  booking
  flows to check eligibility for a specific user
- Add image metadata stripping: uploads now strip all EXIF/GPS data
  via imaging library (security improvement)
- Update ServiceCard frontend: show grayed-out state for ineligible
  services with "contact us" link (public) or just warning (admin)
- Add 2 patch test services to seed data: Gel Polish Full Set,
  Luxury Gel Manicure (48h each)
- Remove deprecated local-dev.sh script
This commit is contained in:
2026-02-20 18:46:38 +00:00
parent eb1a719fc3
commit 41dc839830
13 changed files with 385 additions and 1647 deletions
+15 -10
View File
@@ -6,14 +6,13 @@ Crussell is a **fullstack application** that powers a nailbar / salon book
```
Crussell/
├─ backend/ # Go 1.22 + chi router API
├─ backend/ # Go 1.25 + 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
├─ local-dev-2.sh # Development helper using tmux (seeded with 8 services incl. 2 with patch tests)
└─ README.md
```
@@ -55,13 +54,13 @@ docker compose up --build -d
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`
### Development with `local-dev-2.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.
For a more interactive dev experience the repository ships a small helper script that launches Docker, starts a tmux session with four panes (PostgreSQL console, Go dev server, Svelte dev server, Rustfs logs) and seeds the database with an admin, regular users, and sample services including patch test services.
```bash
chmod +x local-dev.sh
./local-dev.sh
chmod +x local-dev-2.sh
./local-dev-2.sh
```
The script performs the following steps:
@@ -72,7 +71,8 @@ The script performs the following steps:
* `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.
* Rustfs logs
4. **Seeding** creates admin (`admin@example.com`), regular users (`user@example.com`), 8 services (6 standard + 2 requiring patch tests), bookings, exceptional hours.
> **Note**: The script uses a temporary shell script to perform the HTTP calls, so no external tooling like `jq` is required.
@@ -117,11 +117,13 @@ Create a `.env` file in the project root based on the provided `.env.example`.
## 📊 Seeding Data
The `local-dev.sh` script automatically seeds:
The `local-dev-2.sh` script automatically seeds:
* Admin user (`admin@example.com` / `password`)
* Regular user (`user@example.com` / `password`)
* Six example nailbar services
* 8 services:
* 6 standard (no patch test)
* 2 with patch test requirement (48h) - Gel Polish Full Set, Luxury Gel Manicure
The enhanced `local-dev-2.sh` script provides additional test data including:
@@ -170,6 +172,8 @@ docker compose exec backend sh
| 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 |
| Service Eligibility | ✅ | ✅ | Age + patch test filtering; `/api/services/eligible-for/{user_id}` for admin booking flows |
| Image Metadata Stripping | ✅ | ❌ | EXIF/GPS stripped on upload via `imaging` library |
### ⚠️ Partially Complete
@@ -278,6 +282,7 @@ grep -n "r\.\(Get\|Post\|Put\|Delete\|Patch\)" backend/main.go
- ⚠️ **Gap: Rate limiter doesn't read CF-Connecting-IP** - behind Cloudflare all users share one bucket
- ⚠️ **Gap: No HSTS header** - add when HTTPS working
- ⚠️ **Gap: No Referrer-Policy** - for analytics tracking
-**Image metadata stripping** - EXIF/GPS stripped on upload (security improvement)
**Input Validation:**
- Backend validates all inputs against DB schema constraints