diff --git a/docs/doc_v1.json b/docs/doc_v1.json new file mode 100644 index 0000000..9faa529 --- /dev/null +++ b/docs/doc_v1.json @@ -0,0 +1,587 @@ +{ + "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": { + "/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}/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.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" + } + } +} \ No newline at end of file