Skip to content

Repository files navigation

Kiro AppointBot - AI-Powered Appointment Booking via Messenger

Solving a boring, but impactful, real-world problem: Appointment booking is tedious for small businesses and frustrating for customers. This project automates the entire flow using emerging AI agent technology, deployed where customers already are—Facebook Messenger (3+ billion users).

The Real-World Problem

Small businesses—salons, clinics, repair shops—spend hours each week on repetitive appointment scheduling via messaging apps. Customers send fragmented messages ("I need a haircut", then later "maybe Tuesday?", then "actually 3pm works"). Staff manually extract details, check calendars, and confirm—all while juggling other work.

This is exactly the kind of boring, high-volume task where AI agents excel.

Why This Matters

Challenge Traditional Approach Kiro AppointBot
Cross-platform reach Build separate apps for each platform Deploy once on Messenger, reach 3B+ users
Fragmented conversations Manual extraction from chat history AI agent extracts structured data across messages
Calendar coordination Copy-paste between apps Direct Google Calendar integration
Quality improvement Hope the AI gets better Extract real customer conversations as eval cases

The Eval Case Extraction Advantage

Most AI agents are tested with synthetic data. Kiro AppointBot takes a different approach: extract real customer conversations as evaluation cases. The admin dashboard lets you:

  1. Select actual messages from real conversations
  2. Export them as structured test cases
  3. Build a corpus of edge cases your AI encountered in production
  4. Continuously improve agent accuracy using ground truth from your own customers

This creates a flywheel: more conversations → more eval cases → better agents → happier customers → more conversations.


FastAPI application using LangGraph for stateful multi-agent workflows and Pydantic AI for structured outputs. Includes a React admin dashboard for monitoring conversations and extracting evaluation cases. Built with Vertical Slice Architecture, dual-layer type checking (MyPy + Pyright), and comprehensive observability.

Prerequisites

  • Python 3.12+
  • Node.js 20+ (for admin dashboard frontend)
  • PostgreSQL 14+ (Supabase recommended)
  • uv package manager
  • Facebook Page with Messenger enabled
  • Facebook App with Messenger product configured

Quick Start

  1. Clone and setup

    git clone <repository-url>
    cd kiro-appointbot
    uv sync
  2. Configure environment

    cp .env.example .env
    # Edit .env with your Facebook and database credentials
  3. Initialize database

    uv run alembic upgrade head
  4. Run the application

    uv run uvicorn app.main:app --reload --port 8000
  5. Configure Facebook webhook

    • Callback URL: https://your-domain.com/webhook
    • Verify Token: (from FACEBOOK_VERIFY_TOKEN in .env)
    • Subscribe to: messages, messaging_postbacks
    • For local dev: Use ngrok (ngrok http 8000)
  6. Start the admin dashboard (optional)

    cd frontend
    npm install
    npm run dev
  7. Access the application

Architecture & Codebase Overview

System Architecture

Technology Stack:

  • Backend: FastAPI with async support
  • Frontend: React 19 + TypeScript + Tailwind CSS 4
  • Database: PostgreSQL (Supabase) with SQLAlchemy 2.0+
  • AI Agents: Pydantic AI + LangGraph for stateful workflows
  • Type Checking: MyPy + Pyright (backend), TypeScript strict (frontend)
  • Code Quality: Ruff (backend), ESLint (frontend)
  • Testing: Pytest with async support
  • Logging: Structured JSON logs with correlation IDs

Directory Structure

app/
├── core/                    # Universal infrastructure
│   ├── config.py           # Application configuration
│   ├── database.py         # Database connection & session
│   ├── logging.py          # Structured logging setup
│   └── middleware.py       # Request/response middleware
├── shared/                  # Cross-feature utilities
│   └── models.py           # Base models (TimestampMixin)
├── messenger/               # Facebook Messenger feature slice
│   ├── routes.py           # Webhook and API endpoints
│   ├── service.py          # Business logic
│   ├── repository.py       # Database operations
│   ├── models.py           # SQLAlchemy models
│   ├── schemas.py          # Pydantic schemas
│   └── tests/              # Feature tests
├── info_gatherer/           # AI appointment booking feature
│   ├── orchestrator.py     # Workflow lifecycle management
│   ├── agents.py           # Pydantic AI agents
│   ├── repository.py       # State persistence
│   ├── models.py           # Appointment models
│   ├── calendar_client.py  # Google Calendar integration
│   ├── langfuse_client.py  # LLM observability
│   ├── graph/              # LangGraph workflow
│   │   ├── state.py        # Workflow state definition
│   │   ├── nodes.py        # Workflow nodes
│   │   ├── routing.py      # Conditional routing
│   │   └── workflow.py     # Graph assembly
│   └── tests/              # Feature tests
└── admin_dashboard/         # Admin monitoring & eval extraction
    ├── routes.py           # REST + SSE endpoints
    ├── service.py          # Eval case generation
    ├── repository.py       # Cross-feature queries
    ├── schemas.py          # API schemas
    ├── auth.py             # JWT authentication
    ├── sse.py              # Server-Sent Events
    └── tests/              # Feature tests

