From b8218669c2a1650c1ad705576edbc4626ed6cd98 Mon Sep 17 00:00:00 2001 From: mohammad Date: Mon, 2 Mar 2026 00:58:00 +0300 Subject: [PATCH] added claude.md --- CLAUDE.md | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..1f34aad --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,127 @@ +# 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//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//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`)