{ "schemes": [], "swagger": "2.0", "info": { "description": "REST API for SparkProctoring — proctoring session management, telemetry, and video streaming.", "title": "SparkProctoring API", "contact": {}, "version": "1.0" }, "host": "sparkguardian.ru", "basePath": "/api/v1", "paths": { "/me": { "get": { "security": [ { "ForwardAuth": [] } ], "description": "Returns the authenticated user's profile.", "produces": [ "application/json" ], "tags": [ "auth" ], "summary": "Get current user info", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/handler.MeResponse" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } } } } }, "/sessions": { "get": { "security": [ { "ForwardAuth": [] } ], "description": "Paginated list of all sessions with summary stats.", "produces": [ "application/json" ], "tags": [ "sessions" ], "summary": "List proctoring sessions", "parameters": [ { "type": "integer", "description": "Max results (default 50, max 100)", "name": "limit", "in": "query" }, { "type": "integer", "description": "Offset (default 0)", "name": "offset", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/handler.SessionListResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } } } }, "post": { "security": [ { "ForwardAuth": [] } ], "description": "Only teachers and admins may create sessions. Returns session_key for agent auth.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "sessions" ], "summary": "Create a proctoring session", "parameters": [ { "description": "Session title", "name": "body", "in": "body", "required": true, "schema": { "$ref": "#/definitions/handler.CreateSessionRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/handler.CreateSessionResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } } } } }, "/sessions/{id}": { "get": { "security": [ { "ForwardAuth": [] } ], "description": "Returns session info, stream metadata, and event counts.", "produces": [ "application/json" ], "tags": [ "sessions" ], "summary": "Get session details", "parameters": [ { "type": "integer", "description": "Session ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/handler.SessionDetailResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } } } } }, "/sessions/{id}/events": { "get": { "security": [ { "ForwardAuth": [] } ], "description": "Downloads encrypted .bin chunks from S3, decrypts, and returns parsed events with optional time range filtering.", "produces": [ "application/json" ], "tags": [ "telemetry" ], "summary": "Get parsed telemetry events", "parameters": [ { "type": "integer", "description": "Session ID", "name": "id", "in": "path", "required": true }, { "type": "integer", "description": "Start timestamp (Unix ms)", "name": "from", "in": "query" }, { "type": "integer", "description": "End timestamp (Unix ms)", "name": "to", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/handler.ParsedEventsResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } } } } }, "/sessions/{id}/fingerprint/full": { "get": { "security": [ { "ForwardAuth": [] } ], "produces": [ "application/json" ], "tags": [ "fingerprint" ], "summary": "Get fingerprint full snapshot", "parameters": [ { "type": "integer", "description": "Session ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK" }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } } } } }, "/sessions/{id}/fingerprint/heartbeats": { "get": { "security": [ { "ForwardAuth": [] } ], "produces": [ "application/json" ], "tags": [ "fingerprint" ], "summary": "Get fingerprint heartbeats", "parameters": [ { "type": "integer", "description": "Session ID", "name": "id", "in": "path", "required": true }, { "type": "integer", "description": "Start timestamp (Unix ms)", "name": "from", "in": "query" }, { "type": "integer", "description": "End timestamp (Unix ms)", "name": "to", "in": "query" }, { "type": "integer", "description": "Max entries to return", "name": "limit", "in": "query" } ], "responses": { "200": { "description": "OK" } } } }, "/sessions/{id}/fingerprint/summary": { "get": { "security": [ { "ForwardAuth": [] } ], "produces": [ "application/json" ], "tags": [ "fingerprint" ], "summary": "Get fingerprint summary", "parameters": [ { "type": "integer", "description": "Session ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK" } } } }, "/sessions/{id}/playlist/{stream_type}.m3u8": { "get": { "security": [ { "ForwardAuth": [] } ], "description": "Returns M3U8 playlist for a session's video stream.", "produces": [ "application/vnd.apple.mpegurl" ], "tags": [ "streaming" ], "summary": "Get HLS playlist", "parameters": [ { "type": "integer", "description": "Session ID", "name": "id", "in": "path", "required": true }, { "enum": [ "screen", "webcam" ], "type": "string", "description": "Stream type", "name": "stream_type", "in": "path", "required": true } ], "responses": { "200": { "description": "OK" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } } } } }, "/sessions/{id}/segment/{stream_type}/{chunk_idx}.ts": { "get": { "security": [ { "ForwardAuth": [] } ], "description": "Proxies a .ts video segment from S3.", "produces": [ "video/mp2t" ], "tags": [ "streaming" ], "summary": "Get video segment", "parameters": [ { "type": "integer", "description": "Session ID", "name": "id", "in": "path", "required": true }, { "enum": [ "screen", "webcam" ], "type": "string", "description": "Stream type", "name": "stream_type", "in": "path", "required": true }, { "type": "integer", "description": "Chunk index", "name": "chunk_idx", "in": "path", "required": true } ], "responses": { "200": { "description": "OK" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } } } } }, "/sessions/{id}/telemetry": { "get": { "security": [ { "ForwardAuth": [] } ], "description": "Returns all telemetry events for a session.", "produces": [ "application/json" ], "tags": [ "telemetry" ], "summary": "List telemetry events", "parameters": [ { "type": "integer", "description": "Session ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { "$ref": "#/definitions/handler.TelemetryEvent" } } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } } } } }, "/upload": { "post": { "security": [ { "BearerAuth": [] } ], "description": "Upload .ts (video) or .bin (event) file for a session. Max 64 MB.", "consumes": [ "multipart/form-data" ], "tags": [ "agent" ], "summary": "Upload a video or event chunk", "parameters": [ { "type": "integer", "description": "Session ID", "name": "session_id", "in": "formData", "required": true }, { "type": "integer", "description": "Chunk index", "name": "chunk_idx", "in": "formData", "required": true }, { "enum": [ "screen", "webcam" ], "type": "string", "description": "Stream type (default: screen)", "name": "stream_type", "in": "formData" }, { "type": "file", "description": "Chunk file (.ts or .bin)", "name": "file", "in": "formData", "required": true } ], "responses": { "200": { "description": "OK" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/handler.ErrorResponse" } } } } } }, "definitions": { "handler.CreateSessionRequest": { "type": "object", "properties": { "title": { "type": "string", "example": "Экзамен по ОС" } } }, "handler.CreateSessionResponse": { "type": "object", "properties": { "created_at": { "type": "string", "example": "2026-04-05T12:00:00Z" }, "id": { "type": "integer", "example": 1 }, "session_key": { "type": "string", "example": "1" }, "status": { "type": "string", "example": "pending" }, "title": { "type": "string", "example": "Экзамен по ОС" } } }, "handler.ErrorResponse": { "type": "object", "properties": { "code": { "type": "string", "example": "NOT_FOUND" }, "error": { "type": "string", "example": "session not found" } } }, "handler.MeResponse": { "type": "object", "properties": { "email": { "type": "string", "example": "teacher@example.com" }, "id": { "type": "integer", "example": 1 }, "role": { "type": "string", "example": "teacher" } } }, "handler.ParsedEvent": { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "integer" } }, "event_type": { "type": "string", "example": "keyboard" }, "timestamp": { "type": "integer", "example": 1711360200000 } } }, "handler.ParsedEventsResponse": { "type": "object", "properties": { "count": { "type": "integer", "example": 42 }, "events": { "type": "array", "items": { "$ref": "#/definitions/handler.ParsedEvent" } }, "session_id": { "type": "integer", "example": 1 } } }, "handler.SessionDetailResponse": { "type": "object", "properties": { "session": { "$ref": "#/definitions/handler.SessionSummary" }, "streams": { "type": "array", "items": { "$ref": "#/definitions/handler.StreamInfo" } } } }, "handler.SessionListResponse": { "type": "object", "properties": { "limit": { "type": "integer", "example": 50 }, "offset": { "type": "integer", "example": 0 }, "sessions": { "type": "array", "items": { "$ref": "#/definitions/handler.SessionSummary" } }, "total": { "type": "integer", "example": 5 } } }, "handler.SessionSummary": { "type": "object", "properties": { "chunks_total": { "type": "integer", "example": 42 }, "ended_at": { "type": "string" }, "events_total": { "type": "integer", "example": 128 }, "id": { "type": "string", "example": "1" }, "started_at": { "type": "string", "example": "2026-04-05T12:00:00Z" }, "status": { "type": "string", "example": "pending" }, "user_id": { "type": "string", "example": "1" } } }, "handler.StreamInfo": { "type": "object", "properties": { "chunk_count": { "type": "integer", "example": 10 }, "duration_ms": { "type": "integer", "example": 60000 }, "playlist_url": { "type": "string", "example": "/api/v1/sessions/1/playlist/screen.m3u8" }, "stream_type": { "type": "string", "example": "screen" } } }, "handler.TelemetryEvent": { "type": "object", "properties": { "created_at": { "type": "string", "example": "2026-04-05T12:00:00Z" }, "event_type": { "type": "string", "example": "keyboard" }, "id": { "type": "integer", "example": 1 }, "payload": { "type": "array", "items": { "type": "integer" } }, "session_id": { "type": "integer", "example": 1 }, "user_id": { "type": "integer", "example": 42 } } } }, "securityDefinitions": { "BearerAuth": { "description": "JWT token with \"Bearer \" prefix", "type": "apiKey", "name": "Authorization", "in": "header" }, "ForwardAuth": { "description": "Authelia Forward Auth — set automatically by Traefik", "type": "apiKey", "name": "Remote-User", "in": "header" } } }