Backend API
The Ktor service has separate HTTP boundaries for the SvelteKit frontend, automation clients, manual grading, and deployment health. Do not publish the internal frontend or manual-grading routes directly to browsers.
Internal frontend API
Section titled “Internal frontend API”SvelteKit uses /internal/frontend. Every request includes X-Hanami-Frontend-Secret. Authenticated operations also use Authorization: Bearer <hanami-session-id>.
The route tree generates backend/openapi/frontend.json. Each operation has a stable operationId, one of the session, courses, settings, preferences, feedback, grading, or submissions feature tags, typed request and success responses, and the shared error model. Run these commands after changing a frontend-consumed Ktor contract:
cd backend./gradlew generateFrontendOpenApi generatePublicOpenApi
cd ../frontendbun run openapi:generateCI runs both generators and fails if either committed artifact changes.
Session operations
Section titled “Session operations”| Method and path | Authentication | Result |
|---|---|---|
POST /internal/frontend/sessions |
Frontend service | Validates one A+ token and creates an opaque Hanami session |
GET /internal/frontend/session |
Service and session | Current identity, course roles, and preferences |
DELETE /internal/frontend/session |
Service and session | Revokes the current session |
GET /internal/frontend/courses/all |
Frontend service | Public configured-course navigation data |
All other operations require both credentials. Feature routes cover preferences, course discovery and settings, students and course snapshots, feedback documents, rubrics, grading queues and assessments, and submission content or archives.
The generated specification defines the operations and transport schemas. Frontend feature adapters still validate received JSON with Valibot before returning frontend models.
Errors
Section titled “Errors”Internal errors use this JSON shape:
{ "code": "invalid_csv", "detail": "CSV header must be email;languages;feedbackTags;gradingTags", "requestId": "9cb32531-bab4-4e8e-8887-30dd0d170945"}detail and fieldErrors are optional. Responses omit them when the error code and status are sufficient. Status codes still carry their normal meaning. Revision writes preserve ETag, If-Match, X-Assessment-Revision, and 204 No Content behavior.
Ktor does not include A+ bodies, authenticated upstream URLs, SQL errors, SMTP diagnostics, tokens, cookies, ciphertext, or service credentials in the response.
Limits and transport behavior
Section titled “Limits and transport behavior”- Ktor caps write bodies at 2 MB.
- SvelteKit caps normal JSON responses at 2 MiB and submission-content JSON at 25 MiB.
- Diagnostic error bodies are capped at 4 KiB.
- Archive responses stream through SvelteKit without buffering.
- Redirects from Ktor are rejected by the frontend transport.
- Writes and ambiguous grade delivery are not retried automatically.
X-Request-IDis validated or generated in SvelteKit, forwarded to Ktor, and returned to the browser.
Course settings API
Section titled “Course settings API”/api/v1 is the supported automation API. It accepts the caller’s A+ token and remains separate from browser sessions and the frontend service secret.
The current API exposes course settings. Its deterministic OpenAPI 3.1 document is committed as backend/openapi/public-v1.json and served at GET /api/v1/openapi.json. The public and internal specifications remain separate so automation clients do not inherit browser-session contracts.
The documentation site provides a static OpenAPI reference
with separate pages for each operation. The underlying document is available at
/reference/openapi/public-v1.json. The internal frontend specification is not
published.
See Course settings JSON API for requests, revisions, validation errors, and examples.
Manual-grading API
Section titled “Manual-grading API”Manual-grading routes stay under /api/internal. They use X-Hanami-Manual-Grading-Secret and are intended for the isolated grader and deterministic fixture tooling.
| Method and path | Purpose |
|---|---|
POST /api/internal/manual-grading/capabilities |
Register an encrypted deferred callback capability |
GET /api/internal/manual-grading/capabilities |
List capability metadata for one course and exercise |
DELETE /api/internal/manual-grading/capabilities |
Delete capabilities for one course and exercise |
DELETE /api/internal/manual-grading/capabilities/{submissionId} |
Delete one capability |
GET /api/internal/manual-grading/exercises/{exerciseId}/course |
Resolve the configured course for an exercise |
DELETE /api/internal/manual-grading/assessments |
Reset fixture-owned assessment state |
The callback client rejects redirects, limits diagnostics, validates the allowlisted origin and path, and preserves ambiguous-send state when delivery may have succeeded.
Health and metrics
Section titled “Health and metrics”| Method and path | Purpose |
|---|---|
GET /health/live |
Process liveness |
GET /health/ready |
Database-backed readiness |
GET /metrics |
Prometheus metrics for Ktor, the JVM, and Hikari |
These endpoints are unauthenticated because the backend is expected to stay on the private deployment network. Restrict them at the proxy or firewall if Ktor is reachable elsewhere.