Skip to content

Repository files navigation

nexus-scheduler

AI-powered scheduling engine with natural language booking, real-time availability, and multi-provider support.

Correctness guarantees (verified by test suite):

  • Zero double-bookings under concurrent requests — Redis distributed lock with atomic Lua release
  • Idempotent by design — duplicate requests with the same key return the existing booking, never create a second
  • Conflict detection throws 409 SLOT_CONFLICT before any write reaches the database
  • Authorisation enforced at cancel/reschedule — only the organiser can modify their booking

TypeScript Node.js PostgreSQL Redis Docker Anthropic WebSockets GitHub Actions CI


What this is

Nexus Scheduler is a backend service that exposes scheduling as a conversational API. Instead of building rigid UI booking flows, clients send natural language — "Book me a slot next Tuesday afternoon" or "Cancel my 3pm and move it to Thursday" — and the engine resolves availability, checks constraints, handles conflicts, and confirms atomically.

This is not a chatbot wrapper. It's a structured booking engine with an AI reasoning layer sitting in front of it. The AI handles intent extraction and ambiguity resolution; the booking engine handles correctness and consistency.

Built to solve a real problem: most scheduling systems break down at the edges — double-bookings under concurrency, ambiguous user input, timezone handling, recurring event conflicts. This system handles all of them explicitly.


Architecture

Client (HTTP / WebSocket)
        │
        ▼
┌─────────────────────┐
│   API Gateway        │  Express + TypeScript
│   Rate limiting      │  100 req/min per tenant
│   JWT auth           │
└────────┬────────────┘
         │
         ▼
┌─────────────────────┐        ┌──────────────────────┐
│   Intent Resolver    │──────▶│   Claude API          │
│   (AI layer)         │◀──────│   Tool use / fn call  │
│   Extracts:          │        │   Streaming responses │
│   - action type      │        └──────────────────────┘
│   - time expressions │
│   - participant refs │
└────────┬────────────┘
         │  Resolved intent (structured JSON)
         ▼
┌─────────────────────┐
│   Booking Engine     │  Core domain logic
│   - availability     │  Pessimistic locking via Redis
│   - conflict check   │  PostgreSQL transactions
│   - slot reservation │  Idempotency keys on all writes
│   - confirmation     │
└────────┬────────────┘
         │
    ┌────┴────┐
    ▼         ▼
PostgreSQL   Redis
(source of   (distributed lock,
 truth)       availability cache,
              job queue)

Key design decisions:

  • Pessimistic locking for slot reservation — Redis distributed lock held for the duration of a booking transaction. Eliminates double-booking under concurrent load without sacrificing throughput.
  • AI as intent layer only — Claude resolves ambiguous input into a strict JSON schema. The booking engine never receives raw text. This means the AI can be swapped or versioned without touching business logic.
  • Idempotency keys on all mutations — every booking, cancellation, and reschedule is idempotent. Safe to retry on network failure.
  • Streaming responses via WebSocket — the AI reasoning step streams token-by-token to the client so users see progress, not a spinner.

Tech stack

Layer Technology Why
Runtime Node.js 20 + TypeScript Type safety across the full request lifecycle
API Express.js Lightweight, well-understood, easy to instrument
AI Anthropic Claude (tool use) Tool/function calling gives structured JSON output from natural language
Real-time WebSockets (ws) Streaming AI responses without polling
Primary DB PostgreSQL 15 ACID transactions for booking consistency
Cache / locks Redis 7 Distributed locking, availability cache, rate limiting
Job queue BullMQ Reminder emails, async confirmation events
Auth JWT + refresh tokens Stateless, scalable across instances
Containerisation Docker + Docker Compose Full local stack in one command
CI/CD GitHub Actions Lint → test → build → push on every PR

Features

  • Natural language booking — resolves relative time expressions (next Tuesday, end of month, in two weeks), participant references, and duration hints
  • Real-time conflict detection — availability checked and locked atomically; no race conditions
  • Multi-timezone support — all times stored as UTC; display timezone per tenant/user config
  • Recurring event scheduling — daily, weekly, monthly, custom intervals with exception handling
  • Streaming responses — WebSocket endpoint streams AI reasoning in real time
  • Webhook eventsbooking.created, booking.cancelled, booking.rescheduled posted to registered URLs
  • Rate limiting — per-tenant, per-endpoint, configurable via environment
  • Observability — structured JSON logging (Pino), request tracing, health endpoints

