A scalable booking system built with Remix v2 and Cloudflare, designed to handle multiple booking types across various industries and use cases.

Architecture

API Routes (Remix v2)

Following Remix v2 dot notation conventions:

app/routes/
├── api.booking.tsx               // Main booking endpoint for CRUD operations
├── api.booking.$id.tsx           // Get or delete booking by ID
├── api.booking.type.$type.tsx    // Get bookings by type
├── api.booking.email.$email.tsx  // Get bookings by email
├── api.booking.org.$org.tsx      // Get bookings by organization
├── api.booking.user.$userId.tsx  // Get bookings by user ID

Database Schema (D1)

CREATE TABLE bookings (
  id TEXT PRIMARY KEY,
  user_id TEXT NOT NULL,
  email TEXT NOT NULL, 
  type TEXT NOT NULL,
  status TEXT NOT NULL,
  org TEXT,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  deleted_at DATETIME DEFAULT NULL
);

CREATE INDEX idx_bookings_type ON bookings (type) WHERE deleted_at IS NULL;
CREATE INDEX idx_bookings_email ON bookings (email) WHERE deleted_at IS NULL;
CREATE INDEX idx_bookings_user_id ON bookings (user_id) WHERE deleted_at IS NULL;
CREATE INDEX idx_bookings_org ON bookings (org) WHERE deleted_at IS NULL;

Storage Strategy

Core Data (D1)

D1 stores only the essential fields needed for filtering and listing bookings:

  • id (primary key)
  • user_id (who made the booking)
  • email (contact information)
  • type (booking category)
  • status (booking state)
  • org (organization/company)
  • timestamps

Extended Data (KV)

KV store contains the complete booking objects including all extended fields specific to each booking type:

  • Key format: Direct booking ID
  • Value: Complete JSON booking object
  • No TTL (stored until explicitly deleted)

Supported Booking Types

The system supports a wide range of booking types, each with specialized fields:

Appointment

For scheduling meetings and consultations:

  • Virtual or in-person options
  • Participant management
  • Agenda and materials
  • Reminders and notifications

Event

For conferences, webinars, and gatherings:

  • Multi-day scheduling
  • Speaker and presenter management
  • Venue details and capacity
  • Registration and attendance tracking

Rental

For equipment, vehicles, and space rentals:

  • Rental period management
  • Insurance and liability documentation
  • Delivery and pickup options
  • Additional equipment add-ons

Transportation

For airport shuttles, corporate travel, and transportation services:

  • Multiple passenger support
  • Pickup and dropoff locations
  • Vehicle type and features
  • Flight information integration

Medical

For healthcare appointments:

  • Patient information and insurance
  • Provider credentials and specialties
  • Telehealth options
  • Billing and preauthorization

Class/Workshop

For educational sessions and workshops:

  • Instructor information
  • Course materials and prerequisites
  • Multi-session scheduling
  • Capacity and enrollment tracking

API Routes Overview

All API routes follow RESTful conventions using the Remix v2 Resource Routes pattern.

Main Booking API (api.booking.tsx)

POST/api/booking

Create a new booking of any type

PUT/api/booking

Update an existing booking

DELETE/api/booking?id={bookingId}

Soft delete a booking via deleted_at timestamp

Get By ID (api.booking.$id.tsx)

GET/api/booking/{bookingId}

Retrieve a specific booking by ID

Get By Type (api.booking.type.$type.tsx)

GET/api/booking/type/{bookingType}

Retrieve all bookings of a specific type

Get By Email (api.booking.email.$email.tsx)

GET/api/booking/email/{email}

Retrieve all bookings associated with a specific email address

Get By Organization (api.booking.org.$org.tsx)

GET/api/booking/org/{organization}

Retrieve all bookings for a specific organization or company

Get By User ID (api.booking.user.$userId.tsx)

GET/api/booking/user/{userId}

Retrieve all bookings made by a specific user

API Usage Examples

Creating Different Booking Types

// Create an appointment booking
const response = await fetch('/api/booking', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    // Core fields (stored in D1)
    type: "appointment",
    userId: "user123",
    email: "user@example.com",
    org: "acme-corp.com",
    status: "confirmed",
    
    // Extended fields (stored in KV)
    title: "Quarterly Review Meeting",
    description: "Discussion of Q1 results and Q2 planning",
    date: "2025-04-15",
    startTime: "2025-04-15T14:00:00Z",
    endTime: "2025-04-15T15:30:00Z",
    location: {
      name: "HQ Conference Room 3",
      address: "123 Business Park",
      city: "San Francisco",
      state: "CA",
      zipCode: "94103"
    },
    virtual: true,
    meetingLink: "https://meet.example.com/123-456-789"
  })
});

Retrieving Bookings

// Get bookings by organization
const orgBookings = await fetch('/api/booking/org/acme-corp.com');

// Get bookings by user ID
const userBookings = await fetch('/api/booking/user/user123');

// Get bookings by type
const medicalBookings = await fetch('/api/booking/type/medical');

// Get specific booking by ID
const booking = await fetch('/api/booking/booking123-456');

Technical Stack

  • Remix v2
  • Cloudflare D1 (Database)
  • Cloudflare KV (Caching)
  • TypeScript
  • Resource Routes for API
  • Tailwind CSS

Testing

End-to-end testing scripts are available for all booking types:

  • test.py
  • test_appointment.py
  • test_event.py
  • test_rental.py
  • test_transportation.py
  • test_medical.py
  • test_class.py