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.sql
allowsend_date
to 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#GetTemplateCourses
Admins 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.UpdateCourseTemplateStatus
DB:
MarkCourseAsTemplate
/UnmarkCourseAsTemplate
indb/query/template.sql
POST
/api/courses/:uuid/copy
β Copy a course (optionally creating a template)Implementation:
course/copy/router.go#copyCourse
βcopy.copyCourseInternal
See Copy Semantics below.
GET
/api/courses/:uuid/copyable
β Verify all phases expose/copy
endpoint 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.go
Service:
servers/assessment/assessmentTemplates/service.go
DTOs:
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.tsx
Offers: New Course, Create New Template, Use Template
Create Template from scratch:
managementConsole/courseOverview/AddTemplateDialog.tsx
Properties form:
AddTemplateProperties.tsx
withtemplateFormSchema
Creates course via POST
/api/courses/
withtemplate: true
Make Template from existing course:
managementConsole/courseSettings/components/CourseTemplateToggle.tsx
Opens
CopyCourseDialog
withcreateTemplate=true
useTemplateForm
β validates name/semester tagBackend call: POST
/api/courses/:id/copy
withTemplate = true
Use Template to create course:
TemplateSelectionDialog.tsx
Queries templates with
getTemplateCourses
(GET/api/courses/template
)On select β opens
CopyCourseDialog
(useTemplateCopy = true
,createTemplate = false
)Backend call: POST
/api/courses/:templateId/copy
withTemplate = false
Networking helpers:
src/network/queries/getTemplateCourses.ts
src/network/queries/checkCourseTemplateStatus.ts
src/network/mutations/updateCourseTemplateStatus.ts
src/network/hooks/useCopyCourse.ts
src/network/hooks/useTemplateForm.ts
Validations:
src/validations/template.ts
andmakeTemplateCourse.ts
enforce 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:
/copyable
verifies 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.go
and 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.