Features in detail
A complete list of what the system does today, by role and module. Only what is implemented: nothing from the roadmap.
For every user
Sign-in and profile
- Sign-in with email and password; the session is extended automatically.
- Sign-in through the university account or an external identity provider: buttons right on the login page.
- A limit on sign-in attempts per address as protection against password guessing.
- On wrong credentials the system does not reveal which part was wrong, email or password.
- A blocked account cannot sign in.
- After sign-in, a personal dashboard with its own menu for each role.
- Profile: full name, login, email, role, student ID number, linked code-hosting accounts, group, registration date.
- Editing the allowed profile fields: full name, student ID number, code-hosting account and preferred language.
- Password change from the profile with length and confirmation checks.
- On first sign-in the system requires changing the issued password.
- Linking and unlinking external sign-in accounts right in the profile.
- Interface language: English, Polish, Russian, Belarusian; the choice is remembered and applied on every page.
- Dates and numbers are shown in the format of the selected language.
- A “skip to content” link on every page for keyboard users.
Help
- Built-in help for the student and the lecturer: first steps, a guide to the screens and step-by-step recipes.
- A student sees the student help, a lecturer sees the lecturer and student help; help is available in all four interface languages.
Working with GitHub and GitLab
How the system works with the code host
- The course lives in a repository: tasks, guides, rubrics and check templates are files under version control; a course version is a git tag, and content under a tag is immutable.
- The system brings no code hosting of its own: it works on top of the university's GitHub or GitLab through a bot account and least-privilege tokens.
- For every student and every course the system creates a private personal repository from a starter: report template, code skeleton, public tests, CI configuration; private course material never gets in.
- Submission is a pull request on GitHub or a merge request on GitLab; the event arrives by webhook, and a fallback poll of open requests covers a lost webhook.
- Automated checks run in the host's own CI: GitHub Actions or the university's GitLab CI; the system reads the check status and does not start the AI review on a red result.
- Only a neutral comment with a link into the system is posted to the request: no points, no feedback text.
- A force-push is the same submission with a new revision, no duplicates; events on already graded work are ignored.
- Course authoring also goes through requests: task scaffold, file edits and CI templates are sent as a reviewed request, merged only after approval.
- One central repository of automated checks per organisation or group; course and student repositories point at a floating tag, so fixes arrive without commits to every repository.
- Synchronisation of the organisation or group membership with the system: a drift report, invitations for the missing, a dry run without changes.
- Only the student's login goes to the code host: no full name, no email, no grades.
- Both providers at the same time: a user has one account per provider, a course has one provider, and default tokens and organisations are set separately for each.
GitHub
- GitHub.com and GitHub Enterprise Server: the instance address is set in the token.
- A bot account and two tokens: one for membership and invitations, another for course content.
- Students' personal repositories in the university organisation; access by collaborator invitation, organisation membership is optional, organisation members need no invitation.
- Works on the free organisation plan as well: the missing branch protection is compensated by the publishing review gate in the system itself.
- An organisation webhook for pull request events only, with signature verification before the body is parsed.
- The GitHub Actions result is read through check-runs with a fallback through the Actions API; when neither is available, an explicit error instead of a green pass.
- A student without a GitHub account gets an “error” status with the reason; failed repository creations are retried with increasing delays, plus a “Retry” button.
- Organisation invitations by login through the Invitations API.
GitLab CE (self-hosted)
- The university's own GitLab instance: the address and the group are set in the token; courses and students are projects in that group.
- A private personal project per student with the Developer role.
- A webhook on every personal project with a secret token; the setup is re-verified on every pass so an old secret cannot linger.
- The personal project's CI configuration is pinned to the central check repository: the student cannot change it, a stricter boundary than on GitHub.
- Forks are disabled; a merge request from a fork is not accepted as a submission.
- Read access to central checks through Reporter membership without write permissions.
- A working runner is checked at project creation; a stuck pipeline does not block the review forever, the timeout is configurable.
- Switching the central check version for a course without a merge request.
- A shared Keycloak realm for the system and GitLab: one password to sign in to both.
- Runner requirements are documented: docker executor, resource limits, timeouts, network isolation, auto-cancellation of redundant pipelines.
What the university provides
- An organisation on GitHub or a group in its own GitLab CE.
- A bot account and least-privilege tokens registered in the system.
- For GitLab, a docker-executor runner; for GitHub, Actions minutes or a self-hosted runner.
- A public address for webhooks; without it, the fallback poll takes over.
For the student
Assigned work
- Assignment cards: course, task, deadline, submission status; only the student's own group is shown.
- Search across assignments and a filter by status.
- Sorting by deadline, nearest first, taking personal extensions into account.
- An unread-feedback indicator on the assignment card.
- A “repository being prepared” badge while the personal repository is created, and a “closed” mark on closed assignments.
- Assignment page: the guide, the handbook and the report template with full formatting (headings, lists, code blocks).
- A link to the personal repository as soon as it is ready.
- The public rubric with criteria and points: what the points are for is visible before the work starts.
- The personal variant number and its statement.
- The deadline with any personal extension applied.
- A clear message instead of an empty page when the assignment content is temporarily unavailable.
Submitting work
- “Submit for review” and “Resubmit” buttons after revision; when submission is not possible, the button explains why.
- Submission is recorded automatically from the code-hosting event, with no manual steps.
- Work after the deadline is accepted and marked “late”; there are no automatic penalties, the decision is the teacher's.
- Unlimited revisions until the teacher confirms the grade.
- Only a neutral notice with a link into the system goes to the pull request: no points, no feedback text.
- Manual linking of a pull request as a fallback.
- A report by rubric sections right in the system, on a separate tab of the submission page.
- The report draft is saved automatically while typing.
- Preview of a section in rendered form and return to editing.
- Report attachments: images and text files, up to 5 MB per file and 25 MB in total.
- A “section unchanged” mark for sections that needed no edits.
- Report submission with confirmation; “draft” and “submitted” badges with the date.
- The automated review waits for the report to be submitted and does not start earlier.
Review status and feedback
- Clear submission statuses: submitted, checking, reviewed, needs revision, graded.
- A timeline of review steps with submission and grading dates.
- A “what to fix” block at the top of the page when work is returned for revision.
- A “submitted late” mark on the submission page.
- A link to the code and its change history.
- Points for every rubric criterion and the teacher's comment; internal rubric fields are not shown to the student.
- Results of the automated review are not shown to the student: it is the teacher's internal tool.
- The system remembers that feedback was opened and clears the unread indicator.
- After work is returned for revision it gets its own resubmission deadline, shown on the submission page.
Grades
- Grades table: course, task, points, maximum, date.
- Summary: average percentage, graded out of assigned, best result.
- From a table row to the detailed feedback on the submission.
- Feedback notifications inside the system, no email campaigns.
For the lecturer
Courses
- The list of courses the lecturer is attached to: name, repository, number of tasks, current version, status (draft, published, archived).
- Search by name and a filter by course status.
- Course card: repository, version, number of tasks, list of lecturers, code-hosting icon.
- Course structure check before publishing: a report of found tasks and errors.
- Publishing a course version: tasks and rubrics are loaded into the system and become available for assignment.
- An “unpublished changes” indicator relative to the current version.
- Creating a new task with one form: the system scaffolds the required files and opens a pull request.
- A list of pending tasks, created but not yet merged, with links to their pull requests.
- Editing task details: title, order in the list, archiving.
- Viewing a task in the system: guide, report template, rubric, sample solutions.
- Editing task text files in the interface; the change goes out as a pull request, never straight into the course.
- A banner with a link to the open pull request after any change.
- Content assistant: a short topic description turns into a draft task with guide, handbook and rubric.
- Rubric assistant: criteria and points proposed from the text of a finished task.
- An assistant draft is never published on its own: it arrives as a proposal the lecturer edits and accepts.
- Configuring the course's automated checks: choosing from ready templates, previewing, applying through a pull request.
- Visibility of which templates are applied and how many custom check files were added on top.
Tasks and rubrics
- Task rubric: criteria with name, description, maximum points and kind of check, automatic or manual.
- The rubric total is computed and validated at publishing.
- Private grader instructions are visible to the teacher only and never reach the student.
- Bonus points for a task as a separate block.
- Individual task variants.
- The public part of the rubric, criteria and weights, is visible to the student.
- The rubric is snapshotted at assignment time: later course edits do not change what was already issued.
Assignments
- Assigning tasks to a group with one schedule form: course, set of tasks, group, a deadline per task.
- Only published courses and only groups attached to the lecturer can be assigned.
- The participant list is fixed at assignment time: moving a student to another group does not break history or submitted work.
- A personal repository with a starter is created automatically for every participant; the student sees the task at once, the repository when ready.
- Repository readiness per student: ready, preparing, error; a retry for those whose repository failed.
- Participant resync: adding those who joined the group after the start.
- An individual deadline extension for a specific student, marked in the participants table.
- Changing the deadline for the whole group at once.
- Closing an assignment as an explicit action from the list.
- Deleting a mistakenly created assignment while nobody has submitted yet.
- Every assignment change is logged: who changed what and when.
- Assignments table: course, task, group, deadline, participants, submitted, awaiting review, status; filters by course, group and status.
- Summary counters of repository readiness and a link to the students' submissions.
- The assistant's review model is chosen per stream or per individual task; without a choice, the default model applies.
- Stream progress matrix: students and tasks with their statuses, a summary per student, export to CSV.
Review queue
- A work queue per task: student, link to the submission, status, automated check result, grade, last update.
- A counter of submissions awaiting the teacher's decision and a filter by status.
- A “late” mark in the queue.
- The lecturer sees only the submissions of their own groups.
- A unified “Review” queue: all submissions across all of the lecturer's tasks in one list, with filters and counters.
Assistant review
- The automated review starts on its own, with a delay, so it does not fire on every small push.
- A “review postponed until …” badge with a button to run it immediately.
- Review statuses: queued, running, done, needs attention, error.
- A preliminary sum of automatic points right in the queue.
- A failed review is shown with its reason and a restart button.
- A “needs manual attention” mark on results that did not pass the quality filter.
- Hints per criterion: proposed points, confidence level, comment and references to evidence in the code.
- Low-confidence criteria are highlighted so the teacher looks at them first.
- An “apply assistant points” button fills all fields at once, keeping them editable.
- A comment hidden by the safety filter shows why: a match with the reference solution or with the grader instructions, and the matched fragment.
- The text of the student's structured report is passed to the assistant as context.
- Review spending is capped by a daily budget per course; the teacher can still start a review beyond the budget.
- The assistant's review can be restarted even after a finished result, as long as the work is not graded; the model that ran it is shown next to the result.
Grading
- Grading screen: rubric criteria with point fields and a check that a score does not exceed the maximum.
- Next to each criterion, a collapsible section of the student's report with attachment thumbnails.
- A text comment to the student.
- Confirming the final grade: the submission becomes “graded” and a neutral notice goes to the pull request.
- Returning work for revision with a mandatory comment.
- Correcting an already confirmed grade with a mandatory reason.
- Reopening a graded submission for another review with a mandatory reason.
- Who confirmed or changed a grade, and when, is written to the audit log.
- The final score and the maximum are shown after confirmation.
- The “submitted late” mark can be cleared or restored for an individual submission, with a reason.
For the course maintainer
Courses and repositories
- Course registration with one form: a token (provider and organisation come from it), repository name, title, description; the final prefixed name is shown before saving.
- Creation of a private course repository with an initial commit; repeated registration is safe.
- The course token is optional: when empty, the system token is used.
- All courses on one page with search and a status filter.
- Assigning teaching groups to a lecturer: checkboxes per group, “select all”, a counter of assigned groups.
- Lecturers of a course are assigned and removed right in the course card.
Review and publishing
- Review queue: open merge requests across all courses (course, author, number, file count, date) with search by course, author and title.
- A “workflows” label on requests that touch automated-check files.
- Approve or request changes with a comment; counters of approvals and change requests.
- Merging through the system only after approval, or by a person who is not the author.
- Publishing is rejected when changes reached the main branch without approval; the gate works even where branch protection is unavailable.
- Structural check at publishing: the guide is present, the rubric is valid, the points add up, the private folder is not copied to students.
- A secrecy boundary at the grading folder: reference solution, grader instructions and hidden tests never leave the course repository.
- A course version is a git tag; content under a tag is immutable, assignments already issued do not change.
- Reviews and merges are recorded in the audit log.
Central CI checks
- One central repository of automated checks per organisation; one-click deployment, safe to repeat.
- A starter set of seven checks: submission pre-check, structure lint, smoke tests, leaked-secret search, broken links, content lint, request labeller.
- The secret search scans history, not only current files.
- A status card: configured, deployed, current release, floating tags, open requests; a “what is missing” diagnosis linking to settings.
- Viewing check files and editing through a merge request into a service branch; a queue of the central repository's requests with the same review gate.
- A release with a level choice (major, minor, patch): the exact tag is set, the floating one moves automatically.
- A version matrix by course: current, outdated, legacy format, no checks, error.
- One-click course migration to a new version: a request changing only version references; for GitLab, a switch without a request.
- Course and student repositories hold thin stubs pointing at the floating tag: fixes arrive without commits to every repository.
- Without a central repository the built-in templates apply; the preview shows which ones are in use.
- Token separation: one for edits and releases, another only for deployment.
- Deployment, edits, releases and migrations are recorded in the audit log.
System settings
- A single settings page; tokens and providers are picked from lists, not typed as identifiers.
- Default role for new users; default GitHub organisation and GitLab group.
- Name prefixes for course repositories and students' personal repositories.
- A system token for course content with an override per course.
- Delay before the automated review, daily token budget per course, default model and a fallback model, interval of the fallback submission poll.
- Publishing gate: mandatory approval, or off for a lecturer working alone.
- Central check settings: provider, repository name, tokens; the CI configuration path for personal GitLab projects.
- Warnings about references to deleted or revoked tokens right on the page; every change goes to the audit log as an “old → new” pair.
For the administrator
Users
- List: login, full name, email, role, groups, status, date; search, filters by role and status, sorting, pagination.
- Creating a user with one form: email, login, full name, password, role; GitHub and GitLab accounts, student ID number.
- Case-insensitive uniqueness of email and login.
- Bulk CSV import: preview, highlighting of invalid rows, import of valid rows only, a per-row report; up to 500 rows; protection against CSV injection; a row without a password creates a user with an invitation link.
- Editing: full name, login, email, role, code-hosting accounts, student ID; a role change takes effect immediately.
- One account per code provider: GitHub and GitLab at the same time.
- Password reset: a temporary password shown once, a change at the next sign-in is mandatory.
- Deactivation with an explanation of consequences instead of deletion; data is kept; reactivation with the same button.
- The last and the initial administrator are protected from deactivation and demotion.
- A deactivated student: history is kept, they are not added to new assignments, already submitted work can be graded.
- Access is granted by an invitation link from an email instead of a temporary password; the user card shows the invitation status.
Groups
- Group list: name, type, member count, owner; search and a filter by type.
- Creation: a unique name and a type, teaching or custom; a student belongs to at most one teaching group.
- Editing the name and type on the group page with a warning when the type changes.
- Archiving instead of deletion with the member count shown; unarchiving with one button.
- Members: adding with search, removal with confirmation, owner assignment; the owner manages the membership.
- Bulk adding of up to 100 people at once with a role filter and two-step confirmation.
- Members of a teaching group can be split into subgroups; a task is assigned to the whole group or to a single subgroup with its own deadline.
Code-hosting tokens and model keys
- Code-hosting tokens: GitHub or GitLab, self-hosted instance address, organisation or group, a note on permissions, expiry date.
- Encrypted storage only, masked in lists; validation by a test call to the provider, including access to the organisation.
- Several tokens for different organisations; a warning 14 days before expiry.
- In-place rotation without re-linking courses.
- Revocation as an emergency switch: immediate and irreversible, with the affected courses and settings shown; anything revoked is rejected everywhere with an explicit error.
- Deletion only after revocation and only when the token is used nowhere.
- Model keys: provider (including OpenRouter with a fallback model and a data-handling policy), default model, limit, expiry; encryption, masking, validation by a test call.
- The same rotation, revocation and deletion rules for model keys; a revoked default key makes the review explicitly non-working instead of silently switching it off.
- On first start the system creates a local stub key by itself: the review pipeline works without an external model.
- Creation, rotation, revocation and deletion are recorded in the audit log.
Audit log
- Log: time, action, who, on what, details; administrators only.
- Filters by action, actor, target and dates; pagination, newest first.
- Append-only: records cannot be edited or deleted through the interface or the API.
- What gets in: sign-ins and failed attempts with reason and address; users, settings, tokens; assignments, grades, authoring and review, checks, synchronisation, report submissions.
- Code-hosting synchronisation writes one summary event with counters.
Code-hosting synchronisation
- Synchronisation page: choice of provider and token.
- A drift report: matches, present here but missing in the code host, present there but missing here.
- Apply invites the missing members into the organisation or group; a repeated run is safe; a dry run sends no invitations.
- A result with counters and a status per operation; synchronisation is one-way, from the system to the code host.
SSO / OIDC
- OIDC and LDAP sign-in providers: creation, editing, activation and deactivation without deleting the configuration.
- OIDC: issuer, client id and secret, scopes, endpoint overrides, a roles claim; secrets are stored encrypted.
- A “Test” button: discovery, JWKS, token endpoint; for LDAP a test bind.
- Provider buttons on the login page appear according to provider activity.
- Authorization Code with PKCE, state and nonce, full ID token validation; provider tokens are handled on the server only.
- Auto-linking of an existing user by verified email; auto-creation at first sign-in with login collision resolution.
- Role mapping from a groups claim; the role is refreshed at every sign-in; the last-administrator protection applies here too.
- Enforced SSO: password sign-in is rejected for everyone except administrators.
- LDAP provider: address, bind DN, search base and filter, attribute mapping, LDAPS by default.
- Auto-linking of the code-hosting account from a provider claim.
- A shared Keycloak realm for the system and GitLab: one password for both; a script to migrate existing users into Keycloak.
Integrations and operations
AI module
- A model provider with structured output; a local stub for development; without a key the pipeline runs in manual-review mode.
- The model only returns a breakdown in the given schema and does not execute code; execution happens only in CI without system secrets; model keys are stored encrypted on the server and are not sent to the browser.
- An output filter: overlaps between feedback and the reference solution or grader instructions are removed, and the review is marked “needs attention”.
- The comment per criterion is length-limited; free-form model text is not published.
- CI gate: when the automated check is red, the model does not run; missing token permissions produce an explicit error, not a green pass.
- Delayed start, daily budget, retries with increasing delays; when attempts run out, the work goes to manual review and the pipeline does not stall.
Deployment and operations
- Docker Compose: API, worker, frontend, PostgreSQL; migrations apply automatically at start; a profile with Keycloak and OpenLDAP.
- Readiness checks and a health endpoint; Prometheus metrics for the API and the worker.
- The worker is a separate process of the same code base: a queue in PostgreSQL without a broker, retries, periodic jobs.
- A fallback poll of open merge requests as insurance against a lost webhook or the absence of a public address.
- Two-stage images, processes without root; configuration through environment variables; secrets per profile.
- A verification script with local, stand and prod profiles: pytest, frontend unit tests, E2E, an SSO run, a live run against the code host, production smoke tests.
Security
- Argon2 passwords; a short access token and a refresh token with rotation; HttpOnly cookies; sign-out revokes the session.
- Sign-in attempt limits per address and per email; X-Forwarded-For is trusted only from listed subnets.
- Security headers on every response: nosniff, frame denial, Referrer-Policy, CSP; HSTS in production; CORS by allow-list.
- Webhooks: HMAC-SHA256 for GitHub, a secret token for GitLab, constant-time comparison, rejection before the body is parsed.
- All secrets in the database are encrypted: code-hosting tokens, model keys, client secrets, the LDAP password.
- Only the login goes to the code host: no full name, no email, no grades.
- Student isolation: private personal repositories, other students' work is not visible; private course content is never copied to a student.
- No hard deletion; the audit log is append-only.
- Containers without root; static security analysis and dependency audit before every commit.