Instruction file imported from pangeachat/synapse-pangea-chat (
.github/instructions/create-course-space.instructions.md). Copyright stays with the author.
Create Course Space — Synapse Module
Cross-repo design: course-request.instructions.md
Endpoint
POST /_synapse/client/pangea/v1/create_course_space
Lives in the email_invite/ sub-package alongside invite_by_email.
Contract
- Auth: Bearer token (bot user). Choreo logs in with bot credentials from AWS Secrets Manager.
- Input: Course plan ID, title, description, image URL, teacher email, target language, optional extra email template vars. Endpoint does not fetch from CMS — all details passed in body.
- Target language must be an IETF code (
es), never a display name (Spanish). It is stored asl2on the space's course-plan state event and the public course catalog matches it by base language, so a display name matches nothing — and it is sticky, because the one-timel2backfill treats any non-empty value as already correct. It is optional: a space created without it is valid and gets repaired by that backfill, which is the only reason omitting it is safe. See public-courses.
- Target language must be an IETF code (
- Output: Room ID, student access code, admin access code, admin join URL (same format the client already uses for class links — see joining-courses Route 1).
What it does
- Creates a private Matrix space with knock join rules, a course plan state event, and the power levels the client gives a course space it creates itself (
defaultSpacePowerLevelsContent, withm.space.childat 0). Every new space defaultsm.space.childto 0: a regular member must be able to attach a room, because learners' activity sessions fan out into their courses as space children (activities.instructions.md). - Generates two unique access codes (student + admin) and sets both in join rules directly (bypasses
request_room_code) - Uploads course image as room avatar if provided
- Sends branded invite email to teacher via
invite_by_emailwith the admin access code
Admin Access Code
Second code stored alongside the regular access code in join rules. Same format. Teacher uses it via the existing knock_with_code endpoint.
knock_with_code extension
Extend the existing endpoint to check both code fields:
- Student code match → existing behavior (invite as regular member)
- Admin code match → invite + promote to admin + burn the code (remove from join rules state). Single-use by design.
Reuses existing validation, rate limiting, and invite mechanics. No new endpoint — the client already calls knock_with_code for all code-based joins.
Unauthenticated teachers
If the teacher doesn't have a Pangea account, the client handles this: the class code is cached to disk, the user is prompted to sign up, and after account creation the cached code auto-joins. No special handling needed here — see joining-courses "Pre-login persistence."
Dependencies
invite_by_email: Separate session, in progress. Use placeholder for now.- Email templates: Jinja2 in synapse-templates repo, rendered by Synapse's built-in email handler — same as registration emails.
Future Work
- Reusable admin codes (multiple admins per course) — issue TBD
- Automated pipeline trigger (webhook from CMS on status change) — issue TBD