Requires Python 3.14 and Node 24 (mise install picks both up from mise.toml). The frontend is React 19 and TypeScript, built with Vite.
- Copy
.env.exampleto.envand fill in the Canvas sandboxCANVAS_CLIENT_IDandCANVAS_CLIENT_SECRET(ask a maintainer). Never commit.env. - Create a virtual environment and install the server dependencies:
python3 -m venv venv source venv/bin/activate pip install -r server/requirements.txt - Install the frontend dependencies with
yarn install. - Run both with
yarn dev, or separately: the backend withpython3 main.pyfromserver/(port 8000) and the frontend withyarn start(the Vite dev server on port 3000, which forwards API calls, the login routes and/offeringsto port 8000). - Run the backend tests from the repository root with
python -m unittest discover -s server -p "test_*.py".
One deployment serves every bCourses course, with the same routes as seating. Users log in through Canvas OAuth (/login/, which returns to /authorized/), and /offerings lists their courses. Each course offering lives under /offerings/<canvas course id>/. Roles come from each Canvas enrollment at sign-in: Teachers and TAs are staff, and Teachers and Lead TAs are admins. Members of the ADMIN_OVERRIDE_CANVAS_COURSE_ID course are staff and admin everywhere. Someone added to a course after signing in needs to sign out and in again.
Course staff set up Sections for a course with "Import courses from canvas" (/offerings/new). Offerings moved from the monorepo store their data under an old key (cs61a, data8, ...); link each one to its Canvas course with flask --app main link-offering <canvas id> <key> "<name>", run from server/ against that database.
To sign in locally, open localhost:3000/offerings and log in. This works on port 3000 if the sandbox developer key allows http://localhost:3000/authorized/ as a redirect URI. Otherwise, log in at localhost:8000/login/ instead, then go back to localhost:3000. A "template not found" error for course pages on port 8000 is expected, because the built frontend isn't served in development.
The production Sections app is deployed on GCP Cloud Run and interacts with bCourses. To locally mock this setup without exposing the production Canvas API keys, we use a "sandbox" Canvas instance located at ucberkeleysandbox.instructure.com. During onboarding to the sections app, you will be added as an admin to the sandbox Canvas instance where you can view the development API key and create new API keys as needed.
All development work should be done using the sandbox instance. Access to bCourses should only be available in the production deployment once all testing with the sandbox is complete. You can do anything you'd like in the sandbox to simulate your desired testing environment (create courses, add students, specify user roles, etc.). You can make your own course, but we currently have a course set up with users that can be found (after logging) by accessing the "Admin" button on the sidebar, then clicking "UC Berkeley Sandbox". Search through the courses for the one titled "Mango 101 (Deokpy Section)".
Our wrapper for the Canvas API is server/canvas_service.py, which also lists the scopes the app requests at login. Those scopes must match the scopes on the app's Canvas developer key.
bCourses API keys have strict scope and permissions. bCourses API keys should only be used for the exact purpose they were granted for. Specifically, the sections app API key should not be used by another app or for any purpose outside the approved scope for the sections app. If you need a new API key with broader scope or for a different app, please contact @pancakereport to discuss. The process for obtaining a new API key requires faculty or full time staff (like @pancakereport) support and working with RTL who manage bCourses.
- Start the server and front end.
- Set up your sandbox course, either by signing in and using "Import courses from canvas" on
localhost:3000/offerings, or withpython3 seed.py 157fromserver/(157 is Mango 101 on the sandbox; this also adds demo sections). - From the
serverdirectory, import example sections and enrollment into that course:
python3 import_locally.py --course 157 --type sections --file test_csvs/test_sections.csv
python3 import_locally.py --course 157 --type enrollment --file test_csvs/disc_enrollment.csv
python3 import_locally.py --course 157 --type enrollment --file test_csvs/lab_enrollment.csv
- Open
localhost:3000/offerings/157/; you should see the example sections.
- Download the sections database to obtain a
.sqlfile. Relevant Links 1 and 2. - Likely the export uses MySQL syntax, so update it to SQLite.
- In the
serverdirectory, deleteapp.dband runsqlite3 app.db < gcp-sections-export.sql.
Functions marked with the @api decorator are also exposed at /api/sudo/<name>, which runs the function as the user with the given email. These endpoints are disabled unless the API_SECRET environment variable is set, and every request must include that secret. Anyone with the secret can act as any user, so store it in Secret Manager and never commit it. Example request:
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"secret": "",
"email": "", # the user to act as
"args": {
"email": "<student>@berkeley.edu"
}
}' \
"https://<sections-host>/api/sudo/get_student_discussion_attendance"
-
Use
yarn typecheck(TypeScript) andyarn lint(ESLint); CI runs both. -
If you'd to see debugging logs while the server is up and running, the usual
printstatements will not work. Instead, a method that currently works is described in this commit. -
If you run the app locally and sign in, you may need to update the local database to give yourself appropriate access levels to test the admin, staff, and student views. To assign yourself staff and admin access run the following (substituting your own email) after having already logged in:
$ sqlite3 server/app.db $ sqlite> UPDATE user SET is_staff = 1, is_admin = 1 WHERE email = '<example>@berkeley.edu'; $ sqlite> .exitIf at any point you receive a error despite having mocked the proper permissions, you should clear your cookies at
localhost:3000(Inspect page -> "Application" tab -> "Clear site data" button)