frontend/                    # React admin dashboard
├── src/
│   ├── api/                # API client & SSE handlers
│   ├── components/         # UI components
│   │   ├── ConversationList/  # Conversation sidebar
│   │   ├── ChatView/          # Message viewer
│   │   └── EvalPanel/         # Eval case builder
│   ├── contexts/           # React contexts (auth, selection)
│   ├── hooks/              # Custom hooks (SSE, data fetching)
│   ├── pages/              # Page components
│   └── types/              # TypeScript types
└── package.json

Key Components

  • Vertical Slice Architecture: Each feature owns its routes, services, repositories, and models
  • Core Infrastructure (app/core/): Database, logging, config, middleware shared by all features
  • Feature Slices: Self-contained business domains
    • app/messenger/: Facebook Messenger webhook and message storage
    • app/info_gatherer/: AI-powered appointment booking workflow
    • app/admin_dashboard/: Monitoring dashboard and eval case extraction
  • Frontend (frontend/): React SPA for admin monitoring and eval case building

API Endpoints

Messenger (Public)

Endpoint Method Description
/webhook GET Facebook webhook verification
/webhook POST Receive Messenger events
/health GET System health and statistics

Admin Dashboard (Authenticated)

Endpoint Method Description
/api/admin/auth/login POST Authenticate with admin password
/api/admin/conversations GET List conversations with filters
/api/admin/conversations/{psid} GET Get conversation details
/api/admin/conversations/{psid}/messages GET Get messages for conversation
/api/admin/export/eval-case POST Export selected messages as eval case
/api/admin/sse/conversations GET SSE stream for conversation updates
/api/admin/sse/messages/{psid} GET SSE stream for message updates

Deep Dive

Admin Dashboard

React-based monitoring interface for viewing conversations and extracting evaluation cases for AI agent testing.

Features:

  • Real-time conversation list with search and status filters
  • Message viewer with customer/page message distinction
  • Eval case builder for AI agent testing
  • JWT-based authentication
  • Server-Sent Events (SSE) for live updates

Eval Case Extraction:

The Eval Panel allows selecting messages from a conversation to create evaluation test cases for the AI agents:

  1. Select Messages: Click messages in the chat view to select (1-20 messages)
  2. Choose Agent Type: Select target agent (Extraction, Confirmation, or Response)
  3. Configure Options:
    • Include context messages (preceding conversation)
    • Include workflow state snapshot
  4. Export JSON: Download eval case file for use in test suites

Eval Case JSON Format:

{
  "id": "eval-case-abc123",
  "agent_type": "extraction",
  "created_at": "2024-01-15T10:30:00Z",
  "conversation_id": "1234567890",
  "input": {
    "messages": [
      {"role": "customer", "text": "I need an appointment", "timestamp": "..."}
    ],
    "context": [
      {"role": "page", "text": "Hello! How can I help?", "timestamp": "..."}
    ]
  },
  "workflow_state": {
    "status": "gathering",
    "extracted_data": {"name": null, "phone": null}
  },
  "expected_output": null
}

Enable Admin Dashboard:

# .env
ADMIN_DASHBOARD_ENABLED=true
ADMIN_PASSWORD_HASH="$2b$12$..."  # bcrypt hash of admin password
JWT_SECRET_KEY="your-secret-key"

Generate password hash:

from passlib.hash import bcrypt
print(bcrypt.hash("your-password"))

Messenger Integration

