setup guide

Follow this guide to deploy your own instance of CDL Scheduler.

prerequisites

You will need:

  • A Google account with access to Google Calendar, Gmail, and Google Sheets

  • A GitHub account with GitHub Pages enabled

  • Node.js (v16+) with npm installed

  • git installed locally

  • clasp (Command Line Apps Script Projects) — install with:

    npm install -g @google/clasp
    
  • Enable the Google Apps Script API at script.google.com/home/usersettings

step 1: clone the repository

Fork the CDL Scheduler repository on GitHub, then clone your fork:

git clone https://github.com/YOUR_USERNAME/scheduler.git
cd scheduler

step 2: set up the backend (Google Apps Script)

log in to clasp

clasp login

This opens a browser window to authorize clasp with your Google account.

create a new Apps Script project

cd backend
clasp create --type webapp --title "CDL Scheduler Backend"

This creates a new Apps Script project and generates a .clasp.json file in the backend/ directory.

push the backend code

clasp push --force

This uploads all .gs files and appsscript.json to your Apps Script project.

enable the Calendar Advanced Service

  1. Open the Apps Script editor:

    clasp open
    
  2. In the editor, click Services (the + icon in the left sidebar)

  3. Find Google Calendar API and click Add

  4. Keep the default identifier Calendar and click Add

set Script Properties

In the Apps Script editor:

  1. Click the gear icon (Project Settings) in the left sidebar

  2. Scroll down to Script Properties

  3. Click Edit script properties and add the following:

Property

Description

Example

CALENDAR_ID

Google Calendar ID to check for availability

your.email@gmail.com

OWNER_EMAIL

Your email address (receives booking notifications)

your.email@gmail.com

OWNER_NAME

Your display name in emails

Jane Doe

SPREADSHEET_ID

ID of a Google Sheet for storing bookings (create a blank sheet and copy the ID from the URL)

1AbCdEfGhIjKlMnOpQrStUvWxYz

GITHUB_PAGES_URL

Your GitHub Pages URL

https://yourusername.github.io/scheduler

AVAILABILITY_PATTERN

Title of calendar events that define your availability

Office hours

CONFLICT_CALENDAR_IDS

JSON array of calendar IDs to check for conflicts

["your.email@gmail.com"]

MIN_NOTICE_HOURS

Minimum hours before a slot can be booked

12

MAX_ADVANCE_DAYS

Maximum days in advance a slot can be booked

90

TOKEN_EXPIRY_DAYS

Days before booking tokens expire

90

CLEANUP_KEY

Secret key for the cleanup endpoint (generate a random string)

my-secret-cleanup-key-123

Tip

To generate a secure CLEANUP_KEY, run: python3 -c "import secrets; print(secrets.token_hex(32))"

deploy the web app

  1. In the Apps Script editor, click Deploy > New deployment

  2. Click the gear icon next to “Select type” and choose Web app

  3. Set:

    • Description: v1 (or any version label)

    • Execute as: Me

    • Who has access: Anyone

  4. Click Deploy

  5. Copy the Web app URL — you will need this for the frontend configuration

Important

After every clasp push --force, you must create a new versioned deployment for changes to take effect:

  1. Click Deploy > Manage deployments

  2. Click the pencil icon on your deployment

  3. Under Version, select New version

  4. Click Deploy

step 3: set up the frontend (GitHub Pages)

update frontend configuration

Edit config/settings.yaml with your Apps Script URL and preferences:

availability_pattern: "Office hours"
min_notice_hours: 12
max_advance_days: 90
default_timezone: "America/New_York"
theme_color: "#CCE2D8"
apps_script_url: "YOUR_APPS_SCRIPT_WEB_APP_URL_HERE"

Replace YOUR_APPS_SCRIPT_WEB_APP_URL_HERE with the URL you copied during deployment.

customize meeting types

Edit config/meeting-types.yaml to define your meeting types:

meeting_types:
  - id: office-hours
    name: "Office hours"
    duration: 15
    description: "Meet with me about a course."

  - id: project-meeting
    name: "Project meeting"
    duration: 30
    description: "Discuss a project update."
    instructions: "Please share an agenda before our meeting."

Each meeting type has:

  • id — unique identifier (used internally)

  • name — display name shown to visitors

  • duration — meeting length in minutes (15, 30, 45, or 60)

  • description — shown on the meeting type selection page

  • instructions — (optional) additional instructions shown to visitors

customize locations

Edit config/locations.yaml to define available meeting locations:

locations:
  - id: virtual
    label: "Virtual (Zoom)"
    value: "https://zoom.us/my/yourroom"

  - id: in-person
    label: "In-person"
    value: "Room 123, Building Name"

enable GitHub Pages

  1. Go to your repository on GitHub

  2. Navigate to Settings > Pages

  3. Under Source, select Deploy from a branch

  4. Choose main branch and / (root) directory

  5. Click Save

Your scheduler will be available at https://yourusername.github.io/scheduler after a few minutes.

step 4: set up GitHub Actions

The cleanup workflow automatically removes expired bookings. It requires two repository secrets.

  1. Go to your repository on GitHub

  2. Navigate to Settings > Secrets and variables > Actions

  3. Click New repository secret and add:

Secret

Value

APPS_SCRIPT_URL

Your Apps Script web app URL (same URL from the deployment step)

CLEANUP_KEY

The same CLEANUP_KEY value you set in Script Properties

The cleanup runs automatically every Sunday at midnight UTC. You can also trigger it manually from the Actions tab.

step 5: create availability

CDL Scheduler finds your available time slots by looking for calendar events that match your AVAILABILITY_PATTERN.

  1. Open Google Calendar

  2. Create a new event with the title matching your pattern (e.g., “Office hours”)

  3. Set it as a recurring event on the days and times you want to be available

  4. Make sure the event is on the calendar matching your CALENDAR_ID

Tip

The availability pattern is a case-sensitive substring match. If your pattern is “Office hours”, events titled “Office hours” or “Office hours (Spring 2026)” will both match.

step 6: verify your setup

  1. Visit your scheduler site at https://yourusername.github.io/scheduler

  2. Confirm that your meeting types are displayed

  3. Select a meeting type and verify that available slots appear on the calendar

  4. Make a test booking:

    • Pick an available slot

    • Fill in the form with test details

    • Submit the booking

  5. Verify that:

    • A calendar event was created on your Google Calendar

    • You received a confirmation email

    • The test visitor email received a confirmation

    • The reschedule and cancel links in the email work correctly

Tip

If no availability slots appear, check:

  1. Your AVAILABILITY_PATTERN matches the exact title of your calendar events

  2. The calendar events are on the calendar matching CALENDAR_ID

  3. The slots are within the MIN_NOTICE_HOURS and MAX_ADVANCE_DAYS window

  4. The CONFLICT_CALENDAR_IDS doesn’t include calendars with events blocking your availability windows