Skip to content

Backend: Services and API

OpenAPI and API Tools

The OpenAPI specification is the contract between the backend and clients and is generated directly from Go annotations. A test compares the spec against the registered routes to detect drift early on.

  • Specification: app/backend/api/swagger.yaml (JSON: app/backend/api/swagger.json)
  • Swagger UI: https://api.sysdf-rooms.f4.htw-berlin.de/swagger/index.html (local: http://localhost:8081/swagger/index.html)
  • Generation of specs: swag init -g cmd/rooms/main.go -o api
  • Swagger host is set at runtime from swagger_host or server_host/server_port.
  • Bruno collection for API calls: app/backend/api/bruno
  • Test for specification consistency: app/backend/internal/api/v1/router/router_openapi_test.go

Authentication and Authorization

Authentication is based on JWTs issued during login. Authorization is performed via permissions that are loaded into the context during the request and used by the middleware and controllers.

Login/Token

When logging in, a JWT is generated that contains the user as uuid and sub. This token must be sent with every protected API request and is both signed and checked for blacklist entries. Token validity can be configured via environment variables (jwt_valid_duration_in_h and refresh_token_valid_duration_in_days).

  • POST /v1/session/login returns JWT (ES256).
  • Token is sent as Authorization: Bearer <token>.
  • Alternatively, token as a query parameter (e.g., for EventSource connections which do not support custom headers).

Logout/Blacklist

Logout stores the token in Redis so that it is immediately invalidated without having to wait for token expiration. The middleware checks this blacklist with every request.

  • DELETE /v1/session/logout saves tokens in Redis.
  • AuthRequired validates JWT signature and checks Redis blacklist.

Permissions

Permissions are loaded from the roles of the logged-in user. The middleware sets context flags that controllers can use for finer logic (e.g., own data vs. all data). For a complete list of all available permissions, see the Permissions Overview.

  • PermissionMiddlewareWithoutBypass: blocks requests without permission.
  • PermissionMiddlewareWithBypass: stores flags (hasPermission_*) in the context, but does not block.
  • Controllers use flags for “self vs. all” logic (e.g., tasks/events).

Services and Endpoints (API /v1)

The API is divided into logically separate services. Each service encapsulates a specific area, with permissions enforced in the router layer and controllers triggering DB operations.

User

The user service covers self-service, admin management, and verification. When creating a user, a verification token is stored and an email is sent.

  • GET /user/me, PATCH /user/me, DELETE /user/me
  • POST /user (create user, email verification), GET /user, GET /user/:uuid
  • PATCH /user/:uuid, DELETE /user/:uuid
  • User roles: POST /user/roles, PATCH /user/roles, DELETE /user/roles
  • Email verification: GET /user/verify?token=...
  • Password check: POST /user/me/validate-password

Role/Permission

Roles can be created, customized, and deleted, provided that the caller passes the hierarchy and permission checks. Permissions are read-only and are managed centrally.

  • Roles: GET /roles, POST /roles, GET /roles/:uuid, PATCH /roles/:uuid, DELETE /roles/:uuid
  • Role permissions: PATCH /roles/:uuid/permissions, DELETE /roles/:uuid/permissions
  • Permissions read-only: GET /permissions, GET /permissions/:uuid

Session

Sessions are JWT-based and do not include a server-side session database. Logout is therefore an explicit Redis blacklisting step.

  • POST /session/login
  • DELETE /session/logout

Room

Rooms are the center of planning. The room preview renders the current display using the Python renderer without generating new QR codes.

  • GET /rooms, POST /rooms, GET /rooms/:uuid, PUT /rooms/:uuid, DELETE /rooms/:uuid
  • GET /rooms/:uuid/preview (Renderer Preview)
  • POST /rooms/:uuid/clean (RoomStatus)
  • GET /rooms/:uuid/users, POST /rooms/:uuid/users, DELETE /rooms/:uuid/users/:user_uuid
  • GET /rooms/:uuid/checkin, GET /rooms/:uuid/qr-codes

Display

Displays register with their MAC address and API key. The content endpoint only delivers new data if the rendered hash has changed.

  • GET /displays, POST /displays, GET /displays/:uuid, PUT /displays/:uuid, DELETE /displays/:uuid
  • GET /displays/room/:room_uuid
  • GET /displays/:uuid/preview
  • GET /displays/:uuid/content (with header X-Mac-Address, X-API-Key)
  • GET /displays/handshake/:mac (hardware sync)

Schedule (Tasks/Events/Calendar)

The Schedule module manages tasks/events and types and provides a combined calendar view for the dashboard. Optionally, check-in histories can be included in the task responses.

  • Tasks: GET /tasks, POST /tasks, GET /tasks/:uuid, PUT /tasks/:uuid, DELETE /tasks/:uuid
  • Task Types: GET /task-types, POST /task-types, PATCH /task-types/:uuid, DELETE /task-types/:uuid
  • Events: GET /events, POST /events, GET /events/:uuid, PUT /events/:uuid, DELETE /events/:uuid
  • Event Types: GET /event-types, POST /event-types, PATCH /event-types/:uuid, DELETE /event-types/:uuid
  • Calendar: GET /calendar, GET /calendar/events, GET /calendar/tasks

CheckIn

CheckIns are the interface for QR-based actions. They validate QR codes against their validity window and connect the action to the executing user.

  • POST /checkin (via QR code or task)
  • GET /checkin, GET /checkin/:uuid, DELETE /checkin/:uuid
  • GET /checkin/me
  • GET /tasks/:uuid/checkin and GET /rooms/:uuid/checkin

QR codes

QR codes always belong to a Room (required) and optionally to a Task. They can be generated explicitly via the API or implicitly via the renderer. When a check-in is performed, the QR code is referenced by the CheckIn record. Expired, unused codes are cleaned up by a scheduler.

  • GET /qr-codes, GET /qr-codes/active
  • POST /qr-codes, GET /qr-codes/:uuid, PUT /qr-codes/:uuid, DELETE /qr-codes/:uuid
  • Room/Task views: GET /rooms/:uuid/qr-codes, GET /tasks/:uuid/qr-codes

Health

Health is a simple liveness endpoint used by monitoring or load balancers.

  • GET /health

Renderer Flow (Display Content)

Display content generation is deliberately idempotent and cache-friendly. A hash prevents unnecessary payloads and reduces the load on the renderer.

  1. Display requests /displays/:uuid/content (MAC + API key in header).
  2. Backend validates and renders via Python.
  3. Hash is calculated and stored in Display.LastRenderHash.
  4. If hash is unchanged and no force_refresh, 304 is delivered.
  5. Preview endpoints render without new QR codes (read-only).

Validation and error handling

Validation is implemented centrally via middleware and reduces duplicate code in controllers. Errors are returned in a structured manner so that frontend clients can display field errors specifically.

  • ValidateJSON, ValidateURI, ValidateQuery bind and validate requests.
  • Errors are bundled as an errors array (HTTP 400).
  • Controllers return specific status codes (404, 409, 403).