Files
Salon/CLAUDE.md
2026-03-02 00:58:00 +03:00

128 lines
5.5 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Goal
A salon booking platform for KSA (Saudi Arabia) with Django REST API backend and React/Vite frontend. Optimized for phone-first auth (OTP via SMS/WhatsApp), Moyasar payments, Arabic locale (ar-sa), and Riyadh timezone.
## Commands
### Backend
```bash
# Setup (from repo root)
python3 -m venv venv && source venv/bin/activate
pip install -r backend/requirements.txt -r backend/requirements-dev.txt
cp backend/.env.example backend/.env
# Migrations and dev server (from backend/)
cd backend
python3 manage.py migrate
python3 manage.py runserver
# Seed demo data
python3 manage.py seed_demo
# Run all tests (from backend/ with venv active)
cd backend
python3 -m pytest
# Run a single test file
python3 -m pytest apps/accounts/tests/test_otp_limits.py
# Run a single test
python3 -m pytest apps/accounts/tests/test_otp_limits.py::TestClassName::test_method_name
# Run external/integration tests (hits real third-party services)
PYTEST_ADDOPTS='' python3 -m pytest -m external
```
### Authentica E2E Testing
Set these env vars before running external tests:
- `AUTHENTICA_E2E=1`
- `AUTHENTICA_API_KEY=...`
- `AUTHENTICA_E2E_PHONE=...` (phone that will receive OTP)
- `AUTHENTICA_E2E_CODE=...` (OTP code received)
### Frontend
```bash
# From frontend/
cd frontend
npm install
npm run dev # dev server at localhost:5173, proxies /api to localhost:8000
npm run test # vitest
npm run build
```
## Architecture
### Backend (`backend/`)
Django project lives in `backend/salon_api/` (settings, root urls, wsgi/asgi). All domain apps are under `backend/apps/`:
| App | Responsibility |
|-----|----------------|
| `accounts` | Custom User model, phone/OTP auth, JWT tokens, locale preferences |
| `salons` | Salon catalog, services, staff profiles, availability windows, reviews |
| `bookings` | Booking lifecycle, availability/overlap validation, status transitions |
| `payments` | Moyasar integration (create, capture, refund), webhook reconciliation, idempotency |
| `notifications` | Booking lifecycle SMS/WhatsApp messages, stored for auditability |
**Service layer pattern:** Business logic lives in `apps/<app>/services/` (not in views). Views are thin — they validate input, call services, return responses. Keep it this way.
**OTP providers** (`apps/accounts/services/otp.py`): pluggable via `OTP_PROVIDER` env var. Active providers: `console` (dev), `twilio`, `authentica`. `unifonic` is a scaffold. Authentica is the recommended production provider and uses a server-side OTP flow (`uses_provider_otp = True`) — it generates and verifies the code itself, so the DB stores a placeholder hash.
**Payment gateway** (`apps/payments/services/gateway.py`): `MoyasarGateway` implements `BasePaymentGateway`. Amounts are always in minor units (halalas). `MOYASAR_SECRET_KEY` and `MOYASAR_PUBLISHABLE_KEY` are required.
**Sync-only (MVP):** All external calls (OTP sends, notifications, payment gateway) run synchronously in the request path. No task queue. See `docs/adr/0001-synchronous-external-calls-mvp.md`.
**Database:** SQLite for local dev (default), PostgreSQL via `DATABASE_URL` env var for production. Tests use `TEST_DATABASE_URL` if set.
**Localization:** Default language `ar-sa`, timezone `Asia/Riyadh`. `UserLocaleMiddleware` applies per-user locale preference.
### Frontend (`frontend/`)
React 18 + Vite app. Entry: `src/main.jsx``AuthProvider` wraps `App`.
- **Routing:** `react-router-dom` v7 with pages in `src/pages/`
- **Auth:** JWT tokens managed via `src/contexts/AuthContext.jsx`; `src/components/ProtectedRoute.jsx` guards private pages
- **API:** `src/api/client.js` is the axios/fetch wrapper
- **Hooks:** Domain logic extracted into `src/hooks/` (e.g., `useSalonSearch`, `usePaymentForm`)
- **i18n:** `react-i18next` configured in `src/i18n/index.js`; supports `ar-sa` and `en`
Tests use Vitest + Testing Library. Setup in `src/test/setupTests.js`.
## Key Env Vars
Backend (`backend/.env`):
- `DJANGO_SECRET_KEY`, `DJANGO_DEBUG`, `DATABASE_URL`
- `OTP_PROVIDER``console` | `twilio` | `authentica` | `unifonic`
- `AUTHENTICA_API_KEY`, `AUTHENTICA_BASE_URL`, `AUTHENTICA_SENDER_NAME`
- `TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN`, `TWILIO_FROM_NUMBER`, `TWILIO_WHATSAPP_FROM`
- `MOYASAR_SECRET_KEY`, `MOYASAR_PUBLISHABLE_KEY`
- `NOTIFICATION_PROVIDER` — defaults to `OTP_PROVIDER`
- `OTP_EXPIRY_MINUTES`, `OTP_MAX_PER_WINDOW`, `OTP_WINDOW_MINUTES`, `OTP_RESEND_COOLDOWN_SECONDS`
- `CORS_ALLOWED_ORIGINS`
## Testing Conventions
- Backend tests live beside their apps: `apps/<app>/tests/test_*.py`
- `pytest.ini` marks `external` tests as opt-in; default runs skip them
- Frontend tests: Vitest + Testing Library; test files colocated with source (`*.test.jsx`)
- Minimum coverage: auth flows, booking validation, payment state transitions
## ExecPlans
For complex features, use an ExecPlan (see `PLANS.md` for the full spec and active plan pointer). ExecPlans are living documents in `docs/execplans/`. The active plan is listed in `PLANS.md`. Update `docs/risks.md` when opening or closing a significant gap.
## Coding Conventions
- Business logic in service layers; keep views thin
- Predictable error responses: HTTP status code + `detail` field
- Comment intent, edge cases, and non-obvious business rules; skip obvious comments
- Payment and booking flows must be idempotent and auditable
- Phone auth must be rate-limited (enforced in `otp.py` via `OtpRateLimitError` / `OtpCooldownError`)