This folder contains the FastAPI backend used by the booking app to create Google Calendar events after a booking is submitted.
The backend is intentionally small. It currently does one real production job:
- Accept booking payloads from the frontend.
- Convert them into a Google Calendar event.
- Insert that event into the configured Google Calendar account.
It also initializes Firebase Admin for future server-side Firestore work, but the current booking flow still writes to Firestore from the frontend.
main.py- FastAPI application, CORS setup, Firebase and Google Calendar bootstrap, and HTTP routes.features.py- Calendar event construction helpers and stubs for future booking logic.authorize.py- One-time local OAuth helper that generatestoken.jsonfor Google Calendar access.requirements.txt- Python dependencies.vercel.json- Vercel Python deployment config.tests/- Scratch/test scripts used while wiring up the calendar integration.
The current booking flow is:
- The frontend collects booking data.
- The frontend saves the booking document to Firestore.
- The frontend calls
POST /book-tour/on this backend. - The backend calls
createEvent(...)to build a Google Calendar event. - The backend inserts the event into the
primarycalendar withsendUpdates="all".
Important detail: the backend does not currently create or update the Firestore booking record. That work happens in the frontend.
main.py tries to initialize Firebase Admin so the backend can access Firestore later.
Credential loading works in two modes:
- Environment variables containing a Firebase service account
- Local fallback file:
./serviceAccountKey.json
If credential loading fails, the app keeps running with db = None.
main.py also loads Google Calendar credentials. It tries:
- Environment variables containing an OAuth token + refresh token
- Local fallback file:
token.json
If both fail, calendar_service = None.
The backend uses the Google Calendar API client to insert events into the connected calendar account.
This is the FastAPI entrypoint.
It defines:
app = FastAPI()- CORS middleware
- Firebase initialization
- Google Calendar client initialization
- HTTP routes
Routes currently exposed:
GET /OPTIONS /{path:path}POST /test-bookPOST /book-tour/
The core helper here is createEvent(data, calendar_service).
It builds the event payload that gets sent to Google Calendar.
Current behavior:
- Reads
startTimeISOandendTimeISOfrom the request data. - Uses
tourTypeas the event title when present. - Falls back to a default Baskin Engineering location.
- Adds the booking email as an attendee.
- Adds any BESAs listed in
data["besas"]as attendees too. - Sets timezone to
America/Los_Angeles. - Uses default reminders.
There are also placeholder functions:
assignBESA()modifyBooking()
They currently do nothing and are future expansion points.
This is a one-time local helper script used to generate a Google OAuth token.
It:
- Reads
client_secret.json - Opens the browser for user consent
- Saves the resulting credentials to
token.json
Use this when you need to create or refresh the local calendar token.
These are not formal automated tests yet.
testCalendar.pyis only a note placeholder.getfromFireDb.pyis empty.
main.py can read Firebase credentials from environment variables:
FIREBASE_TYPEFIREBASE_PROJECT_IDFIREBASE_PRIVATE_KEY_IDFIREBASE_PRIVATE_KEYFIREBASE_CLIENT_EMAILFIREBASE_CLIENT_IDFIREBASE_AUTH_URIFIREBASE_TOKEN_URIFIREBASE_AUTH_PROVIDER_X509_CERT_URLFIREBASE_CLIENT_X509_CERT_URLFIREBASE_UNIVERSE_DOMAIN
If those are not present, it falls back to:
./serviceAccountKey.json
main.py can read Google Calendar credentials from environment variables:
CALENDAR_TOKENCALENDAR_REFRESH_TOKENCALENDAR_TOKEN_URICALENDAR_CLIENT_IDCALENDAR_CLIENT_SECRETCALENDAR_EXPIRY- optionalCALENDAR_UNIVERSE_DOMAIN- optionalCALENDAR_ACCOUNT- optional
If those are not present, it falls back to:
token.json
Local files expected by the helper scripts:
client_secret.json- used byauthorize.pytoken.json- generated byauthorize.pyserviceAccountKey.json- Firebase Admin fallback credential file
From the backend/ directory:
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtIf you are using the local file-based auth flow:
python3 authorize.pyThat creates token.json.
For local development:
uvicorn main:app --reloadIf you want to run the module directly:
python3 main.pyBy default the app listens on 0.0.0.0:8000 when started through main.py.
Simple health-check style route.
Response:
{ "Hello": "World" }Global preflight handler for CORS requests.
Response:
{ "message": "preflight ok" }This route manually sets:
Access-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-Headers
Developer stub endpoint.
It currently builds a hard-coded sample booking payload, but it does not return or persist anything. It is effectively a placeholder for manual testing.
Main booking endpoint.
Request body:
{
"startTimeISO": "2025-12-19T15:30:00-08:00",
"endTimeISO": "2025-12-19T16:30:00-08:00",
"email": "visitor@example.com",
"firstName": "Ada",
"lastName": "Lovelace",
"besas": [
{ "email": "guide@example.com", "name": "Guide Name" }
],
"tourType": "BESAs Drop In Office Hours",
"location": "Baskin Engineering Courtyard"
}Behavior:
- The request JSON is passed to
createEvent(...). - The returned event is inserted into the primary Google Calendar.
- The API returns the Google Calendar API response from
events().insert(...).execute().
If calendar_service is unavailable, this route will fail when it tries to call calendar_service.events().
The event created in features.py includes:
summarylocationdescriptionstart.dateTimestart.timeZoneend.dateTimeend.timeZoneattendeestransparencyvisibilityreminders
The description text is currently hard-coded and includes:
- Tour location instructions
- Contact email
- A reminder that tours are scheduled in Pacific Time
- A note about avoiding double booking
vercel.json maps all requests to main.py and deploys the app as a Python serverless function.
main.pyis the build entrypoint.- All routes are rewritten to
main.py.
That means the same FastAPI app handles every deployed backend route.
These are current code realities, not idealized architecture decisions:
ALLOWED_ORIGINSis defined inmain.py, but the CORS middleware currently hardcodes onlyhttps://besa-booking.vercel.app.FRONTENDpoints to a different Vercel URL than the middleware origin list.- The backend does not yet expose CRUD endpoints for bookings.
- The backend does not currently write to Firestore.
assignBESA()andmodifyBooking()are placeholders.POST /test-bookis a stub and does not validate or return useful data.- The calendar flow depends on a valid OAuth token or refresh token.
Check:
token.jsonexists, or theCALENDAR_*environment variables are set- the Google account has Calendar API access
- the target calendar is reachable
calendar_serviceis notNone
Check:
serviceAccountKey.jsonexists locally, or the Firebase env vars are set- the service account has Firestore permissions
- the Firebase project ID matches the client app
If the frontend cannot reach the backend from the browser, the likely cause is an origin mismatch in allow_origins or the manual OPTIONS response headers.
If you keep extending this backend, the next logical additions are:
- Booking read/update/delete endpoints
- Firestore writes from the backend instead of the client
- Calendar event update and cancellation support
- Proper request/response models with Pydantic
- Error handling for missing credentials and invalid payloads
- Automated tests for
createEvent(...)and the booking route