The core feature captures and stores Facebook Messenger conversations:

  • Real-time message capture via webhook
  • Automatic conversation threading by customer PSID
  • Message deduplication (handles webhook retries)
  • Image attachment metadata storage
  • Rate limiting (100 messages/minute by default)

Info-Gatherer AI Agent (Optional)

AI-powered appointment booking workflow that:

  • Activates when page admin sends @appointment keyword
  • Extracts customer name, phone, service type, and appointment datetime
  • Creates Google Calendar events when appointments are confirmed
  • Deactivates via @cancel keyword or 12-hour timeout

Workflow Nodes & Agents:

Node Agent Purpose
extraction_node ExtractionAgent Extract & validate: name, phone, service, datetime
confirmation_node ConfirmationAssessmentAgent Assess yes/no/unclear, check calendar, book
response_node ResponseGeneratorAgent Generate contextual reply to customer

Workflow Execution Flow:

┌─────────────────────────────────────────────────────────────────────────┐
│  START → route_by_status()                                              │
│            │                                                            │
│            ├── "gathering"  → extraction_node → response_node → END    │
│            ├── "confirming" → confirmation_node → response_node → END  │
│            └── "finished"   → END                                       │
└─────────────────────────────────────────────────────────────────────────┘

Enable Info-Gatherer:

# .env
INFO_GATHERER_ENABLED=true
INFO_GATHERER_MODEL="openai:gpt-4o-mini"
OPENAI_API_KEY="sk-your-openai-api-key"

Google Calendar Integration

To automatically create calendar events when appointments are confirmed:

Step 1: Create Google Cloud Project

  1. Go to Google Cloud Console
  2. Create a new project (or select existing)
  3. Enable Google Calendar API: APIs & Services → Library → Search "Google Calendar API" → Enable

Step 2: Create Service Account

  1. Go to IAM & Admin → Service Accounts → Create Service Account
  2. Name it (e.g., appointment-bot) → Create and Continue → Done
  3. Click on the created service account → Keys tab → Add Key → Create new key → JSON → Download

Step 3: Get Calendar ID

  • Primary calendar: Your Gmail address (e.g., your-email@gmail.com)
  • Dedicated calendar (recommended): Create new calendar in Google Calendar → Settings → Integrate calendar → Copy Calendar ID

Step 4: Share Calendar with Service Account

  1. In Google Calendar settings, under "Share with specific people"
  2. Add service account email (from JSON file, e.g., appointment-bot@project.iam.gserviceaccount.com)
  3. Set permission to "Make changes to events"

Step 5: Configure Environment Variables

# .env
GOOGLE_CALENDAR_ENABLED=true
GOOGLE_CALENDAR_ID="your-calendar-id@group.calendar.google.com"
GOOGLE_SERVICE_ACCOUNT_FILE="/path/to/service-account.json"

LLM Observability (Optional)

Track AI agent performance with Langfuse:

# .env
LANGFUSE_PUBLIC_KEY="pk-your-key"
LANGFUSE_SECRET_KEY="sk-your-key"
LANGFUSE_HOST="https://cloud.langfuse.com"

Logging Pattern

Structured JSON logs with hybrid dotted namespace:

  • Format: {domain}.{component}.{action}_{state}
  • Examples: messenger.webhook_received, application.lifecycle.started
  • Automatic correlation IDs for request tracing

See .kiro/steering/logging-standard.md for complete taxonomy.

Type Safety Strategy

Dual-layer type checking for maximum safety:

  1. MyPy: Development workflow (pragmatic, faster iteration)
  2. Pyright: Production gate (strict, catches edge cases)

All functions must have complete type annotations. No Any types without documentation.

Usage Examples

Running the Frontend

cd frontend

# Install dependencies
npm install

# Start development server (with hot reload)
npm run dev

# Build for production
npm run build

# Preview production build
npm run preview

# Lint code
npm run lint

Running Tests

# All backend tests
uv run pytest -v

# With coverage
uv run pytest --cov=app --cov-report=html

# Integration tests only
uv run pytest -m integration

# Skip integration tests
uv run pytest -m "not integration"

Code Quality Checks

# Backend: Development workflow (fast)
uv run ruff check . --fix && uv run ruff format . && uv run mypy app/

# Backend: Pre-commit workflow (comprehensive)
uv run ruff check . --fix && uv run ruff format . && uv run mypy app/ && uv run pyright app/

