This is already done. The Boulder Sheet is live, the script is deployed, the calendar is connected, and the board is reading all of it. Steps 1, 3 and 4 below are history, not homework. Keep this page to look up what a column means, and to redeploy the script after any edit to Code.gs (step 2).
When this is done, the Sheet is the master for its rows and the calendar is the master for its events. The team edits those. Nobody edits the board. The board just shows what they say.
Upload 26-0717-BC-BOOKING-SHEET-READY.xlsx (it's in the GDrive
08-BOOKING-SYSTEM folder) to the Boulder Google Drive, open it, then
File > Save as Google Sheets. Done. The tabs, headers, and the whole
current season are already in it.
Google keeps the original file and gives you a live Sheets copy; work in the copy. If you'd rather build the spreadsheet yourself, see the appendix at the end.
The field tables below are reference now, not instructions. The ready file already carries every column. Use the tables when you want to know what a column means or how to fill a cell.
| Field | What it is |
|---|---|
id | Short name-tag for the unit, lowercase with dashes: cedar-chalet. Every row needs one. |
name | The name people say: Cedar Chalet |
type | One of: Lodging, Event, Training, Outdoor. Bed math only counts Lodging rows. |
group | The section it sits under on the board: Cabins & Suites, Dorm Village, Event & Training, Outdoor |
sleeps | How many beds, a number. 0 for event spaces. |
event_capacity | How many people the space holds for an event. Empty for plain lodging. |
config | The bed or room mix, in words: 1 King, 1 Queen, 5 Twin |
rate | The headline rate, just the number: 300 |
rate_basis | What that rate means, in words: per night (occ 6, +$30/extra) |
off_season_rate | Off-season number, or empty if not set |
kitchen | TRUE or FALSE |
shared_bath | TRUE or FALSE |
family_friendly | TRUE or FALSE |
quiet | TRUE or FALSE |
bookable_now | TRUE or FALSE |
map_x | Map position, left to right (percent, 0 to 100) on the Campus view aerial. Leave empty to use the position saved in the board's data.json. |
map_y | Map position, top to bottom (percent, 0 to 100). Same note. |
notes | Anything worth knowing about the unit |
| Field | What it is |
|---|---|
id | Short name-tag for the booking, lowercase with dashes: amanda-likhita-aug. Every row needs one; it is how clicks and links find the booking. |
name | What the team calls it: Women's Retreat, Amanda & Likhita |
org | The organization behind it, or empty |
event_type | In words: Retreat, Wedding, Lodging stay, Family reunion, Produced event, Partner event, Community event, Corporate retreat |
status | Exactly one of these words: Open, Inquiry, Qualified, Quoted, Pending contract, Confirmed. (Held still works; it is the old word for Pending contract.) |
party_size | How many people, a number, or empty |
arrive | Arrival date: 2026-08-27. A real Sheet date works too. |
depart | Departure (checkout) date. Nights = depart minus arrive. |
day_event | TRUE for a one-day event. Set depart to the next day so it paints on its date. Otherwise leave empty. |
spaces | The unit ids this booking uses, comma-separated in one cell: cedar-chalet, grotto. Ids must match the Units tab id column. Leave empty if units are not itemized yet. |
extras | Everything beyond buildings and beds, free text in one cell: amenity access (pool, sauna, volleyball), activities, which part of campus, whatever helps. Line breaks inside the cell are fine and show as written on the booking's detail panel. Or empty. |
beds | Beds the party uses, a number, or empty |
quote | Quoted total, just the number, or empty |
deposit | Deposit amount, just the number, or empty |
deposit_paid | TRUE once paid, FALSE while owed, empty if no deposit yet |
contact | The person's name |
email | Their email |
phone | Their phone |
notes | The story of the booking: counts due, open questions, anything the team should see |
parties | Reserved for multi-party bookings, comma-separated. Fine to leave empty. |
assumed | Optional. Field names whose values are a best guess rather than on file, comma-separated: spaces, party_size. The board marks those with a dashed "assumed" tag. Leave empty when everything is confirmed. |
The board needs id, name, status, arrive and depart on every booking, and id, name, type, group and sleeps on every unit. Everything else can sit empty; the board shows "not on file". Column order does not matter, the header names do.
Code.gs (open it here) and hit the save icon./exec.{"units":booking/app.js in the site repo.const CONFIG = { SHEET_JSON_URL: "" };
const CONFIG = { SHEET_JSON_URL: "https://script.google.com/macros/s/XXXX/exec" };
The Boulder team's standard process is the Google Calendar: the event goes on the calendar, and the dorm and the notes go in the event's description. The board can read that calendar directly. So the team keeps doing exactly what they do today: put the event on the calendar, dorm and notes in the description. The board picks it up on its own.
The calendar ID ships inside Code.gs โ it points at
BCR Events (NEW), the calendar the team edits. Nothing to find or type. The
script only reads the calendar, never writes to it. Two things to know:
calendar_error: No calendar found, share the calendar to that account
with See all event details and fetch again. Sharing needs no redeploy.CONFIG line
at the top of Code.gs and deploying a new version.How calendar events land on the board:
Cedar Chalet,
Tamarack Dorm) puts that unit on the booking. Spelling matters,
capitals do not.data.json in the repo and notes
it in the browser console. Fix the feed and it comes right back.Any change to Code.gs means a fresh paste: replace everything in
Extensions > Apps Script with the new file โ the calendar ID ships inside it,
so there is nothing to re-type. Then Deploy > Manage deployments > pencil icon
> Version: New version > Deploy. The /exec URL does not change, so the board
needs nothing.
If you ever start from a blank Google Sheet instead of the ready file: make two tabs named exactly Units and Bookings (double-click a tab name to rename it). Row 1 of each tab holds the field names from the tables in step 1, spelled exactly (lowercase, with underscores). Every row under row 1 is one unit or one booking. Column order does not matter, the header names do.