Backend (FastAPI + Python 3.12): - Multi-tenant auth with JWT: login, register, refresh, Meta OAuth - Business & BusinessConfig management - WhatsApp webhook with HMAC signature verification - Bot engine powered by Claude AI - Calendar availability with Redis caching - Reservations CRUD with status management - Dashboard analytics (stats, agenda, peak hours) - Billing & plan management - Admin panel with platform-wide stats - Async bcrypt via asyncio.to_thread - IntegrityError handling for concurrent registration race conditions Frontend (React 18 + Vite + Tailwind CSS): - Multi-step guided registration form with helper text on every field - Login page with show/hide password toggle - Protected routes with AuthContext - Dashboard with stats cards, bar chart, and daily agenda - Reservations list with search, filters, and inline status actions - Calendar with weekly view, slot availability, and date blocking - Config page: business info, schedules, bot personality - Billing page with plan comparison and usage bar Design system: - Bricolage Grotesque + DM Sans typography - Emerald primary palette with semantic color tokens - scale(0.97) button press feedback, ease-out animations - Skeleton loaders, stagger animations, prefers-reduced-motion support - Accessible: aria-labels, visible focus rings, 4.5:1 contrast Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Multi-tenant SaaS platform for automating WhatsApp Business reservations via an AI-powered bot. Businesses (restaurants, clinics, salons) connect their WhatsApp and a Claude-powered bot handles bookings conversationally.
Repository Structure
hermesmessages/
├── backend/ # FastAPI API — Python 3.12+
├── frontend/ # (in progress)
└── database/ # docker-compose.yml (PostgreSQL + Redis)
Tech Stack
| Layer | Technology |
|---|---|
| Language | Python 3.12+ |
| Framework | FastAPI |
| Database | PostgreSQL + SQLAlchemy (async) + Alembic |
| Cache | Redis |
| Validation | Pydantic v2 |
| Auth | JWT |
| AI | Claude API (claude-sonnet-4-20250514) |
| Testing | Pytest |
Common Commands
All backend commands run from backend/:
# Start local services
cd database && docker-compose up -d
# Install dependencies
cd backend && pip install -r requirements.txt
# Run development server
cd backend && uvicorn app.main:app --reload
# Run migrations
cd backend && alembic upgrade head
# Generate new migration
cd backend && alembic revision --autogenerate -m "description"
# Run tests
cd backend && pytest
# Run a single test file
cd backend && pytest tests/test_calendar.py
Backend Architecture
Module Structure
backend/
├── app/
│ ├── main.py
│ ├── core/ # Config & infrastructure
│ │ ├── config.py # pydantic-settings
│ │ ├── database.py # async PostgreSQL
│ │ ├── redis.py
│ │ ├── security.py # JWT, hashing
│ │ ├── dependencies.py # get_current_business, require_admin
│ │ └── errors.py # global exception handler
│ ├── modules/
│ │ ├── auth/
│ │ ├── business/
│ │ ├── whatsapp/
│ │ ├── bot_engine/
│ │ ├── calendar/
│ │ ├── reservations/
│ │ ├── notifications/
│ │ ├── dashboard/
│ │ ├── billing/
│ │ └── admin/
│ └── shared/
├── alembic/
│ └── versions/0001_initial.py
└── requirements.txt
Each module contains: router.py, service.py, models.py, schemas.py, and optionally dependencies.py.
Module Data Flow
WhatsApp webhook → Bot Engine → Calendar → Reservations → Notifications
↑
Business Config
Critical Business Logic
Multi-tenancy Rule
business_id is always extracted from the JWT token — never from the request body or path params. All queries must filter by business_id from the token. Exception: the WhatsApp webhook resolves business_id via whatsapp_phone_number_id (no JWT on webhook calls).
Availability Calculation (calendar/service.py)
- Fetch
BusinessConfigfor the business - Check if date is in
open_daysand not inblocked_dates - Generate all time slots using
open_time,close_time,slot_duration - Query confirmed+pending reservations for that day
- Filter slots where existing count <
max_per_slot - Cache result in Redis with 5-minute TTL
- Invalidate cache when a reservation is created, updated, cancelled, or deleted
WhatsApp Webhook (whatsapp/router.py)
GET /whatsapp/webhook— Meta verification (returnhub.challenge)POST /whatsapp/webhook— ValidateX-Hub-Signature-256, dispatch to bot engine viaBackgroundTasks, respond 200 immediately
Bot Engine (bot_engine/service.py)
- Load/create
ConversationContextfrom Redis (TTL: 30 min, key:conv:{business_id}:{phone}) - Build system prompt with: assistant name/tone, available slots, collected data, language instruction
- Call Claude API — response must be JSON with
action: collect_more | create_reservation | cancel - If
create_reservation→ callreservations/service.py::create_reservation, clear context - If
cancel→ clear context - Send reply via WhatsApp Graph API
- Save updated context to Redis
Key Models
- Business — tenant record with Meta/WhatsApp credentials, plan (
free|basic|pro), status (trial|active|suspended) - BusinessConfig —
open_days(list of 0-6 ints),open_time/close_time,slot_duration(minutes),max_per_slot,blocked_dates(PostgreSQL ARRAY columns) - Reservation —
status: pending|confirmed|cancelled|no_show,source: whatsapp|manual,time_endcomputed fromslot_duration - User —
role: owner|admin,meta_user_idfor Facebook OAuth
Environment Variables
Defined in backend/.env.example:
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/hermesmessages
REDIS_URL=redis://localhost:6379
SECRET_KEY=
META_APP_ID=
META_APP_SECRET=
META_WEBHOOK_VERIFY_TOKEN=
ANTHROPIC_API_KEY=
ENVIRONMENT=development|production
Access Control
- All endpoints require JWT except
GET/POST /whatsapp/webhookand/auth/* /admin/*routes requirerole: admin(enforced viarequire_admindependency)