AI Appointment Scheduler
A full-stack, AI-powered scheduling system for a hair salon: customers book appointments through a natural-language chat interface instead of a traditional form.
What it does
Customers describe what they need in plain English (“I'd like highlights next Saturday at 2pm”) and a conversational AI agent handles the entire booking flow — checking availability, confirming details, and optionally collecting payment — all in a single chat thread.
Key engineering highlights
LangGraph ReAct agent
A tool-calling loop (check availability → book → request payment), compiled once at startup and shared across all concurrent sessions via checkpoint-keyed conversation state.
Dual request-path architecture
The agent handles customer interactions while admin reads bypass the LLM entirely for direct, low-latency service access.
Structured payment trigger
The agent emits a structured sentinel via a tool response; the backend extracts it and the frontend renders an inline payment modal — with no client-side prompt parsing.
Clean service boundary
All persistence logic lives in a single service class, making the storage layer swappable without touching the agent or the API.
Natural-language dates
With python-dateparser, the agent passes the user’s phrasing verbatim to tools rather than forcing ISO format on the customer.
Architecture
┌──────────────────────────────────────────────────────────────┐
│ BROWSER │
│ ┌────────────────────────┐ ┌────────────────────────┐ │
│ │ client-app :4200 │ │ admin-app :4201 │ │
│ │ SchedulingPrompt │ │ AppointmentList │ │
│ │ • chat UI │ │ • live table │ │
│ │ • threadId (UUID) │ │ • loading / error │ │
│ │ • payment modal │ │ │ │
│ └───────────┬────────────┘ └───────────┬────────────┘ │
└───────────────│────────────────────────────│────────────────┘
POST /chat GET /appointments
POST /appointments/{id}/pay POST /appointments/{id}/pay
│ │
┌───────────────▼────────────────────────────▼────────────────┐
│ FastAPI :8000 │
│ ┌────────────────────────┐ ┌────────────────────────┐ │
│ │ chat.py │ │ appointments.py │ │
│ │ rate limiter │ │ GET /appointments │ │
│ │ (20 req/60s/thread) │ │ GET /…/{id} │ │
│ │ │ │ │ POST /appointments │ │
│ │ ▼ │ │ POST /…/{id}/pay │ │
│ │ graph.ainvoke() │ └───────────┬────────────┘ │
│ │ scan ToolMessages │ │ │
│ │ → extract │ │ │
│ │ payment_request │ │ │
│ └───────────┬────────────┘ │ │
└───────────────│────────────────────────────│────────────────┘
▼ │
┌───────────────────────────────┐ │
│ LangGraph StateGraph │ │
│ (compiled once at startup) │ │
│ ┌─────────┐ tool_calls? │ │
│ │ agent │───────────────►│ │
│ │ node │◄───────────────│ │
│ └────┬────┘ ┌─────────┐ │ │
│ │ │ tools │ │ │
│ ▼ │ node │ │ │
│ END └────┬────┘ │ │
│ MemorySaver │ │ │
│ (thread_id key) │ │ │
└───────────────────────│───────┘ │
▼ ▼
┌──────────────────────────────────────────────────────────────┐
│ AppointmentService │
│ (single owner of all storage) │
│ check_availability │ book_appointment │ cancel │ mark_paid │
│ _store: dict[id → Appointment] │
│ (in-memory, PoC) │
└───────────────────────────────┬──────────────────────────────┘
│ (DATABASE_URL wired, not yet used)
▼
┌──────────────────┐
│ PostgreSQL │
│ port 5433 │
│ (Docker) │
└──────────────────┘The key architectural insight is the payment trigger: the agent emits a payment_request sentinel via a tool response, extracted on the backend — the frontend renders a payment modal without ever parsing the LLM’s text.
Tech stack
AI / Agent
- LangGraph (ReAct)
- LangChain
- Claude — Anthropic
- Custom agent tools
Backend
- Python
- FastAPI
- Pydantic Settings
- python-dateparser
Frontend
- Angular 21
- TypeScript
- Signals reactivity
- ngx-markdown
Infrastructure
- Docker
- PostgreSQL
Want an AI agent for your business?
Let's talk about how I can design conversational AI agents that automate your customer journeys.