Unified schedule app for all MatterLab subgroup meetings at schedule.matter.toronto.edu.
The recommended setup is the in-app admin flow: connect the subgroup lead's Google account and choose Create everything. The app creates and connects all Google resources in that account; no per-subgroup GCP project or JSON key is needed.
The steps below document the legacy/manual recovery path for existing service accounts and Shared Drives.
Every subgroup supports lead-owned Drive OAuth for generated Slides and PDF uploads. Existing groups can continue using their service account and Shared Drive until their lead connects.
- Go to console.cloud.google.com
- Create a new project (or use an existing one) — the
project_idin your secrets comes from here - Enable these APIs for the project (search each in the top bar and click Enable):
- Go to IAM & Admin > Service Accounts
- Click Create Service Account, give it a name (e.g.
schedule-ml), click Done - Click the new service account, go to the Keys tab
- Click Add Key > Create new key > JSON — a
.jsonfile downloads
That JSON file contains everything you need for the [groupslug.gcp_service_account] section:
| JSON field | Secrets field |
|---|---|
type |
type (always "service_account") |
project_id |
project_id |
private_key_id |
private_key_id |
private_key |
private_key (the long -----BEGIN PRIVATE KEY-----... string) |
client_email |
client_email (e.g. schedule-ml@myproject.iam.gserviceaccount.com) |
client_id |
client_id |
auth_uri |
auth_uri |
token_uri |
token_uri |
auth_provider_x509_cert_url |
auth_provider_x509_cert_url |
client_x509_cert_url |
client_x509_cert_url |
Copy each value from the JSON into your secrets/groupslug.toml under [groupslug.gcp_service_account].
Create a new Google Sheet and share it with the service account's client_email as Editor.
The spreadsheet_id is the long string in the Sheet URL:
https://docs.google.com/spreadsheets/d/THIS_IS_THE_SPREADSHEET_ID/edit
Add these tabs (exact names):
| Tab | Columns |
|---|---|
Schedule |
Date, Presenter (or Presenter 1, Presenter 2 for two-presenter groups) |
Participants |
Name, Email |
Materials |
Date, Title, Description, PDF_Name, PDF_Link |
Slides |
Date, Presentation_ID, Presentation_Link |
For an existing service-account setup, create two folders inside a Google Shared
Drive and grant the service account client_email Content manager access.
When the lead connects Google Drive in Admin Settings, the folders may remain in
My Drive instead.
- Materials folder — for uploaded PDFs → this is
folder_id - Slides folder — for generated slide decks → this is
slides_folder_id
The folder ID is in the URL:
https://drive.google.com/drive/folders/THIS_IS_THE_FOLDER_ID
Create a Google Slides presentation to use as a template. Add these placeholders in the slides:
{{DATE}}— replaced with the meeting date{{PRESENTER}}— for 1-presenter groups{{PRESENTER1}},{{PRESENTER2}}— for two-presenter groups
Share it with the service account client_email as Viewer. The slides_template_id is in the URL:
https://docs.google.com/presentation/d/THIS_IS_THE_TEMPLATE_ID/edit
Each subgroup has its own file in secrets/. Copy the example and fill it in:
cp secrets/group.toml.example secrets/ml.toml # or quantum.toml, general.toml, etc.The [section] name must match the filename: [ml], [quantum], [general], [drugdiscovery], [handson], [elagente], [robotics].
The remaining fields:
| Field | What it is |
|---|---|
admin_password |
Password to access the admin panel (you pick this) |
organizer_name |
Name shown in confirmation emails (e.g. "Luis Mantilla") |
zoom_link |
Zoom meeting URL for this subgroup |
encryption_key |
Any secret string used to encrypt confirmation links (you pick this) |
No email passwords are stored in secrets. Admins enter their email credentials in the app each session when sending confirmation emails.
Build on the cluster (avoids ARM/x86 mismatch from Mac):
# On the cluster
git clone <repo-url> ~/schedule-logs
cd ~/schedule-logs
# Copy secrets from your local machine:
# scp -r secrets/ user@schedule.matter.toronto.edu:~/schedule-logs/secrets/
docker-compose up -d --build# After code changes:
git pull && docker-compose down && docker-compose up -d --build
# After secrets-only changes (no rebuild needed):
docker-compose restartpip install -r requirements.txt
# Put secrets in secrets/ as above, then:
cat secrets/*.toml > .streamlit/secrets.toml
streamlit run app.pyWhen you click Send Confirmation Emails in the admin panel, the app asks for your email and password. It auto-detects the provider from your email domain:
| Domain | Provider | What to enter |
|---|---|---|
cs.toronto.edu |
UofT CS | Your CS lab password |
utoronto.ca / mail.utoronto.ca |
UofT Outlook | Your UTORid password |
gmail.com |
Gmail | A Gmail App Password (see below) |
Credentials are kept in memory for the session only — never saved to disk or sheets.
Gmail blocks regular password login. You need a one-time App Password:
- Go to myaccount.google.com/apppasswords
- You may need to enable 2-Step Verification first at myaccount.google.com/signinoptions/two-step-verification
- On the App Passwords page, type a name (e.g. "MatterLab Schedule") and click Create
- Google shows a 16-character password like
abcd efgh ijkl mnop— copy it - Paste that into the App Password field in the send dialog
You only need to generate this once. Save it somewhere safe (e.g. a password manager) — Google won't show it again.
Each group's admin logs in via the sidebar password. From there you can manage participants, edit schedules, update integration settings, and change the admin password. Admin-managed passwords are stored as PBKDF2 hashes.
The Streamlit toolbar is set to minimal, which removes viewer tools including
the screen-recording option. Streamlit usage telemetry is also disabled.
Computers on the Matter internal wired network (10.21.0.0/16) or UofT CS wired
network (128.100.0.0/16) bypass Slack sign-in. All other client addresses use
the normal Slack authentication flow. Nginx supplies the trusted client address
through X-Real-IP, and Streamlit is bound to localhost so clients cannot connect
directly and forge that proxy header. The login page displays the workspace value
aspuru, and the OAuth request includes The Matter Lab team ID so Slack preselects
the workspace for users who are already signed in there.
Every subgroup uses the same self-service configuration and always appears as a normal subgroup entry. When one is not configured, opening it shows the admin setup screen instead of a schedule. The lead connects their Google account and the app creates the workspace folder, Sheet and required tabs, materials folder, generated-slides folder, and Slides template in their My Drive. A manual path remains available to connect existing resources. Configured Shared Drive groups continue working before their lead connects.
The Google Cloud Shell key generator remains available only for legacy recovery and existing service-account configurations.
Submitted setup values are stored as a private draft before Google validation. Failed validation and application deployments therefore preserve URLs, meeting settings, and selected setup mode for the next retry. The draft does not enable the subgroup and is cleared after validation succeeds.
Service accounts have no personal Drive storage. Connected groups therefore create generated Slides and uploaded PDFs as the lead, using that account's My Drive quota. During a handover, the new lead reconnects from Admin Settings; the stored resource IDs and deployment do not change, provided the new lead can access the existing resources.
The site shows a one-time operator setup when no OAuth client exists. Create a
Google OAuth client with application type Web,
add the exact redirect URI displayed by the app, and upload the downloaded JSON.
After that, subgroup leads only use Connect Google Drive. The OAuth client and
per-group refresh tokens are stored in data/groups.json, which is mode 0600.
Meeting day, presentation duration, organizer, Zoom link, and one/two-presenter mode are editable in the same UI. Changing presenter mode creates a timestamped backup of the Schedule tab before migrating its columns.
UI-managed secrets are stored in data/groups.json with mode 0600; the
directory is mounted read/write only for runtime configuration and is excluded
from Git and Docker build contexts. The CLI setup command remains available as a
recovery path.