API

REST endpoints

POST   /api/v1/bookings/intent      # Submit natural language, get structured intent
POST   /api/v1/bookings             # Create booking (structured)
GET    /api/v1/bookings/:id         # Get booking detail
PATCH  /api/v1/bookings/:id         # Reschedule
DELETE /api/v1/bookings/:id         # Cancel
GET    /api/v1/availability         # Query available slots
POST   /api/v1/webhooks             # Register webhook URL

WebSocket

ws://host/ws/booking-stream

# Send:
{ "type": "intent", "message": "Book me a slot next Tuesday afternoon", "tenant_id": "..." }

# Receive (streamed):
{ "type": "stream", "delta": "Checking availability for..." }
{ "type": "resolved", "intent": { "action": "create", "datetime": "2026-05-27T14:00:00Z", ... } }
{ "type": "confirmed", "booking": { "id": "...", "slot": "...", "confirmation_code": "..." } }

Natural language examples

"Book me next Tuesday at 2pm for 30 minutes"
"Cancel my appointment this Friday"
"Do I have anything on Thursday afternoon?"
"Move my 10am tomorrow to the same time next week"
"Schedule a 1-hour call with John for sometime next Monday"
"Am I free this Thursday between 2 and 4?"

Getting started

Prerequisites: Docker, Docker Compose, an Anthropic API key.

git clone https://github.com/ykachala/nexus-scheduler.git
cd nexus-scheduler
cp .env.example .env
# Add your ANTHROPIC_API_KEY to .env
docker compose up

The API is available at http://localhost:3000. Postgres on 5432, Redis on 6379.

# Run tests
npm test

# Run with hot reload (local dev without Docker)
npm install
npm run dev

Environment variables

NODE_ENV=development
PORT=3000
DATABASE_URL=postgresql://user:pass@localhost:5432/nexus
REDIS_URL=redis://localhost:6379
ANTHROPIC_API_KEY=sk-ant-...
JWT_SECRET=your-secret
RATE_LIMIT_WINDOW_MS=60000
RATE_LIMIT_MAX=100

Performance

Load tested with k6 against a 2-vCPU / 4GB instance:

Scenario RPS p95 latency Error rate
Availability queries (cached) 1,200 18ms 0%
Standard booking (DB write) 340 95ms 0%
AI intent resolution (streaming) 80 1.2s first token 0%
Concurrent booking same slot (50 VUs) 0% double-bookings

AI latency is network-bound to Anthropic's API. All booking engine operations are sub-100ms.


Deployment

Docker Compose (single server)

docker compose -f docker-compose.prod.yml up -d

Kubernetes (Helm chart included)

helm install nexus-scheduler ./helm/nexus-scheduler \
  --set image.tag=latest \
  --set env.ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY

AWS ECS

A Terraform module for ECS + RDS + ElastiCache is included under infrastructure/terraform/.


Project structure

nexus-scheduler/
├── src/
│   ├── api/              # Route handlers, middleware
│   ├── ai/               # Intent resolver, Claude integration, tool definitions
│   ├── booking/          # Core domain: availability, locking, confirmation
│   ├── queue/            # BullMQ workers: reminders, webhook dispatch
│   ├── websocket/        # WS server and streaming handler
│   ├── db/               # Prisma schema, migrations, query helpers
│   └── config/           # Env, logger, rate limiter setup
├── tests/
│   ├── unit/
│   ├── integration/
│   └── load/             # k6 scripts
├── helm/                 # Kubernetes Helm chart
├── infrastructure/       # Terraform (AWS ECS + RDS + ElastiCache)
├── docker-compose.yml
├── docker-compose.prod.yml
└── .github/workflows/    # CI: lint, test, build, push

Related


Author: Yoweli Kachala  |  LinkedIn  |  Cape Town, South Africa

About

Natural language scheduling API — book, cancel, reschedule via conversational endpoint. TypeScript + Claude

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages