Templating System (Developer Guide)ο
This document explains how the templating system works end-to-end for developers: data model, server endpoints, client flows, and expected copy semantics.
Conceptο
A template is a first-class course record with template = true. It acts as a blueprint to create new courses. Creating from a template performs a deep copy of the original courseβs configuration.
Data Model and Constraintsο
course.template(boolean) marks a course as a template.Migrations support template courses: e.g.,
0015_check_dates_template.up.sqlallowsend_dateto be null for template courses.Name/SemesterTag validation on the client prevents
-in either field.ECTS is fixed for some course types (Seminar = 5, Practical = 10) via UI rules; Lecture requires manual input.
Server (Core) Endpointsο
All routes below are in servers/core and use Gin with permission middleware.
GET
/api/courses/templateβ List template coursesImplementation:
course/router.go#getTemplateCoursesβcourse/service.go#GetTemplateCoursesAdmins get all template courses; Lecturers see only templates they have roles for (restricted query).
GET
/api/courses/:uuid/templateβ Check if a course is a templateImplementation:
course/router.go#checkCourseTemplateStatusβservice.CheckCourseTemplateStatus
PUT
/api/courses/:uuid/templateβ Mark/unmark a course as a templateImplementation:
course/router.go#updateCourseTemplateStatusβservice.UpdateCourseTemplateStatusDB:
MarkCourseAsTemplate/UnmarkCourseAsTemplateindb/query/template.sql
POST
/api/courses/:uuid/copyβ Copy a course (optionally creating a template)Implementation:
course/copy/router.go#copyCourseβcopy.copyCourseInternalSee Copy Semantics below.
GET
/api/courses/:uuid/copyableβ Verify all phases expose/copyendpoint and are reachable.
Copy Semantics (servers/core/course/copy/copy_course.go)ο
When copying with Template = false:
Creates a new course with given Name, SemesterTag, StartDate, EndDate
Copies:
Course phases and their order (phase graph)
Phase/data/participation graphs
DTO mappings and meta graphs
Application form if both source and target course have an application phase
Student-readable and restricted metadata
CourseType and ECTS
Creates Keycloak roles/groups for the new course
When copying with Template = true:
Same as above, but:
StartDate and EndDate are omitted (NULL dates)
The new course is marked as template (
MarkCourseAsTemplate)
Error handling: Runs within a DB transaction; partial failures roll back. Some operations (e.g., phase configuration copy) are executed after commit and may still return errors up the call chain.
Server (Assessment) β Assessment Templatesο
Separate from course templates, the assessment service exposes assessment template management:
Router:
servers/assessment/assessmentTemplates/router.goService:
servers/assessment/assessmentTemplates/service.goDTOs:
assessmentTemplateDTO/*
Endpoints under /assessment-template (Prompt Admin for mutating routes):
GET
/assessment-templateβ ListGET
/assessment-template/:templateIDβ Get by IDPOST
/assessment-templateβ CreatePUT
/assessment-template/:templateIDβ UpdateDELETE
/assessment-template/:templateIDβ Delete
Use GetCoursePhasesByAssessmentTemplate to find course phases using a given assessment template.
Client (Core) Flowο
Key files under clients/core:
Course creation choices UI:
managementConsole/courseOverview/AddingCourse/components/CourseCreationChoiceDialog.tsxOffers: New Course, Create New Template, Use Template
Create Template from scratch:
managementConsole/courseOverview/AddTemplateDialog.tsxProperties form:
AddTemplateProperties.tsxwithtemplateFormSchemaCreates course via POST
/api/courses/withtemplate: true
Make Template from existing course:
managementConsole/courseSettings/components/CourseTemplateToggle.tsxOpens
CopyCourseDialogwithcreateTemplate=trueuseTemplateFormβ validates name/semester tagBackend call: POST
/api/courses/:id/copywithTemplate = true
Use Template to create course:
TemplateSelectionDialog.tsxQueries templates with
getTemplateCourses(GET/api/courses/template)On select β opens
CopyCourseDialog(useTemplateCopy = true,createTemplate = false)Backend call: POST
/api/courses/:templateId/copywithTemplate = false
Networking helpers:
src/network/queries/getTemplateCourses.tssrc/network/queries/checkCourseTemplateStatus.tssrc/network/mutations/updateCourseTemplateStatus.tssrc/network/hooks/useCopyCourse.tssrc/network/hooks/useTemplateForm.ts
Validations:
src/validations/template.tsandmakeTemplateCourse.tsenforce name and semester tag rules and ECTS input constraints.
Permissionsο
Listing templates: Prompt Admin, Course Lecturer
Creating templates (from scratch or from existing course): Prompt Admin, Course Lecturer
Using templates to create a course: Prompt Admin, Course Lecturer
The server additionally filters template visibility for non-admins based on the userβs course roles.
Edge Cases and Notesο
Name/SemesterTag uniqueness and format are enforced downstream; UI prevents hyphens and empty values.
If the source course lacks an application phase, the application form is not copied (no-op).
Copyability check:
/copyableverifies all phases implement copy; UI shows a confirmation step.After creating a course (or template), the client refreshes Keycloak token and refetches courses to ensure new roles are loaded for navigation.
Extending the Systemο
To add fields that should be copied, update
copy_course.goand the DTO/metadata conversion utilities.To expose new template kinds (e.g., per-phase templates), add appropriate endpoints in the respective service and mirror the client flows.