# Frontend: Lint and type check
cd frontend && npm run lint

Database Migrations

# Create new migration
uv run alembic revision --autogenerate -m "Description"

# Apply migrations
uv run alembic upgrade head

# Rollback one migration
uv run alembic downgrade -1

Platform-Specific Setup

The application runs on Windows, Linux, and macOS. All commands use cross-platform tools.

Windows (PowerShell)

# Clone and setup
git clone <repository-url>
cd kiro-appointbot
uv sync

# Configure environment
copy .env.example .env
# Edit .env with your credentials

# Run application
uv run uvicorn app.main:app --reload --port 8000

Linux / macOS (Bash)

# Clone and setup
git clone <repository-url>
cd kiro-appointbot
uv sync

# Configure environment
cp .env.example .env
# Edit .env with your credentials

# Run application
uv run uvicorn app.main:app --reload --port 8000

Docker (All Platforms)

Docker provides a consistent environment across all operating systems.

# Start backend + frontend (connects to your Supabase DATABASE_URL)
docker-compose up -d --build

# View logs
docker-compose logs -f app

# Check health
curl http://localhost:8000/health

# Access the application
# - API: http://localhost:8000
# - Frontend: http://localhost:5173

# Stop services
docker-compose down

Optional: Local PostgreSQL (for offline development)

# Start with local PostgreSQL
docker-compose --profile local-db up -d --build

# Run database migrations
docker-compose exec app alembic upgrade head

# Stop and remove volumes
docker-compose --profile local-db down -v

Configuration

Key environment variables (see .env.example for complete list):

Variable Description Required
DATABASE_URL PostgreSQL connection string Yes
FACEBOOK_PAGE_ACCESS_TOKEN Facebook Page token Yes
FACEBOOK_APP_SECRET Facebook App secret Yes
FACEBOOK_VERIFY_TOKEN Custom webhook verify token Yes
INFO_GATHERER_ENABLED Enable AI agent No
OPENAI_API_KEY OpenAI API key (if AI enabled) Conditional
GOOGLE_CALENDAR_ENABLED Enable calendar integration No
ADMIN_DASHBOARD_ENABLED Enable admin dashboard No
ADMIN_PASSWORD_HASH Bcrypt hash of admin password Conditional
JWT_SECRET_KEY Secret key for JWT tokens Conditional

Troubleshooting

Common Issues

Database connection errors

  • Verify PostgreSQL/Supabase is accessible
  • Check DATABASE_URL in .env matches your database
  • Ensure migrations are applied: uv run alembic upgrade head

Type checking errors

  • Run MyPy: uv run mypy app/
  • Run Pyright: uv run pyright app/
  • Check for missing type annotations
  • Clear cache if stale: rm -rf .mypy_cache

Import errors or module not found

  • Reinstall dependencies: uv sync
  • Check Python version: python --version (requires 3.12+)
  • Clear caches: rm -rf .mypy_cache .pytest_cache .ruff_cache

Facebook webhook not receiving events

  • Verify webhook URL is publicly accessible (use ngrok for local dev)
  • Check verify token matches FACEBOOK_VERIFY_TOKEN in .env
  • Ensure webhook subscriptions are active in Facebook App Dashboard
  • Review logs: LOG_LEVEL=DEBUG

Application won't start

  • Check .env file exists with all required variables
  • Verify port isn't in use:
    • Windows: netstat -ano | findstr :8000
    • Linux/macOS: lsof -i :8000
  • Run with debug: LOG_LEVEL=DEBUG uv run uvicorn app.main:app

Admin dashboard login fails

  • Verify ADMIN_DASHBOARD_ENABLED=true in .env
  • Check ADMIN_PASSWORD_HASH is a valid bcrypt hash
  • Ensure JWT_SECRET_KEY is set
  • Test password hash: python -c "from passlib.hash import bcrypt; print(bcrypt.verify('your-password', 'your-hash'))"

Frontend can't connect to backend

  • Ensure backend is running on port 8000
  • Check Vite proxy configuration in frontend/vite.config.ts
  • Verify CORS settings allow localhost:5173

Getting Help

  • Logs: Review structured logs for detailed error context
  • Documentation: Check .kiro/steering/ for detailed guides
  • Debug Mode: Run with LOG_LEVEL=DEBUG for verbose output

License

MIT License - see LICENSE file for details.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages