845
docs/doc_v2.json
Normal file
845
docs/doc_v2.json
Normal file
@@ -0,0 +1,845 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user