Skip to content

BE-Student-Ambassadors/besabookingapi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Backend Documentation

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:

  1. Accept booking payloads from the frontend.
  2. Convert them into a Google Calendar event.
  3. 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.

What Lives Here

  • 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 generates token.json for Google Calendar access.
  • requirements.txt - Python dependencies.
  • vercel.json - Vercel Python deployment config.
  • tests/ - Scratch/test scripts used while wiring up the calendar integration.

High-Level Flow

The current booking flow is:

  1. The frontend collects booking data.
  2. The frontend saves the booking document to Firestore.
  3. The frontend calls POST /book-tour/ on this backend.
  4. The backend calls createEvent(...) to build a Google Calendar event.
  5. The backend inserts the event into the primary calendar with sendUpdates="all".

Important detail: the backend does not currently create or update the Firestore booking record. That work happens in the frontend.

Runtime Responsibilities

Firebase Admin

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.

Google Calendar

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.

Files In Detail

main.py

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-book
  • POST /book-tour/

features.py

The core helper here is createEvent(data, calendar_service).

It builds the event payload that gets sent to Google Calendar.

Current behavior:

  • Reads startTimeISO and endTimeISO from the request data.
  • Uses tourType as 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.

authorize.py

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.

tests/

These are not formal automated tests yet.

  • testCalendar.py is only a note placeholder.
  • getfromFireDb.py is empty.

Configuration

Firebase Service Account

main.py can read Firebase credentials from environment variables:

  • FIREBASE_TYPE
  • FIREBASE_PROJECT_ID
  • FIREBASE_PRIVATE_KEY_ID
  • FIREBASE_PRIVATE_KEY
  • FIREBASE_CLIENT_EMAIL
  • FIREBASE_CLIENT_ID
  • FIREBASE_AUTH_URI
  • FIREBASE_TOKEN_URI
  • FIREBASE_AUTH_PROVIDER_X509_CERT_URL
  • FIREBASE_CLIENT_X509_CERT_URL
  • FIREBASE_UNIVERSE_DOMAIN

If those are not present, it falls back to:

  • ./serviceAccountKey.json

Google Calendar OAuth

main.py can read Google Calendar credentials from environment variables:

  • CALENDAR_TOKEN
  • CALENDAR_REFRESH_TOKEN
  • CALENDAR_TOKEN_URI
  • CALENDAR_CLIENT_ID
  • CALENDAR_CLIENT_SECRET
  • CALENDAR_EXPIRY - optional
  • CALENDAR_UNIVERSE_DOMAIN - optional
  • CALENDAR_ACCOUNT - optional

If those are not present, it falls back to:

  • token.json

Local Secret Files

Local files expected by the helper scripts:

  • client_secret.json - used by authorize.py
  • token.json - generated by authorize.py
  • serviceAccountKey.json - Firebase Admin fallback credential file

Local Setup

From the backend/ directory:

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Generate Google Calendar Token

If you are using the local file-based auth flow:

python3 authorize.py

That creates token.json.

Run the Server

For local development:

uvicorn main:app --reload

If you want to run the module directly:

python3 main.py

By default the app listens on 0.0.0.0:8000 when started through main.py.

API Reference

GET /

Simple health-check style route.

Response:

{ "Hello": "World" }

OPTIONS /{path:path}

Global preflight handler for CORS requests.

Response:

{ "message": "preflight ok" }

This route manually sets:

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers

POST /test-book

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.

POST /book-tour/

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().

Google Calendar Event Shape

The event created in features.py includes:

  • summary
  • location
  • description
  • start.dateTime
  • start.timeZone
  • end.dateTime
  • end.timeZone
  • attendees
  • transparency
  • visibility
  • reminders

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

Deployment

vercel.json maps all requests to main.py and deploys the app as a Python serverless function.

Vercel Config

  • main.py is the build entrypoint.
  • All routes are rewritten to main.py.

That means the same FastAPI app handles every deployed backend route.

Important Limitations

These are current code realities, not idealized architecture decisions:

  • ALLOWED_ORIGINS is defined in main.py, but the CORS middleware currently hardcodes only https://besa-booking.vercel.app.
  • FRONTEND points 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() and modifyBooking() are placeholders.
  • POST /test-book is a stub and does not validate or return useful data.
  • The calendar flow depends on a valid OAuth token or refresh token.

Practical Troubleshooting

Calendar Requests Fail

Check:

  • token.json exists, or the CALENDAR_* environment variables are set
  • the Google account has Calendar API access
  • the target calendar is reachable
  • calendar_service is not None

Firebase Fails to Initialize

Check:

  • serviceAccountKey.json exists locally, or the Firebase env vars are set
  • the service account has Firestore permissions
  • the Firebase project ID matches the client app

CORS Issues

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.

Suggested Next Backend Improvements

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

Releases

No releases published

Packages

 
 
 

Contributors

Languages