Skip to content

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.

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:

Terminal window
cd backend
./gradlew generateFrontendOpenApi generatePublicOpenApi
cd ../frontend
bun run openapi:generate

CI runs both generators and fails if either committed artifact changes.

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.

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.

  • 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-ID is validated or generated in SvelteKit, forwarded to Ktor, and returned to the browser.

/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 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.

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.