{ "openapi": "3.1.0", "info": { "title": "Rally Tascas API", "version": "0.1.0" }, "paths": { "/api/rally/v1/team/": { "get": { "tags": [ "Team" ], "summary": "Get Teams", "description": "The team directory.\n\nThis route had no auth dependency at all \u2014 ``curr_user`` was optional\nand only steered the redaction of the next post's name \u2014 so the full\nroster, with every team's progress, was readable by anyone whatever\nthe event had configured. An anonymous caller is now served only while\nthe event publishes to the public (``public_access_enabled`` and\n``show_live_leaderboard``): that pair is what the public scoreboard\nruns on, and closing either one closes this too.\n``show_score_mode`` decides whether the points and ranks come with it.", "operationId": "get_teams", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/ListingTeam" }, "type": "array", "title": "Response Get Teams" } } } } }, "security": [ { "HTTPBearer": [] } ] }, "post": { "tags": [ "Team" ], "summary": "Create Team", "operationId": "create_team", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamCreate" } } }, "required": true }, "responses": { "201": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PrivilegedDetailedTeam" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/team/me": { "get": { "tags": [ "Team" ], "summary": "Get Own Team", "description": "The caller's own team. Gated by ``participant_view_enabled``.\n\nThe team's own screen is the participant view, so the switch that\nturns that view off has to close this too \u2014 it used to be honoured by\nthe SPA's routing alone.", "operationId": "get_own_team", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PrivilegedDetailedTeam" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/team/{id}": { "get": { "tags": [ "Team" ], "summary": "Get Team By Id", "operationId": "get_team_by_id", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PrivilegedDetailedTeam" } } } }, "401": { "description": "Authentication required (User or Team Token)" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "put": { "tags": [ "Team" ], "summary": "Update Team", "operationId": "update_team", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamUpdate" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DetailedTeam" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "delete": { "tags": [ "Team" ], "summary": "Delete Team", "description": "Delete a team. Only admins can delete teams.", "operationId": "delete_team", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "type": "string" }, "title": "Response Delete Team" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/team/{id}/checkpoint": { "put": { "tags": [ "Team" ], "summary": "Add Checkpoint", "operationId": "add_checkpoint", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminCheckPointSelect" } } } }, "responses": { "201": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DetailedTeam" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/team/{id}/photo": { "put": { "tags": [ "Team" ], "summary": "Upload Team Photo", "description": "Upload the team's official photo to R2 and persist its URL.\n\nAllowed for admins/managers (UPDATE_TEAM) or the captain of this team.\nReplaces any previous photo.", "operationId": "upload_team_photo", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Id" } } ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_upload_team_photo" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DetailedTeam" } } } }, "403": { "description": "Not allowed to change this team's photo" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/team/{id}/evaluations": { "get": { "tags": [ "Team" ], "summary": "Get Team Evaluations", "description": "Get evaluations for a specific team.\nAccessible by:\n- The team members themselves (via Team Token or linked NEI account)\n- Staff/Admins/Managers (via NEI account)", "operationId": "get_team_evaluations", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true, "title": "Response Get Team Evaluations" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/checkpoint/": { "get": { "tags": [ "CheckPoint" ], "summary": "Get Checkpoints", "description": "Return visible checkpoints based on settings and the requesting user's role.", "operationId": "get_checkpoints", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/DetailedCheckPoint" }, "type": "array", "title": "Response Get Checkpoints" } } } }, "403": { "description": "Checkpoint map is hidden" } }, "security": [ { "HTTPBearer": [] } ] }, "post": { "tags": [ "CheckPoint" ], "summary": "Create Checkpoint", "operationId": "create_checkpoint", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckPointCreate" } } }, "required": true }, "responses": { "201": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminCheckPoint" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/checkpoint/count": { "get": { "tags": [ "CheckPoint" ], "summary": "Get Checkpoints Count", "description": "Return the total number of checkpoints.", "operationId": "get_checkpoints_count", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "integer", "title": "Response Get Checkpoints Count" } } } }, "401": { "description": "Authentication required" } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/checkpoint/me": { "get": { "tags": [ "CheckPoint" ], "summary": "Get Next Checkpoint", "description": "Return the next checkpoint a team must head to.\n\nStaff/admin bypass redaction (they run the event); a team's own\ntoken is redacted the same as the list endpoint \u2014 this route is not\na way around that.", "operationId": "get_next_checkpoint", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DetailedCheckPoint" } } } }, "401": { "description": "Authentication required (User with Team or Team Token)" } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/checkpoint/teams": { "get": { "tags": [ "CheckPoint" ], "summary": "Get Checkpoint Teams", "description": "If a staff is authenticated, returned all teams that just passed\nthrough a staff's checkpoint.\nIf an admin is authenticated, returned all teams.", "operationId": "get_checkpoint_teams", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "checkpoint_id", "in": "query", "required": false, "schema": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Checkpoint Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ListingTeam" }, "title": "Response Get Checkpoint Teams" } } } }, "401": { "description": "Authentication required" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/checkpoint/reorder": { "put": { "tags": [ "CheckPoint" ], "summary": "Reorder Checkpoints", "description": "Reorder checkpoints by updating their order values.", "operationId": "reorder_checkpoints", "requestBody": { "content": { "application/json": { "schema": { "additionalProperties": { "type": "integer" }, "type": "object", "title": "Checkpoint Orders" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "additionalProperties": { "type": "string" }, "type": "object", "title": "Response Reorder Checkpoints" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/checkpoint/admin/route": { "get": { "tags": [ "CheckPoint" ], "summary": "Get Route Status", "description": "The planning view of the route: drafts included, each post with the\nfields it still lacks. Admin/staff only \u2014 it carries the staff script\nand the challenge brief, which are answers as far as a team is\nconcerned.", "operationId": "get_route_status", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RouteStatus" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/checkpoint/{id}": { "put": { "tags": [ "CheckPoint" ], "summary": "Update Checkpoint", "operationId": "update_checkpoint", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckPointUpdate" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminCheckPoint" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "delete": { "tags": [ "CheckPoint" ], "summary": "Delete Checkpoint", "description": "Delete a checkpoint. Only admins can delete checkpoints.", "operationId": "delete_checkpoint", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "type": "string" }, "title": "Response Delete Checkpoint" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/checkpoint/{id}/clue-image": { "put": { "tags": [ "CheckPoint" ], "summary": "Upload Clue Image", "description": "Upload the clue's picture-riddle to R2 and persist its URL.\n\nSame shape as the team-photo upload: every other image in the app is\nset this way, and expecting an admin to paste an R2 URL by hand was\nthe odd one out. Replaces (and deletes) any previous clue image.", "operationId": "upload_clue_image", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Id" } } ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_upload_clue_image" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DetailedCheckPoint" } } } }, "404": { "description": "Checkpoint not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/user/search": { "get": { "tags": [ "User" ], "summary": "Search Oidc Users", "description": "Search NEI accounts by name, username or email.\n\nWhen the Authentik management API is configured, searches *all* Authentik\naccounts (so people who never logged in still appear); otherwise falls back\nto accounts already mirrored locally after a first OIDC login.", "operationId": "search_oidc_users", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "q", "in": "query", "required": true, "schema": { "type": "string", "title": "Q" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/OidcUserSearchResult" }, "title": "Response Search Oidc Users" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/user/staff-assignments": { "get": { "tags": [ "User" ], "summary": "Get Staff Assignments", "description": "Get rally-staff users and their checkpoint assignments, one page at\na time.\n\nWhen the Authentik management API is configured, members of the staff\ngroup are fetched live and mirrored locally on the fly, so an account\nshows up here as soon as it is added to the group in Authentik, with no\nprior login required. Otherwise falls back to users already mirrored\nlocally (i.e. who have logged in at least once with the staff scope).\n\nThe candidate set is every user who currently holds the rally-staff\nrole \u2014 an Authentik-group membership, not something scoped to any\none rally event \u2014 so it only grows over a deployment's life. `q`\n(matches name or email, case-insensitive) finds one person directly\ninstead of paging through everyone.", "operationId": "get_staff_assignments", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "q", "in": "query", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Q" } }, { "name": "page", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "default": 1, "title": "Page" } }, { "name": "page_size", "in": "query", "required": false, "schema": { "type": "integer", "maximum": 100, "minimum": 1, "default": 20, "title": "Page Size" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Page_RallyStaffAssignmentWithCheckpoint_" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/user/me": { "get": { "tags": [ "User" ], "summary": "Get Me", "description": "Get current user information from the validated authentik token.", "operationId": "get_me", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "additionalProperties": true, "type": "object", "title": "Response Get Me" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/user/{user_id}/checkpoint-assignment": { "put": { "tags": [ "User" ], "summary": "Update Checkpoint Assignment", "description": "Update a user's checkpoint assignment.\nThis creates/updates Rally-specific staff assignments.", "operationId": "update_checkpoint_assignment", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "user_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "User Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckpointAssignmentUpdate" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallyStaffAssignmentWithCheckpoint" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/user/guide-assignments": { "get": { "tags": [ "User" ], "summary": "Get Guide Assignments", "description": "Get rally-guide users and their team assignments, one page at a\ntime.\n\nA guide accompanies one team through the whole route (unlike staff,\nwho are fixed to a post). Mirrors the staff-assignment flow: members\nof the Authentik guide group are fetched live and mirrored locally,\nso an account shows up as soon as it is added to the group, with no\nprior login required.\n\nSame unbounded-candidate-set reasoning as `/staff-assignments` \u2014 see\nits docstring. `q` finds one person directly instead of paging\nthrough everyone.", "operationId": "get_guide_assignments", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "q", "in": "query", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Q" } }, { "name": "page", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "default": 1, "title": "Page" } }, { "name": "page_size", "in": "query", "required": false, "schema": { "type": "integer", "maximum": 100, "minimum": 1, "default": 20, "title": "Page Size" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Page_RallyGuideAssignmentWithTeam_" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/user/{user_id}/guide-team-assignment": { "put": { "tags": [ "User" ], "summary": "Update Guide Team Assignment", "description": "Update a guide user's team assignment.\n\nmirrors the staff-assignment audit trail above -- previously this\nwas the one assignment-mutation endpoint that left no audit record, so\n\"which guide was on which team, and when\" was unrecoverable for an\nincident review.", "operationId": "update_guide_team_assignment", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "user_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "User Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamAssignmentUpdate" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallyGuideAssignmentWithTeam" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/rally/settings": { "get": { "tags": [ "Settings" ], "summary": "View Rally Settings", "description": "View rally settings", "operationId": "view_rally_settings", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallySettingsResponse" } } } } }, "security": [ { "HTTPBearer": [] } ] }, "put": { "tags": [ "Settings" ], "summary": "Update Rally Settings", "description": "Update global rally configuration (admin only).\nArgs:\n settings_in: New settings values\n\nReturns:\n Updated rally settings\n\nRaises:\n 403: If user is not authorized\n 400: If validation fails", "operationId": "update_rally_settings", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallySettingsUpdate" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallySettingsResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/rally/settings/public": { "get": { "tags": [ "Settings" ], "summary": "View Rally Settings Public", "description": "View rally settings (public access - no authentication required)", "operationId": "view_rally_settings_public", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallySettingsResponse" } } } } } } }, "/api/rally/v1/rally/settings/banner": { "put": { "tags": [ "Settings" ], "summary": "Upload Rally Banner", "description": "Upload the event banner image to Cloudflare R2 (admin only).", "operationId": "upload_rally_banner", "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_upload_rally_banner" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallySettingsResponse" } } } }, "400": { "description": "Invalid file" }, "403": { "description": "Not authorized" }, "503": { "description": "R2 storage not configured or upload failed" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/rally/settings/logo": { "put": { "tags": [ "Settings" ], "summary": "Upload Rally Logo", "description": "Upload the event logo image to Cloudflare R2 (admin only).", "operationId": "upload_rally_logo", "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_upload_rally_logo" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallySettingsResponse" } } } }, "400": { "description": "Invalid file" }, "403": { "description": "Not authorized" }, "503": { "description": "R2 storage not configured or upload failed" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/rally/settings/favicon": { "put": { "tags": [ "Settings" ], "summary": "Upload Rally Favicon", "description": "Upload the browser-tab favicon to Cloudflare R2 (admin only). Accepts png/ico/svg.", "operationId": "upload_rally_favicon", "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_upload_rally_favicon" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallySettingsResponse" } } } }, "400": { "description": "Invalid file" }, "403": { "description": "Not authorized" }, "503": { "description": "R2 storage not configured or upload failed" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/rally/settings/regulamento": { "put": { "tags": [ "Settings" ], "summary": "Upload Rally Rules Pdf", "description": "Upload the official regulation PDF to Cloudflare R2 (admin only).", "operationId": "upload_rally_rules_pdf", "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_upload_rally_rules_pdf" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallySettingsResponse" } } } }, "400": { "description": "Invalid file" }, "403": { "description": "Not authorized" }, "503": { "description": "R2 storage not configured or upload failed" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/versus/pair": { "post": { "tags": [ "Versus" ], "summary": "Create Versus Pair", "description": "Create versus pair", "operationId": "create_versus_pair", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VersusPairCreate" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VersusPairResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/versus/team/{team_id}/opponent": { "get": { "tags": [ "Versus" ], "summary": "Get Team Opponent", "description": "Get a team's opponent", "operationId": "get_team_opponent", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "team_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Team Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VersusOpponentResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/versus/groups": { "get": { "tags": [ "Versus" ], "summary": "List Versus Groups", "description": "Get all versus groups", "operationId": "list_versus_groups", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VersusGroupListResponse" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/versus/groups/{group_id}": { "delete": { "tags": [ "Versus" ], "summary": "Remove Versus Group", "operationId": "remove_versus_group", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "group_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Group Id" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/team/{team_id}/members": { "post": { "tags": [ "Team Members" ], "summary": "Add Team Member", "description": "Add a member to a team.", "operationId": "add_team_member", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "team_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Team Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamMemberAdd" } } } }, "responses": { "201": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamMemberResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "get": { "tags": [ "Team Members" ], "summary": "Get Team Members", "description": "Get all members of a team.", "operationId": "get_team_members", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "team_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Team Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/TeamMemberResponse" }, "title": "Response Get Team Members" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/team/{team_id}/members/{user_id}/link": { "post": { "tags": [ "Team Members" ], "summary": "Link Team Member", "description": "Link a name-only placeholder member to a real NEI (OIDC) account.\n\n``user_id`` is the placeholder (a user row with no authentik_sub); the body\ncarries the Authentik subject of the account chosen via search. If that\naccount has never logged in, a local mirror is created for it. The\nplaceholder's team membership is moved onto the account and the placeholder\nis removed, mirroring the self-service ``/profile/claim`` flow but\nadmin-driven. A participation row is recorded for the event.", "operationId": "link_team_member", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "team_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Team Id" } }, { "name": "user_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "User Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamMemberLink" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamMemberResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/team/{team_id}/members/{user_id}/link-self": { "post": { "tags": [ "Team Members" ], "summary": "Link Self Team Member", "description": "Self-serve variant of ``link_team_member``.\n\nLets whoever holds a team's access code claim a placeholder slot in that\nteam using the NEI (OIDC) account they just logged in with.\n\nThe client can only send a single bearer token per request, and it\nswitches to the OIDC token as soon as this NEI login completes \u2014 so\nteam membership cannot be proven via the (now unavailable) team token\nhere. The caller therefore re-presents the team access code, which is\nwhat binds them to ``team_id``; the OIDC bearer only says *who* they are.\nPlaceholder state alone is not authorization: without the code check any\nauthenticated user could claim any team's open slot.", "operationId": "link_self_team_member", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "team_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Team Id" } }, { "name": "user_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "User Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamMemberLinkSelf" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamMemberResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/team/{team_id}/members/{user_id}": { "delete": { "tags": [ "Team Members" ], "summary": "Remove Team Member", "description": "Remove a member from a team.", "operationId": "remove_team_member", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "team_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Team Id" } }, { "name": "user_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "User Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "type": "string" }, "title": "Response Remove Team Member" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "put": { "tags": [ "Team Members" ], "summary": "Update Team Member", "description": "Update a team member's information.", "operationId": "update_team_member", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "team_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Team Id" } }, { "name": "user_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "User Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamMemberUpdate" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamMemberResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/activities/": { "post": { "tags": [ "Activities" ], "summary": "Create Activity", "description": "Create a new activity", "operationId": "create_activity", "security": [ { "HTTPBearer": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityCreate" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "get": { "tags": [ "Activities" ], "summary": "Get Activities", "description": "Get activities list", "operationId": "get_activities", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "skip", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 0, "default": 0, "title": "Skip" } }, { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "maximum": 1000, "minimum": 1, "default": 100, "title": "Limit" } }, { "name": "checkpoint_id", "in": "query", "required": false, "schema": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0 }, { "type": "null" } ], "title": "Checkpoint Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityListResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/activities/results": { "get": { "tags": [ "Activities" ], "summary": "Get All Activity Results", "description": "Get all activity results (evaluations) with team and activity details.\n\nscoped to the current event and paginated \u2014\nunscoped, this grew without bound across editions and every past\nedition's rows returned on every call.", "operationId": "get_all_activity_results", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "skip", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 0, "default": 0, "title": "Skip" } }, { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "maximum": 1000, "minimum": 1, "default": 200, "title": "Limit" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ActivityResultResponse" }, "title": "Response Get All Activity Results" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/activities/{activity_id}": { "get": { "tags": [ "Activities" ], "summary": "Get Activity", "description": "Get activity by ID", "operationId": "get_activity", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "activity_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Activity Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "put": { "tags": [ "Activities" ], "summary": "Update Activity", "description": "Update an activity", "operationId": "update_activity", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "activity_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Activity Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityUpdate" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "delete": { "tags": [ "Activities" ], "summary": "Delete Activity", "description": "Delete an activity and refresh the scores it was contributing to.", "operationId": "delete_activity", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "activity_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Activity Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "type": "string" }, "title": "Response Delete Activity" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/activities/results/": { "post": { "tags": [ "Activities" ], "summary": "Create Activity Result", "description": "Create a new activity result", "operationId": "create_activity_result", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityResultCreate" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityResultResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/activities/results/{result_id}": { "get": { "tags": [ "Activities" ], "summary": "Get Activity Result", "description": "Get activity result by ID", "operationId": "get_activity_result", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "result_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Result Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityResultResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "put": { "tags": [ "Activities" ], "summary": "Update Activity Result", "description": "Update an activity result", "operationId": "update_activity_result", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "result_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Result Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityResultUpdate" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityResultResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/activities/results/{result_id}/extra-shots": { "post": { "tags": [ "Activities" ], "summary": "Apply Extra Shots", "description": "Apply extra shots bonus to activity result", "operationId": "apply_extra_shots", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "result_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Result Id" } }, { "name": "extra_shots", "in": "query", "required": true, "schema": { "type": "integer", "minimum": 0, "title": "Extra Shots" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "type": "string" }, "title": "Response Apply Extra Shots" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/activities/results/{result_id}/penalty": { "post": { "tags": [ "Activities" ], "summary": "Apply Penalty", "description": "Apply a penalty occurrence count to an activity result, priced\nserver-side the same way as every other penalty.", "operationId": "apply_penalty", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "result_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Result Id" } }, { "name": "penalty_type", "in": "query", "required": true, "schema": { "type": "string", "pattern": "^(vomit|not_drinking)$", "title": "Penalty Type" } }, { "name": "penalty_count", "in": "query", "required": true, "schema": { "type": "integer", "minimum": 1, "title": "Penalty Count" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "type": "string" }, "title": "Response Apply Penalty" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/activities/{activity_id}/ranking": { "get": { "tags": [ "Activities" ], "summary": "Get Activity Ranking", "description": "Get ranking for a specific activity", "operationId": "get_activity_ranking", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "activity_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Activity Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityRanking" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/activities/ranking/global": { "get": { "tags": [ "Activities" ], "summary": "Get Global Ranking", "description": "Get global team ranking", "operationId": "get_global_ranking", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GlobalRanking" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/activities/team-vs/{activity_id}": { "post": { "tags": [ "Activities" ], "summary": "Create Team Vs Result", "description": "Create team vs team activity results", "operationId": "create_team_vs_result", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "activity_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Activity Id" } }, { "name": "team1_id", "in": "query", "required": true, "schema": { "type": "integer", "title": "Team1 Id" } }, { "name": "team2_id", "in": "query", "required": true, "schema": { "type": "integer", "title": "Team2 Id" } }, { "name": "winner_id", "in": "query", "required": true, "schema": { "type": "integer", "title": "Winner Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true, "title": "Match Data" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "type": "string" }, "title": "Response Create Team Vs Result" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/activities/{activity_id}/statistics": { "get": { "tags": [ "Activities" ], "summary": "Get Activity Statistics", "description": "Get statistics for a specific activity", "operationId": "get_activity_statistics", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "activity_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Activity Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true, "title": "Response Get Activity Statistics" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/staff/my-checkpoint": { "get": { "tags": [ "Staff Evaluation" ], "summary": "Get My Checkpoint", "description": "Get the checkpoint assigned to the current staff member", "operationId": "get_my_checkpoint", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DetailedCheckPoint" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/staff/teams": { "get": { "tags": [ "Staff Evaluation" ], "summary": "Get Teams At My Checkpoint", "description": "Get all teams at the staff member's assigned checkpoint", "operationId": "get_teams_at_my_checkpoint", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "items": { "additionalProperties": true, "type": "object" }, "type": "array", "title": "Response Get Teams At My Checkpoint" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/staff/teams/{team_id}/activities": { "get": { "tags": [ "Staff Evaluation" ], "summary": "Get Team Activities For Evaluation", "description": "Get activities for a specific team that can be evaluated by this staff member", "operationId": "get_team_activities_for_evaluation", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "team_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Team Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true, "title": "Response Get Team Activities For Evaluation" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/staff/teams/{team_id}/activities/{activity_id}/evaluate": { "post": { "tags": [ "Staff Evaluation" ], "summary": "Evaluate Team Activity", "description": "Evaluate a team's performance in an activity.\n\nAccepts an optional ``Idempotency-Key`` header. When present, a retry of the\nsame logical submit (same key + payload) replays the stored response instead\nof re-scoring; a reused key with a different payload is rejected with 409.\nSubmits without a key behave exactly as before.", "operationId": "evaluate_team_activity", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "team_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Team Id" } }, { "name": "activity_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Activity Id" } }, { "name": "Idempotency-Key", "in": "header", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Idempotency-Key" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityResultEvaluation" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityResultResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/staff/teams/{team_id}/activities/{activity_id}/evaluate/{result_id}": { "put": { "tags": [ "Staff Evaluation" ], "summary": "Update Team Activity Evaluation", "description": "Update a team's activity evaluation", "operationId": "update_team_activity_evaluation", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "team_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Team Id" } }, { "name": "activity_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Activity Id" } }, { "name": "result_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Result Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityResultStaffUpdate" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActivityResultResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/staff/evaluations/{result_id}/history": { "get": { "tags": [ "Staff Evaluation" ], "summary": "Get Evaluation History", "description": "Audit trail for a single result: every edit and contest, newest first.\n\nManager/admin only \u2014 staff can score but the trail (who overrode whom) is a\ndispute-resolution tool for organizers.", "operationId": "get_evaluation_history", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "result_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Result Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/EvaluationHistoryEntry" }, "title": "Response Get Evaluation History" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/staff/all-evaluations": { "get": { "tags": [ "Staff Evaluation" ], "summary": "Get All Evaluations", "description": "Get all evaluations.\n\nAccessible by staff (filtered to their checkpoint) and by managers\n(all data).", "operationId": "get_all_evaluations", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "checkpoint_id", "in": "query", "required": false, "schema": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Checkpoint Id" } }, { "name": "team_id", "in": "query", "required": false, "schema": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Team Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true, "title": "Response Get All Evaluations" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/rally/duration": { "get": { "tags": [ "Rally Duration" ], "summary": "Get Rally Duration", "description": "Get rally duration and timing information.\n\nReturns:\n Rally timing status including current time, start/end times,\n time remaining/elapsed, and progress percentage.", "operationId": "get_rally_duration", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "additionalProperties": true, "type": "object", "title": "Response Get Rally Duration" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/rally/team-duration/{team_id}": { "get": { "tags": [ "Rally Duration" ], "summary": "Get Team Rally Duration", "description": "Get rally duration information for a specific team.\n\nArgs:\n team_id: ID of the team to get duration info for\n\nReturns:\n Team-specific rally duration information.", "operationId": "get_team_rally_duration", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "team_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Team Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true, "title": "Response Get Team Rally Duration" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/rally/pace-ranking": { "get": { "tags": [ "Rally Duration" ], "summary": "Get Pace Ranking", "description": "Public scoreboard pace, redacted alongside hidden score standings.", "operationId": "get_pace_ranking", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaceRanking" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/team-auth/login": { "post": { "tags": [ "Team Auth" ], "summary": "Team Login", "description": "Authenticate a team using their access code.\nReturns a JWT token for subsequent requests.", "operationId": "team_login", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamLoginRequest" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamLoginResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/team-auth/verify": { "get": { "tags": [ "Team Auth" ], "summary": "Verify Token", "description": "Verify a team JWT token.\nReturns the team data if valid.", "operationId": "verify_token", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamTokenData" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/team-auth/refresh": { "post": { "tags": [ "Team Auth" ], "summary": "Refresh Team Token", "description": "Refresh a team JWT token.\nTakes an existing team token and returns a new one with extended expiration,\nup to an absolute session lifetime (TEAM_TOKEN_MAX_LIFETIME_HOURS) counted\nfrom the original login.", "operationId": "refresh_team_token", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamLoginResponse" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/team-auth/evaluations/{result_id}/contest": { "post": { "tags": [ "Team Auth" ], "summary": "Contest Evaluation", "description": "Let a team dispute one of *its own* results.\n\nAppends a CONTESTED row to the audit trail with the team's reason. Does not\nchange the score \u2014 it flags the result for an organizer to review. A team\nmay only contest results belonging to itself.", "operationId": "contest_evaluation", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "result_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Result Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContestRequest" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EvaluationHistoryEntry" } } } }, "404": { "description": "Activity result not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/scoreboard/live": { "get": { "tags": [ "Scoreboard" ], "summary": "Get Live Scoreboard", "description": "Return the cached global ranking, recomputing on a cache miss.\n\nWhen the realtime subsystem is disabled there is no cache to read and no\nworker keeping it warm, but the ranking is still a plain DB computation \u2014\nserve it directly from Postgres instead of failing the public view.\n\n``show_live_leaderboard`` gates it: the switch used to hide the\nscoreboard in the SPA while this endpoint served the standings to\nanyone who asked.", "operationId": "get_live_scoreboard", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "items": { "additionalProperties": true, "type": "object" }, "type": "array", "title": "Response Get Live Scoreboard" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/scoreboard/stream": { "get": { "tags": [ "Scoreboard" ], "summary": "Stream Scoreboard", "description": "Server-Sent Events stream that emits a 'refresh' on each leaderboard update.", "operationId": "stream_scoreboard", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/events/stream": { "get": { "tags": [ "Scoreboard" ], "summary": "Stream Rally Events", "description": "Server-Sent Events stream that forwards raw activity_result/team events.\n\nUnlike /scoreboard/stream (which only signals \"leaderboard changed\"), this\nstream forwards each event's type and JSON payload so callers can react to\nthe specific team/activity involved \u2014 e.g. staff-evaluation and\nteam-progress pages invalidating only their own affected queries instead\nof refetching on every unrelated event.\n\nGated on ``show_live_leaderboard`` like the scoreboard itself: the\npayloads it forwards carry the same score changes, so leaving it open\nwould hand out live standings by another name.", "operationId": "stream_rally_events", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/scoreboard/recompute": { "post": { "tags": [ "Scoreboard" ], "summary": "Recompute Classification", "description": "Admin escape hatch: re-price every result with the *current* scoring\nsettings, recompute every team's total and rank, then drop the cached\nleaderboard so the next read is fresh.\n\nThe re-price is the point. Every other path in the system rescores only\nthe rows touched by the write that triggered it, so editing a scoring\nvalue in the admin (a penalty price, the extra-shot bonus, a\nDynamicRule) does not move results that were already scored. This\nendpoint is how that change is applied on purpose, rather than\nsilently mid-event.\n\nIt also remains the recovery path for a recompute that was missed\noutright \u2014 a crash mid-write, a stalled worker, a manual DB edit.", "operationId": "recompute_classification", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "additionalProperties": true, "type": "object", "title": "Response Recompute Classification" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/badges": { "get": { "tags": [ "Badges" ], "summary": "List All Badges", "description": "Every badge awarded across all teams, newest first.", "operationId": "list_all_badges", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/TeamBadgeRead" }, "type": "array", "title": "Response List All Badges" } } } } } } }, "/api/rally/v1/teams/{team_id}/badges": { "get": { "tags": [ "Badges" ], "summary": "List Team Badges", "description": "All badges a single team holds, newest first.", "operationId": "list_team_badges", "parameters": [ { "name": "team_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Team Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/TeamBadgeRead" }, "title": "Response List Team Badges" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/teams/{team_id}/badge-showcase": { "get": { "tags": [ "Badges" ], "summary": "Team Badge Showcase", "description": "The full badge board for a team: active catalogue + what it has earned.\n\nOne request drives the locked/earned grid. ``earned`` collapses to the\nearliest award per badge code (a team may hold a code for several scopes).\nWhen the feature is disabled the board is empty so a direct API hit\nreveals nothing.", "operationId": "team_badge_showcase", "parameters": [ { "name": "team_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Team Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BadgeShowcaseResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/checkpoint/checkin-token": { "get": { "tags": [ "Check-in" ], "summary": "Get Checkin Token", "description": "Mint a rotating check-in QR token for a checkpoint.\n\nStaff get a token for their assigned checkpoint. Admins/managers may pass a\n``checkpoint_id`` to mint (or preview) the QR for any checkpoint they are\nviewing; staff cannot mint for a checkpoint other than their own.", "operationId": "get_checkin_token", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "checkpoint_id", "in": "query", "required": false, "schema": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Checkpoint Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "type": "string" }, "title": "Response Get Checkin Token" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/checkpoint/staff-check-in": { "post": { "tags": [ "Check-in" ], "summary": "Staff Check In", "description": "Staff scans an arriving team's QR (its access code).\n\nPrimary purpose: *identify the team* so staff open the correct evaluation\nfast and without mistakes. Secondary: mark the team's arrival at the staff's\ncheckpoint when it is the team's next post. Tolerant by design \u2014 a re-scan\n(team already here) or an early scan never errors, so it stays usable\nalongside versus/head-to-head flows; it just reports the arrival ``status``.\n\nNot gated by ``SELF_CHECKIN_ENABLED``: that flag governs teams scanning a\ncheckpoint's QR to advance themselves. A staff member scanning a team to\nidentify it and open the right evaluation is the normal staffed flow and\nmust work whether or not self check-in is enabled.", "operationId": "staff_check_in", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StaffCheckinRequest" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StaffCheckinResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/checkpoint/check-in": { "post": { "tags": [ "Check-in" ], "summary": "Check In", "description": "Check the calling team into the checkpoint encoded in the scanned token.", "operationId": "check_in", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckinRequest" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckinResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/events": { "get": { "tags": [ "Events", "Events" ], "summary": "List Events", "description": "List events (newest first). Public \u2014 drives the homepage event selector.", "operationId": "list_events", "parameters": [ { "name": "skip", "in": "query", "required": false, "schema": { "type": "integer", "default": 0, "title": "Skip" } }, { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "default": 100, "title": "Limit" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/RallyEventResponse" }, "title": "Response List Events" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "post": { "tags": [ "Events", "Events" ], "summary": "Create Event", "description": "Create a new event edition (admin/manager only).", "operationId": "create_event", "security": [ { "HTTPBearer": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallyEventCreate" } } } }, "responses": { "201": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallyEventResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/events/{event_id}/configuration-status": { "get": { "tags": [ "Events", "Events" ], "summary": "Event Configuration Status", "operationId": "event_configuration_status", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "event_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Event Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfigurationStatusResponse" } } } }, "404": { "description": "Event not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/events/{event_id}/capabilities": { "patch": { "tags": [ "Events", "Events" ], "summary": "Update Event Capabilities", "operationId": "update_event_capabilities", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "event_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Event Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateEventCapabilitiesRequest" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfigurationStatusResponse" } } } }, "404": { "description": "Event not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/events/{event_id}/change-format": { "post": { "tags": [ "Events", "Events" ], "summary": "Change Event Format", "operationId": "change_event_format", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "event_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Event Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChangeEventFormatRequest" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChangeEventFormatResponse" } } } }, "404": { "description": "Event not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/events/current": { "get": { "tags": [ "Events", "Events" ], "summary": "Get Current Event", "description": "Return the current event (bootstrapping a default one if none exists).", "operationId": "get_current_event", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallyEventResponse" } } } } } } }, "/api/rally/v1/events/{event_id}": { "get": { "tags": [ "Events", "Events" ], "summary": "Get Event", "operationId": "get_event", "parameters": [ { "name": "event_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Event Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallyEventResponse" } } } }, "404": { "description": "Event not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "put": { "tags": [ "Events", "Events" ], "summary": "Update Event", "operationId": "update_event", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "event_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Event Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallyEventUpdate" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallyEventResponse" } } } }, "404": { "description": "Event not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/events/{event_id}/set-current": { "post": { "tags": [ "Events", "Events" ], "summary": "Set Current Event", "description": "Make the given event the sole current edition (admin/manager only).", "operationId": "set_current_event", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "event_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Event Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RallyEventResponse" } } } }, "404": { "description": "Event not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/events/{event_id}/clone-from/{source_event_id}": { "post": { "tags": [ "Events", "Events" ], "summary": "Clone Event Structure", "description": "Seed an empty edition from a previous one (admin/manager only).\n\nCopies structure only \u2014 route, activities, badges, rules, settings.\nTeams and everything they did stay in the source edition.", "operationId": "clone_event_structure", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "event_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Event Id" } }, { "name": "source_event_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Source Event Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CloneStructureResponse" } } } }, "404": { "description": "Event not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/events/{event_id}/rotation-schedule": { "post": { "tags": [ "Events", "Events" ], "summary": "Generate Rotation Schedule", "description": "Generate and persist a round-robin rotation schedule for an Olympic event.\n\nReads the event's current teams and checkpoints, runs the generator, and\nstores the result in RallyEvent.rotation_schedule. Returns the schedule.", "operationId": "generate_rotation_schedule", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "event_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Event Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RotationScheduleResponse" } } } }, "404": { "description": "Event not found" }, "400": { "description": "Rotation schedule cannot be generated for this event" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/profile/me": { "get": { "tags": [ "Profile" ], "summary": "Get My Profile", "description": "Return the caller's profile and participation history.\n\nIf the caller is themselves currently on a team, their participation in the\ncurrent event is recorded lazily so the active edition always shows.", "operationId": "get_my_profile", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProfileResponse" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/profile/history": { "get": { "tags": [ "Profile" ], "summary": "Get My History", "description": "List the caller's past participations (newest first).", "operationId": "get_my_history", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/ParticipationEntry" }, "type": "array", "title": "Response Get My History" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/profile/claimable": { "get": { "tags": [ "Profile" ], "summary": "Get Claimable Members", "description": "List a team's name-only members (by access code) the caller can claim.\n\nThe caller enters their team's access code; this returns the placeholder\nmembers (no linked account) so they can pick which one is them and claim it.", "operationId": "get_claimable_members", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "access_code", "in": "query", "required": true, "schema": { "type": "string", "title": "Access Code" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ClaimableTeam" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/profile/claim/{member_user_id}": { "post": { "tags": [ "Profile" ], "summary": "Claim Membership", "description": "Claim a name-only team member as the caller's own participation.\n\nThe placeholder member (a ``user`` row with no authentik_sub) is merged into\nthe caller's account: its team membership moves to the caller and the\nplaceholder is removed. A participation row is recorded for the event.\n\nThe team's access code must be re-presented: it is the only thing tying\nthe caller to that roster, since the OIDC bearer proves identity but not\nteam membership.", "operationId": "claim_membership", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "member_user_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Member User Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ClaimMembershipRequest" } } } }, "responses": { "201": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ParticipationEntry" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/checkpoint/{checkpoint_id}/media": { "get": { "tags": [ "Checkpoint Media" ], "summary": "List Checkpoint Media", "operationId": "list_checkpoint_media", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "checkpoint_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Checkpoint Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CheckpointMediaResponse" }, "title": "Response List Checkpoint Media" } } } }, "404": { "description": "Checkpoint not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "post": { "tags": [ "Checkpoint Media" ], "summary": "Create Checkpoint Media", "operationId": "create_checkpoint_media", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "checkpoint_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Checkpoint Id" } } ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_create_checkpoint_media" } } } }, "responses": { "201": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckpointMediaResponse" } } } }, "404": { "description": "Checkpoint not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/checkpoint/media/{media_id}": { "put": { "tags": [ "Checkpoint Media" ], "summary": "Update Checkpoint Media", "operationId": "update_checkpoint_media", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "media_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Media Id" } } ], "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_update_checkpoint_media" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckpointMediaResponse" } } } }, "404": { "description": "Media not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "delete": { "tags": [ "Checkpoint Media" ], "summary": "Delete Checkpoint Media", "operationId": "delete_checkpoint_media", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "media_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Media Id" } } ], "responses": { "204": { "description": "Successful Response" }, "404": { "description": "Media not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/checkpoint/{checkpoint_id}/media/reorder": { "post": { "tags": [ "Checkpoint Media" ], "summary": "Reorder Checkpoint Media", "operationId": "reorder_checkpoint_media", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "checkpoint_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Checkpoint Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "array", "items": { "type": "integer" }, "title": "Ordered Ids" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CheckpointMediaResponse" }, "title": "Response Reorder Checkpoint Media" } } } }, "404": { "description": "Checkpoint not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/checkpoint/{checkpoint_id}/guide-indications": { "get": { "tags": [ "Checkpoint Guide Indications" ], "summary": "List Guide Indications", "operationId": "list_guide_indications", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "checkpoint_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Checkpoint Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CheckpointGuideIndication" }, "title": "Response List Guide Indications" } } } }, "404": { "description": "Checkpoint not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "post": { "tags": [ "Checkpoint Guide Indications" ], "summary": "Create Guide Indication", "operationId": "create_guide_indication", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "checkpoint_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Checkpoint Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckpointGuideIndicationCreate" } } } }, "responses": { "201": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckpointGuideIndication" } } } }, "404": { "description": "Checkpoint not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/checkpoint/guide-indications/{indication_id}": { "put": { "tags": [ "Checkpoint Guide Indications" ], "summary": "Update Guide Indication", "operationId": "update_guide_indication", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "indication_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Indication Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckpointGuideIndicationUpdate" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckpointGuideIndication" } } } }, "404": { "description": "Guide indication not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "delete": { "tags": [ "Checkpoint Guide Indications" ], "summary": "Delete Guide Indication", "operationId": "delete_guide_indication", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "indication_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Indication Id" } } ], "responses": { "204": { "description": "Successful Response" }, "404": { "description": "Guide indication not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/checkpoint/{checkpoint_id}/arrive": { "post": { "tags": [ "Checkpoint Arrive" ], "summary": "Arrive At Checkpoint", "operationId": "arrive_at_checkpoint", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "checkpoint_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Checkpoint Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ArriveRequest" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ArriveResponse" } } } }, "400": { "description": "GPS check-in unavailable, missing coordinates, too far from the checkpoint, or a checkpoint the team is not due at yet" }, "404": { "description": "Checkpoint not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/checkpoint/{checkpoint_id}/hints": { "get": { "tags": [ "Checkpoint Hints" ], "summary": "List Checkpoint Hints", "description": "Hints this team already paid for at a checkpoint, plus how many are left.", "operationId": "list_checkpoint_hints", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "checkpoint_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Checkpoint Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamHints" } } } }, "401": { "description": "Authentication required (Team Token)" }, "404": { "description": "Checkpoint not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/checkpoint/{checkpoint_id}/skip": { "post": { "tags": [ "Checkpoint Hints" ], "summary": "Skip Checkpoint", "description": "Give up on this checkpoint: forfeit its score, pay the penalty, move on.\n\nThe way out for a team that cannot solve a riddle. Without it the hint\nladder runs out and the post is theirs for the rest of the event.", "operationId": "skip_checkpoint", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "checkpoint_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Checkpoint Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckpointSkipped" } } } }, "400": { "description": "Not the team's current checkpoint, or already given up" }, "401": { "description": "Authentication required (Team Token)" }, "404": { "description": "Checkpoint not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/team-auth/hints": { "get": { "tags": [ "Checkpoint Hints" ], "summary": "List Team Hints", "description": "Every hint this team has bought across the event, and what it cost.\n\nThe per-checkpoint listing only covers one post; a team that spent\npoints at several has no other way to add them up, since the awards\ncarrying the charges are admin-only.", "operationId": "list_team_hints", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamHintSummary" } } } }, "401": { "description": "Authentication required (Team Token)" } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/checkpoint/{checkpoint_id}/hint": { "post": { "tags": [ "Checkpoint Hints" ], "summary": "Reveal Checkpoint Hint", "description": "Unlock the next hint for this checkpoint and charge the team.", "operationId": "reveal_checkpoint_hint", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "checkpoint_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Checkpoint Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HintReveal" } } } }, "400": { "description": "Not the team's current checkpoint, or no hints left" }, "401": { "description": "Authentication required (Team Token)" }, "404": { "description": "Checkpoint not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/checkpoint/{checkpoint_id}/proximity": { "post": { "tags": [ "Checkpoint Proximity" ], "summary": "Read Checkpoint Proximity", "description": "How close the team is, as a coarse band \u2014 never a metre count.", "operationId": "read_checkpoint_proximity", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "checkpoint_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Checkpoint Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProximityRequest" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProximityReading" } } } }, "400": { "description": "Not enabled, not the team's checkpoint, or no coordinates" }, "401": { "description": "Authentication required (Team Token)" }, "404": { "description": "Checkpoint not found" }, "429": { "description": "Too many proximity checks" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/route-stages": { "get": { "tags": [ "Route Stages" ], "summary": "List Route Stages", "operationId": "list_route_stages", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/RouteStageResponse" }, "type": "array", "title": "Response List Route Stages" } } } } }, "security": [ { "HTTPBearer": [] } ] }, "post": { "tags": [ "Route Stages" ], "summary": "Create Route Stage", "operationId": "create_route_stage", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RouteStageCreate" } } }, "required": true }, "responses": { "201": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RouteStageResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/route-stages/{id}": { "put": { "tags": [ "Route Stages" ], "summary": "Update Route Stage", "operationId": "update_route_stage", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RouteStageUpdate" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RouteStageResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "delete": { "tags": [ "Route Stages" ], "summary": "Delete Route Stage", "description": "Delete a stage. Its posts stay in the route, unstaged \u2014 deleting a\nrule must not delete the places.", "operationId": "delete_route_stage", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "type": "string" }, "title": "Response Delete Route Stage" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/badge-definitions": { "get": { "tags": [ "Badge Admin" ], "summary": "List Badge Definitions", "operationId": "list_badge_definitions", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/BadgeDefinitionResponse" }, "type": "array", "title": "Response List Badge Definitions" } } } } } }, "post": { "tags": [ "Badge Admin" ], "summary": "Create Badge Definition", "operationId": "create_badge_definition", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BadgeDefinitionCreate" } } }, "required": true }, "responses": { "201": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BadgeDefinitionResponse" } } } }, "409": { "description": "Badge code already exists" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/badge-definitions/{id}": { "put": { "tags": [ "Badge Admin" ], "summary": "Update Badge Definition", "operationId": "update_badge_definition", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BadgeDefinitionUpdate" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BadgeDefinitionResponse" } } } }, "404": { "description": "Badge definition not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "delete": { "tags": [ "Badge Admin" ], "summary": "Delete Badge Definition", "operationId": "delete_badge_definition", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Id" } } ], "responses": { "204": { "description": "Successful Response" }, "404": { "description": "Badge definition not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/badge-definitions/{id}/icon": { "post": { "tags": [ "Badge Admin" ], "summary": "Upload Badge Icon", "operationId": "upload_badge_icon", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Id" } } ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_upload_badge_icon" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BadgeDefinitionResponse" } } } }, "404": { "description": "Badge definition not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/badges/award": { "post": { "tags": [ "Badge Admin" ], "summary": "Manual Award Badge", "operationId": "manual_award_badge", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ManualBadgeAwardCreate" } } }, "required": true }, "responses": { "201": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeamBadgeRead" } } } }, "404": { "description": "Badge definition not found" }, "400": { "description": "Badge is inactive" }, "409": { "description": "Team already holds this badge" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/badges/{badge_id}": { "delete": { "tags": [ "Badge Admin" ], "summary": "Revoke Badge", "operationId": "revoke_badge", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "badge_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Badge Id" } } ], "responses": { "204": { "description": "Successful Response" }, "404": { "description": "Badge not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/activities/deferred/{activity_id}/capture": { "post": { "tags": [ "Deferred Judging" ], "summary": "Capture Deferred Result", "operationId": "capture_deferred_result", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "activity_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Activity Id" } }, { "name": "team_id", "in": "query", "required": false, "schema": { "type": "integer", "default": 0, "title": "Team Id" } } ], "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_capture_deferred_result" } } } }, "responses": { "201": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeferredResultResponse" } } } }, "404": { "description": "Activity or team not found, or team of another event" }, "400": { "description": "Activity is not deferred-judged type, or team_id is missing" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/activities/results/{result_id}/judge": { "put": { "tags": [ "Deferred Judging" ], "summary": "Judge Deferred Result", "operationId": "judge_deferred_result", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "result_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Result Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JudgeRequest" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeferredResultResponse" } } } }, "404": { "description": "Result not found" }, "400": { "description": "Result is not pending judgment" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/activities/results/{result_id}/set-team-photo": { "put": { "tags": [ "Deferred Judging" ], "summary": "Set Team Photo From Result", "description": "Promote one of a deferred-judging result's submitted photos to the team's official photo.\n\nGated by rally_settings.allow_photo_as_team_photo so an admin can turn\nthis capability off event-wide. The chosen URL must already be one of\nthe result's own media_urls (already stored in R2) to prevent staff\nfrom pointing a team's photo at an arbitrary URL, and \u2014 like the\ncapture route \u2014 scoped to the caller's own post: proving *some*\nassignment was never the same as proving this one.", "operationId": "set_team_photo_from_result", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "result_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Result Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetTeamPhotoRequest" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetTeamPhotoResponse" } } } }, "403": { "description": "Setting a team photo from an activity photo is disabled" }, "404": { "description": "Result not found" }, "400": { "description": "Photo does not belong to this result" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/activities/deferred/pending": { "get": { "tags": [ "Deferred Judging" ], "summary": "List Pending Judgments", "operationId": "list_pending_judgments", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/DeferredResultResponse" }, "type": "array", "title": "Response List Pending Judgments" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/activities/deferred/{activity_id}/results": { "get": { "tags": [ "Deferred Judging" ], "summary": "List Deferred Results For Activity", "description": "Every capture for one post, pending and already-judged \u2014 the side-\nby-side view a judge ranks from, with full context instead of just\nwhat's still outstanding.", "operationId": "list_deferred_results_for_activity", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "activity_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Activity Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/DeferredResultResponse" }, "title": "Response List Deferred Results For Activity" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/activities/deferred/{activity_id}/rank": { "post": { "tags": [ "Deferred Judging" ], "summary": "Rank Deferred Results", "description": "Score every capture for this post by where the judge placed it \u2014\n1st gets the activity's max_points, last gets min_points, linearly\nin between.", "operationId": "rank_deferred_results", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "activity_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Activity Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RankRequest" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/DeferredResultResponse" }, "title": "Response Rank Deferred Results" } } } }, "404": { "description": "Activity not found" }, "400": { "description": "The ranking doesn't cover every capture for this activity, or lists one twice" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/dynamic-rules": { "get": { "tags": [ "Dynamic Scoring" ], "summary": "List Dynamic Rules", "description": "Rules of the current event; deleted ones never appear.\n\n``include_inactive`` is for the admin screen, which has to keep showing\na rule it has switched off \u2014 otherwise the switch has nothing left to\nswitch back on. The staff form omits it and sees only live rules.\n\nStays public, like the listing already was: a rule that is switched off\nis no more sensitive than one that is on, and the active ones are\npublic already.", "operationId": "list_dynamic_rules", "parameters": [ { "name": "include_inactive", "in": "query", "required": false, "schema": { "type": "boolean", "default": false, "title": "Include Inactive" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/DynamicRuleResponse" }, "title": "Response List Dynamic Rules" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "post": { "tags": [ "Dynamic Scoring" ], "summary": "Create Dynamic Rule", "operationId": "create_dynamic_rule", "security": [ { "HTTPBearer": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DynamicRuleCreate" } } } }, "responses": { "201": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DynamicRuleResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/dynamic-rules/{rule_id}": { "put": { "tags": [ "Dynamic Scoring" ], "summary": "Update Dynamic Rule", "operationId": "update_dynamic_rule", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "rule_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Rule Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DynamicRuleUpdate" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DynamicRuleResponse" } } } }, "404": { "description": "Rule not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "delete": { "tags": [ "Dynamic Scoring" ], "summary": "Delete Dynamic Rule", "operationId": "delete_dynamic_rule", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "rule_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Rule Id" } } ], "responses": { "204": { "description": "Successful Response" }, "404": { "description": "Rule not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/dynamic-awards": { "get": { "tags": [ "Dynamic Scoring" ], "summary": "List Dynamic Awards", "operationId": "list_dynamic_awards", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "team_id", "in": "query", "required": false, "schema": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Team Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/DynamicAwardResponse" }, "title": "Response List Dynamic Awards" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } }, "post": { "tags": [ "Dynamic Scoring" ], "summary": "Create Dynamic Award", "operationId": "create_dynamic_award", "security": [ { "HTTPBearer": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DynamicAwardCreate" } } } }, "responses": { "201": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DynamicAwardResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/dynamic-awards/{award_id}": { "delete": { "tags": [ "Dynamic Scoring" ], "summary": "Delete Dynamic Award", "operationId": "delete_dynamic_award", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "award_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Award Id" } } ], "responses": { "204": { "description": "Successful Response" }, "404": { "description": "Award not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/guide/checkpoints": { "get": { "tags": [ "Guide" ], "summary": "List Guide Checkpoints", "description": "Checkpoints with their media gallery for the current event.\n\nEvery post is returned \u2014 a guide accompanies their team through the\nwhole route rather than being fixed to one \u2014 with the team's current\npost flagged via ``is_current`` for the client to highlight. Ordered\nby checkpoint order.", "operationId": "list_guide_checkpoints", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/GuideCheckpointResponse" }, "type": "array", "title": "Response List Guide Checkpoints" } } } }, "403": { "description": "Guide mode is not active for this event" } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/guide/checkpoints/{checkpoint_id}/teams": { "get": { "tags": [ "Guide" ], "summary": "List Guide Teams At Checkpoint", "description": "Teams that have arrived at this post, and the hints they bought.", "operationId": "list_guide_teams_at_checkpoint", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "checkpoint_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Checkpoint Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/GuideTeamAtCheckpoint" }, "title": "Response List Guide Teams At Checkpoint" } } } }, "403": { "description": "Guide mode is off, or not this guide's checkpoint" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/guide/checkpoints/{checkpoint_id}/arrivals": { "post": { "tags": [ "Guide" ], "summary": "Record Guide Arrival", "description": "Mark a team as arrived, on the guide's word instead of a GPS fix.\n\nGPS check-in fails for ordinary reasons \u2014 a flat battery, no signal, an\nindoor post \u2014 and the guide is standing there watching the team. This\nis the fallback, and it is audited like every other progress write.", "operationId": "record_guide_arrival", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "checkpoint_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Checkpoint Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GuideArrivalRequest" } } } }, "responses": { "201": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GuideArrivalResponse" } } } }, "400": { "description": "Outside the event window, or a cross-edition team" }, "403": { "description": "Guide mode is off, not this guide's checkpoint, or not this guide's team" }, "404": { "description": "Checkpoint not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/guide/team": { "get": { "tags": [ "Guide" ], "summary": "Get Guide Team", "description": "The guide's own assigned team \u2014 name, members, and access-code QR.\n\nScoped to the single team this guide is assigned to; a guide never\nsees another team's roster or access code through this endpoint.", "operationId": "get_guide_team", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PrivilegedDetailedTeam" } } } }, "403": { "description": "Guide mode is not active for this event" }, "404": { "description": "No team assigned to this guide" } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/events/{event_id}/export": { "get": { "tags": [ "Export", "Events" ], "summary": "Export Event Results", "description": "Return an .xlsx workbook of the event's results (admin/manager only).", "operationId": "export_event_results", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "event_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Event Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } }, "404": { "description": "Event not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/events/{event_id}/report": { "get": { "tags": [ "Export", "Events" ], "summary": "Export Event Report", "description": "Return a .pdf final report of the event (admin/manager only):\nranking, per-checkpoint detail, captured photos, event stats.", "operationId": "export_event_report", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "event_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Event Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } }, "404": { "description": "Event not found" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/audit": { "get": { "tags": [ "Audit" ], "summary": "List Audit Log", "description": "Filtered, paginated audit trail \u2014 admin only.\n\n``action`` matches by prefix (e.g. \"badge.\" matches both\n\"badge.granted\" and \"badge.revoked\") so a caller can filter by\ncategory without enumerating every specific action.", "operationId": "list_audit_log", "security": [ { "HTTPBearer": [] } ], "parameters": [ { "name": "action", "in": "query", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Action" } }, { "name": "actor_id", "in": "query", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Actor Id" } }, { "name": "target_type", "in": "query", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Target Type" } }, { "name": "since", "in": "query", "required": false, "schema": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Since" } }, { "name": "until", "in": "query", "required": false, "schema": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Until" } }, { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "maximum": 200, "minimum": 1, "default": 50, "title": "Limit" } }, { "name": "offset", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 0, "default": 0, "title": "Offset" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/AuditLogEntry" }, "title": "Response List Audit Log" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/rally/v1/push/vapid-public-key": { "get": { "tags": [ "Push Notifications" ], "summary": "Get Vapid Public Key", "description": "The public key the frontend passes to `PushManager.subscribe`.\n\nNone when VAPID isn't configured \u2014 the frontend must not prompt for\nnotification permission in that case (nothing would ever be sent).", "operationId": "get_vapid_public_key", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VapidPublicKey" } } } } } } }, "/api/rally/v1/push/subscribe": { "post": { "tags": [ "Push Notifications" ], "summary": "Push Subscribe", "operationId": "push_subscribe", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PushSubscriptionCreate" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PushSubscriptionRead" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/push/unsubscribe": { "post": { "tags": [ "Push Notifications" ], "summary": "Push Unsubscribe", "operationId": "push_unsubscribe", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PushSubscriptionUnsubscribe" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/push/broadcast": { "post": { "tags": [ "Push Notifications" ], "summary": "Push Broadcast", "description": "Send one notification to every subscribed device \u2014 an admin\nannouncement to all teams at once, not addressed to one participant.", "operationId": "push_broadcast", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PushBroadcastRequest" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PushBroadcastResult" } } } }, "503": { "description": "Push notifications are not configured" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/push/checkpoint-announcement": { "post": { "tags": [ "Push Notifications" ], "summary": "Push Checkpoint Announcement", "description": "Let staff announce something about their own post \u2014 no admin in\nthe loop. Reaches every team like an admin broadcast does (the whole\nrally needs to know a post is delayed or closed, not just teams\nalready there); the post's own name is stamped onto the title\nserver-side so a staffer can't post as if they were a different\ncheckpoint or as a generic admin message.", "operationId": "push_checkpoint_announcement", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PushCheckpointAnnouncementRequest" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PushBroadcastResult" } } } }, "403": { "description": "Staff user has no checkpoint assignment" }, "503": { "description": "Push notifications are not configured" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/health/ready": { "get": { "tags": [ "health" ], "summary": "Readiness Check", "description": "Readiness probe: aggregates DB, Redis and worker liveness.\n\nReturns 503 when any checked dependency is unhealthy so a silently\nstale leaderboard (dead worker) or a database/Redis outage surfaces to\nops. Not wired to the container healthcheck \u2014 see ``health_check`` in\n``app.main``.", "operationId": "readiness_check", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Readiness" } } } } } } }, "/api/rally/v1/admin/metrics": { "get": { "tags": [ "health" ], "summary": "Get Admin Metrics", "description": "Prometheus counters aggregated for the admin panel \u2014 admin only.\n\nThe raw ``/metrics`` scrape endpoint has no authentication and is not\nrouted publicly; this is the authenticated way to read the same\ncounters from a browser.", "operationId": "get_admin_metrics", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MetricsSummary" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/api/rally/v1/admin/idempotency-keys/purge": { "post": { "tags": [ "health" ], "summary": "Purge Idempotency Keys", "description": "Delete completed idempotency-key rows older than the TTL \u2014 admin\nonly. nothing pruned this table before; run manually or on a\nschedule (e.g. an external cron hitting this endpoint) until an\nin-process scheduler exists.", "operationId": "purge_idempotency_keys", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "additionalProperties": { "type": "integer" }, "type": "object", "title": "Response Purge Idempotency Keys" } } } } }, "security": [ { "HTTPBearer": [] } ] } }, "/health": { "get": { "tags": [ "health" ], "summary": "Health Check", "description": "Liveness probe: 200 whenever the process can serve requests.\n\nThis is the Docker healthcheck target (and gates ``depends_on``), so it must\nNOT fail on a dependency outage \u2014 a down Redis/DB would otherwise tear down\nthe whole stack. Dependency status lives in the readiness probe instead,\nunder the versioned prefix (see ``app.api.api_v1.health``).", "operationId": "health_check", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "additionalProperties": { "type": "string" }, "type": "object", "title": "Response Health Check" } } } } } } } }, "components": { "schemas": { "ActivityCreate": { "properties": { "name": { "type": "string", "maxLength": 255, "minLength": 1, "title": "Name" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "activity_type": { "$ref": "#/components/schemas/ActivityType", "description": "Activity type enum" }, "checkpoint_id": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0.0 }, { "type": "null" } ], "title": "Checkpoint Id" }, "config": { "additionalProperties": true, "type": "object", "title": "Config" }, "is_active": { "type": "boolean", "title": "Is Active", "default": true }, "is_global": { "type": "boolean", "title": "Is Global", "default": false }, "available_from": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Available From" }, "available_until": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Available Until" } }, "type": "object", "required": [ "name", "activity_type" ], "title": "ActivityCreate", "description": "Schema for creating an activity" }, "ActivityListResponse": { "properties": { "activities": { "items": { "$ref": "#/components/schemas/ActivityResponse" }, "type": "array", "title": "Activities" }, "total": { "type": "integer", "title": "Total" }, "page": { "type": "integer", "title": "Page" }, "size": { "type": "integer", "title": "Size" } }, "type": "object", "required": [ "activities", "total", "page", "size" ], "title": "ActivityListResponse", "description": "Schema for activity list response" }, "ActivityRanking": { "properties": { "activity_id": { "type": "integer", "title": "Activity Id" }, "activity_name": { "type": "string", "title": "Activity Name" }, "rankings": { "items": { "$ref": "#/components/schemas/TeamRanking" }, "type": "array", "title": "Rankings" } }, "type": "object", "required": [ "activity_id", "activity_name", "rankings" ], "title": "ActivityRanking", "description": "Schema for activity-specific ranking" }, "ActivityResponse": { "properties": { "name": { "type": "string", "maxLength": 255, "minLength": 1, "title": "Name" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "activity_type": { "$ref": "#/components/schemas/ActivityType", "description": "Activity type enum" }, "checkpoint_id": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0.0 }, { "type": "null" } ], "title": "Checkpoint Id" }, "config": { "additionalProperties": true, "type": "object", "title": "Config" }, "is_active": { "type": "boolean", "title": "Is Active", "default": true }, "is_global": { "type": "boolean", "title": "Is Global", "default": false }, "available_from": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Available From" }, "available_until": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Available Until" }, "id": { "type": "integer", "title": "Id" }, "created_at": { "type": "string", "format": "date-time", "title": "Created At" }, "updated_at": { "type": "string", "format": "date-time", "title": "Updated At" } }, "type": "object", "required": [ "name", "activity_type", "id", "created_at", "updated_at" ], "title": "ActivityResponse", "description": "Schema for activity response" }, "ActivityResultCreate": { "properties": { "activity_id": { "type": "integer", "exclusiveMinimum": 0.0, "title": "Activity Id" }, "team_id": { "type": "integer", "exclusiveMinimum": 0.0, "title": "Team Id" }, "result_data": { "additionalProperties": true, "type": "object", "title": "Result Data" }, "extra_shots": { "type": "integer", "minimum": 0.0, "title": "Extra Shots", "default": 0 }, "penalties": { "additionalProperties": { "type": "integer" }, "type": "object", "title": "Penalties" }, "penalty_counts": { "anyOf": [ { "additionalProperties": { "type": "integer" }, "type": "object" }, { "type": "null" } ], "title": "Penalty Counts" }, "bonuses": { "additionalProperties": { "type": "integer" }, "type": "object", "title": "Bonuses" }, "bonus_counts": { "anyOf": [ { "additionalProperties": { "type": "integer" }, "type": "object" }, { "type": "null" } ], "title": "Bonus Counts" } }, "type": "object", "required": [ "activity_id", "team_id" ], "title": "ActivityResultCreate", "description": "Schema for creating an activity result" }, "ActivityResultEvaluation": { "properties": { "result_data": { "additionalProperties": true, "type": "object", "title": "Result Data" }, "extra_shots": { "type": "integer", "minimum": 0.0, "title": "Extra Shots", "default": 0 }, "penalty_counts": { "anyOf": [ { "additionalProperties": { "type": "integer" }, "type": "object" }, { "type": "null" } ], "title": "Penalty Counts" }, "bonus_counts": { "anyOf": [ { "additionalProperties": { "type": "integer" }, "type": "object" }, { "type": "null" } ], "title": "Bonus Counts" } }, "type": "object", "title": "ActivityResultEvaluation", "description": "What a staff member submits when evaluating a team at a checkpoint.\n\nDeliberately has no ``penalties`` or ``bonuses`` field. Staff submit\noccurrence *counts* (\"2 vomits\", \"3 for performance\"); the server prices\nthem from RallySettings / ``Activity.config.penalty_counters`` /\n``Activity.config.bonus_counters`` / active DynamicRule rows and writes the\nresulting points itself. Accepting points here would let the request body\nname its own deduction \u2014 or, on the bonus side, its own award \u2014 and no\namount of client-side validation can close that, since the client is what\nwould be sending the number.\n\nThe internal ``ActivityResultCreate``/``ActivityResultUpdate`` schemas do\nstill carry ``penalties``, for admin tooling and service-to-service calls\nthat legitimately set points directly." }, "ActivityResultResponse": { "properties": { "activity_id": { "type": "integer", "exclusiveMinimum": 0.0, "title": "Activity Id" }, "team_id": { "type": "integer", "exclusiveMinimum": 0.0, "title": "Team Id" }, "result_data": { "additionalProperties": true, "type": "object", "title": "Result Data" }, "extra_shots": { "type": "integer", "minimum": 0.0, "title": "Extra Shots", "default": 0 }, "penalties": { "additionalProperties": { "type": "integer" }, "type": "object", "title": "Penalties" }, "penalty_counts": { "anyOf": [ { "additionalProperties": { "type": "integer" }, "type": "object" }, { "type": "null" } ], "title": "Penalty Counts" }, "bonuses": { "additionalProperties": { "type": "integer" }, "type": "object", "title": "Bonuses" }, "bonus_counts": { "anyOf": [ { "additionalProperties": { "type": "integer" }, "type": "object" }, { "type": "null" } ], "title": "Bonus Counts" }, "id": { "type": "integer", "title": "Id" }, "time_score": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Time Score" }, "points_score": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Points Score" }, "boolean_score": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Boolean Score" }, "team_vs_result": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Team Vs Result" }, "final_score": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Final Score" }, "is_completed": { "type": "boolean", "title": "Is Completed", "default": false }, "completed_at": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Completed At" }, "created_at": { "type": "string", "format": "date-time", "title": "Created At" }, "updated_at": { "type": "string", "format": "date-time", "title": "Updated At" } }, "type": "object", "required": [ "activity_id", "team_id", "id", "created_at", "updated_at" ], "title": "ActivityResultResponse", "description": "Schema for activity result response" }, "ActivityResultStaffUpdate": { "properties": { "result_data": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Result Data" }, "extra_shots": { "anyOf": [ { "type": "integer", "minimum": 0.0 }, { "type": "null" } ], "title": "Extra Shots" }, "penalty_counts": { "anyOf": [ { "additionalProperties": { "type": "integer" }, "type": "object" }, { "type": "null" } ], "title": "Penalty Counts" }, "bonus_counts": { "anyOf": [ { "additionalProperties": { "type": "integer" }, "type": "object" }, { "type": "null" } ], "title": "Bonus Counts" } }, "type": "object", "title": "ActivityResultStaffUpdate", "description": "What a staff member submits when *editing* an existing evaluation.\n\nregression: the PUT endpoint used to accept ``ActivityResultUpdate``,\nwhich carries ``penalties`` (raw points, unvalidated) and ``is_completed``.\n``apply_modifiers`` does ``raw_score -= penalty_value``, so a negative\n``penalties`` value is a bonus a staff member could award themselves via\n``PUT .../evaluate/{id}`` \u2014 the ABAC rule that lets staff touch their own\ncheckpoint's results (``UPDATE_ACTIVITY_RESULT``) doesn't distinguish\n\"change my counts\" from \"set an arbitrary point total\".\n\nMirrors ``ActivityResultEvaluation`` (the create-time staff schema):\ncounts, never points, and no ``is_completed`` toggle. ``bonuses`` is\nexcluded for exactly the same reason ``penalties`` is \u2014 it is the very\nthing the negative-penalty hole was being used to fabricate." }, "ActivityResultUpdate": { "properties": { "result_data": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Result Data" }, "extra_shots": { "anyOf": [ { "type": "integer", "minimum": 0.0 }, { "type": "null" } ], "title": "Extra Shots" }, "penalties": { "anyOf": [ { "additionalProperties": { "type": "integer" }, "type": "object" }, { "type": "null" } ], "title": "Penalties" }, "penalty_counts": { "anyOf": [ { "additionalProperties": { "type": "integer" }, "type": "object" }, { "type": "null" } ], "title": "Penalty Counts" }, "bonuses": { "anyOf": [ { "additionalProperties": { "type": "integer" }, "type": "object" }, { "type": "null" } ], "title": "Bonuses" }, "bonus_counts": { "anyOf": [ { "additionalProperties": { "type": "integer" }, "type": "object" }, { "type": "null" } ], "title": "Bonus Counts" }, "is_completed": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Is Completed" } }, "type": "object", "title": "ActivityResultUpdate", "description": "Schema for updating an activity result.\n\nFor admin/service callers only. Carries ``penalties`` (raw points) and\n``is_completed`` directly \u2014 a staff-facing endpoint must never accept\nthis: see ``ActivityResultStaffUpdate``." }, "ActivityType": { "type": "string", "enum": [ "TimeBasedActivity", "ScoreBasedActivity", "BooleanActivity", "TeamVsActivity", "GeneralActivity", "DeferredJudgedActivity" ], "title": "ActivityType", "description": "Enum for activity types with string values for database compatibility" }, "ActivityUpdate": { "properties": { "name": { "anyOf": [ { "type": "string", "maxLength": 255, "minLength": 1 }, { "type": "null" } ], "title": "Name" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "activity_type": { "anyOf": [ { "$ref": "#/components/schemas/ActivityType" }, { "type": "null" } ], "description": "Activity type enum" }, "checkpoint_id": { "anyOf": [ { "type": "integer", "exclusiveMinimum": 0.0 }, { "type": "null" } ], "title": "Checkpoint Id" }, "config": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Config" }, "is_active": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Is Active" }, "is_global": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Is Global" }, "available_from": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Available From" }, "available_until": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Available Until" } }, "type": "object", "title": "ActivityUpdate", "description": "Schema for updating an activity" }, "AdminCheckPoint": { "properties": { "is_draft": { "type": "boolean", "title": "Is Draft", "default": false }, "is_placeholder": { "type": "boolean", "title": "Is Placeholder", "default": false }, "staff_script": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Staff Script" }, "challenge_brief": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Challenge Brief" }, "name": { "type": "string", "title": "Name" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "latitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Latitude" }, "longitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Longitude" }, "order": { "type": "integer", "title": "Order" }, "arrival_radius_m": { "type": "integer", "title": "Arrival Radius M", "default": 50 }, "clue": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Clue" }, "clue_media_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Clue Media Url" }, "stage_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Stage Id" }, "available_from": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Available From" }, "available_until": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Available Until" }, "id": { "type": "integer", "title": "Id" }, "is_redacted": { "type": "boolean", "title": "Is Redacted", "default": false }, "search_latitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Search Latitude" }, "search_longitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Search Longitude" }, "search_radius_m": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Search Radius M" }, "is_reachable": { "type": "boolean", "title": "Is Reachable", "default": false }, "missing": { "items": { "type": "string" }, "type": "array", "title": "Missing", "default": [] } }, "type": "object", "required": [ "name", "order", "id" ], "title": "AdminCheckPoint", "description": "The admin/staff view of a post: the participant fields plus the\nplanning ones and a readiness verdict.\n\nReturned only by admin-authenticated routes. Teams get\n``DetailedCheckPoint``, which structurally cannot carry these fields." }, "AdminCheckPointSelect": { "properties": { "checkpoint_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Checkpoint Id" } }, "type": "object", "title": "AdminCheckPointSelect" }, "ArriveRequest": { "properties": { "latitude": { "type": "number", "maximum": 90.0, "minimum": -90.0, "title": "Latitude" }, "longitude": { "type": "number", "maximum": 180.0, "minimum": -180.0, "title": "Longitude" } }, "type": "object", "required": [ "latitude", "longitude" ], "title": "ArriveRequest" }, "ArriveResponse": { "properties": { "team_id": { "type": "integer", "title": "Team Id" }, "checkpoint_id": { "type": "integer", "title": "Checkpoint Id" }, "distance_m": { "type": "number", "title": "Distance M" }, "already_registered": { "type": "boolean", "title": "Already Registered" }, "auto_completed": { "type": "boolean", "title": "Auto Completed", "default": false } }, "type": "object", "required": [ "team_id", "checkpoint_id", "distance_m", "already_registered" ], "title": "ArriveResponse" }, "AuditLogEntry": { "properties": { "id": { "type": "integer", "title": "Id" }, "event_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Event Id" }, "actor_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Actor Id" }, "actor_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Actor Name" }, "actor_kind": { "type": "string", "title": "Actor Kind" }, "action": { "type": "string", "title": "Action" }, "target_type": { "type": "string", "title": "Target Type" }, "target_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Target Id" }, "changes": { "additionalProperties": true, "type": "object", "title": "Changes" }, "note": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Note" }, "request_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Request Id" }, "created_at": { "type": "string", "format": "date-time", "title": "Created At" } }, "type": "object", "required": [ "id", "actor_kind", "action", "target_type", "created_at" ], "title": "AuditLogEntry", "description": "One audit-trail row: who did what, to what, and when." }, "BadgeDefinitionCreate": { "properties": { "name": { "type": "string", "title": "Name" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "is_active": { "type": "boolean", "title": "Is Active", "default": true }, "is_auto": { "type": "boolean", "title": "Is Auto", "default": false }, "color": { "type": "string", "title": "Color", "default": "#8b5cf6" }, "glyph": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Glyph" }, "trigger_type": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Trigger Type" }, "criteria": { "additionalProperties": true, "type": "object", "title": "Criteria", "default": {} }, "code": { "type": "string", "title": "Code" } }, "type": "object", "required": [ "name", "code" ], "title": "BadgeDefinitionCreate" }, "BadgeDefinitionLite": { "properties": { "code": { "type": "string", "title": "Code" }, "name": { "type": "string", "title": "Name" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "color": { "type": "string", "title": "Color" }, "glyph": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Glyph" }, "icon_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Icon Url" } }, "type": "object", "required": [ "code", "name", "color" ], "title": "BadgeDefinitionLite", "description": "Display fields of a badge definition, for the team showcase." }, "BadgeDefinitionResponse": { "properties": { "name": { "type": "string", "title": "Name" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "is_active": { "type": "boolean", "title": "Is Active", "default": true }, "is_auto": { "type": "boolean", "title": "Is Auto", "default": false }, "color": { "type": "string", "title": "Color", "default": "#8b5cf6" }, "glyph": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Glyph" }, "trigger_type": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Trigger Type" }, "criteria": { "additionalProperties": true, "type": "object", "title": "Criteria", "default": {} }, "id": { "type": "integer", "title": "Id" }, "code": { "type": "string", "title": "Code" }, "icon_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Icon Url" } }, "type": "object", "required": [ "name", "id", "code" ], "title": "BadgeDefinitionResponse" }, "BadgeDefinitionUpdate": { "properties": { "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Name" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "is_active": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Is Active" }, "is_auto": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Is Auto" }, "color": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Color" }, "glyph": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Glyph" }, "trigger_type": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Trigger Type" }, "criteria": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Criteria" } }, "type": "object", "title": "BadgeDefinitionUpdate" }, "BadgeShowcaseResponse": { "properties": { "definitions": { "items": { "$ref": "#/components/schemas/BadgeDefinitionLite" }, "type": "array", "title": "Definitions" }, "earned": { "items": { "$ref": "#/components/schemas/EarnedBadge" }, "type": "array", "title": "Earned" } }, "type": "object", "required": [ "definitions", "earned" ], "title": "BadgeShowcaseResponse", "description": "Everything the team badge board needs in one request.\n\n``definitions`` is the full active catalogue (drives the locked+earned grid);\n``earned`` is this team's awards, joined to the catalogue by ``code``." }, "Body_capture_deferred_result": { "properties": { "images": { "anyOf": [ { "items": { "type": "string", "contentMediaType": "application/octet-stream" }, "type": "array" }, { "type": "null" } ], "title": "Images" } }, "type": "object", "title": "Body_capture_deferred_result" }, "Body_create_checkpoint_media": { "properties": { "kind": { "$ref": "#/components/schemas/MediaKind" }, "caption": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Caption" }, "order": { "type": "integer", "title": "Order", "default": 0 }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Title" }, "content_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Content Url" }, "content_text": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Content Text" }, "image": { "anyOf": [ { "type": "string", "contentMediaType": "application/octet-stream" }, { "type": "null" } ], "title": "Image" } }, "type": "object", "required": [ "kind" ], "title": "Body_create_checkpoint_media" }, "Body_update_checkpoint_media": { "properties": { "caption": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Caption" }, "order": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Order" }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Title" }, "content_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Content Url" }, "content_text": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Content Text" }, "image": { "anyOf": [ { "type": "string", "contentMediaType": "application/octet-stream" }, { "type": "null" } ], "title": "Image" } }, "type": "object", "title": "Body_update_checkpoint_media" }, "Body_upload_badge_icon": { "properties": { "image": { "type": "string", "contentMediaType": "application/octet-stream", "title": "Image" } }, "type": "object", "required": [ "image" ], "title": "Body_upload_badge_icon" }, "Body_upload_clue_image": { "properties": { "image": { "type": "string", "contentMediaType": "application/octet-stream", "title": "Image" } }, "type": "object", "required": [ "image" ], "title": "Body_upload_clue_image" }, "Body_upload_rally_banner": { "properties": { "image": { "type": "string", "contentMediaType": "application/octet-stream", "title": "Image" } }, "type": "object", "required": [ "image" ], "title": "Body_upload_rally_banner" }, "Body_upload_rally_favicon": { "properties": { "image": { "type": "string", "contentMediaType": "application/octet-stream", "title": "Image" } }, "type": "object", "required": [ "image" ], "title": "Body_upload_rally_favicon" }, "Body_upload_rally_logo": { "properties": { "image": { "type": "string", "contentMediaType": "application/octet-stream", "title": "Image" } }, "type": "object", "required": [ "image" ], "title": "Body_upload_rally_logo" }, "Body_upload_rally_rules_pdf": { "properties": { "image": { "type": "string", "contentMediaType": "application/octet-stream", "title": "Image" } }, "type": "object", "required": [ "image" ], "title": "Body_upload_rally_rules_pdf" }, "Body_upload_team_photo": { "properties": { "image": { "type": "string", "contentMediaType": "application/octet-stream", "title": "Image" } }, "type": "object", "required": [ "image" ], "title": "Body_upload_team_photo" }, "ChangeEventFormatRequest": { "properties": { "event_type": { "$ref": "#/components/schemas/EventType" }, "event_profile": { "$ref": "#/components/schemas/EventProfile" } }, "type": "object", "required": [ "event_type", "event_profile" ], "title": "ChangeEventFormatRequest" }, "ChangeEventFormatResponse": { "properties": { "event": { "$ref": "#/components/schemas/RallyEventResponse" }, "changes": { "items": { "additionalProperties": true, "type": "object" }, "type": "array", "title": "Changes" }, "issues": { "items": { "$ref": "#/components/schemas/ConfigurationIssueResponse" }, "type": "array", "title": "Issues" }, "ready": { "type": "boolean", "title": "Ready" } }, "type": "object", "required": [ "event", "changes", "issues", "ready" ], "title": "ChangeEventFormatResponse" }, "CheckPointCreate": { "properties": { "is_draft": { "type": "boolean", "title": "Is Draft", "default": false }, "is_placeholder": { "type": "boolean", "title": "Is Placeholder", "default": false }, "staff_script": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Staff Script" }, "challenge_brief": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Challenge Brief" }, "name": { "type": "string", "title": "Name" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "latitude": { "anyOf": [ { "type": "number", "maximum": 90.0, "minimum": -90.0 }, { "type": "null" } ], "title": "Latitude" }, "longitude": { "anyOf": [ { "type": "number", "maximum": 180.0, "minimum": -180.0 }, { "type": "null" } ], "title": "Longitude" }, "order": { "type": "integer", "title": "Order" }, "arrival_radius_m": { "type": "integer", "minimum": 0.0, "title": "Arrival Radius M", "default": 50 }, "clue": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Clue" }, "clue_media_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Clue Media Url" }, "stage_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Stage Id" }, "available_from": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Available From" }, "available_until": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Available Until" } }, "type": "object", "required": [ "name", "order" ], "title": "CheckPointCreate" }, "CheckPointUpdate": { "properties": { "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Name" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "latitude": { "anyOf": [ { "type": "number", "maximum": 90.0, "minimum": -90.0 }, { "type": "null" } ], "title": "Latitude" }, "longitude": { "anyOf": [ { "type": "number", "maximum": 180.0, "minimum": -180.0 }, { "type": "null" } ], "title": "Longitude" }, "arrival_radius_m": { "anyOf": [ { "type": "integer", "minimum": 0.0 }, { "type": "null" } ], "title": "Arrival Radius M" }, "clue": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Clue" }, "clue_media_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Clue Media Url" }, "stage_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Stage Id" }, "available_from": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Available From" }, "available_until": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Available Until" }, "is_draft": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Is Draft" }, "is_placeholder": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Is Placeholder" }, "staff_script": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Staff Script" }, "challenge_brief": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Challenge Brief" } }, "type": "object", "title": "CheckPointUpdate", "description": "A post's editable fields.\n\n``order`` is deliberately absent. It is not a plain column: it is unique\nper event, it is what progress is read by, and moving it has to renumber\nthe rest of the route. Writing it here did none of that \u2014 no uniqueness\ncheck (so it could collide with ``uq_checkpoint_event_order``) and no\nresequence \u2014 which is why reordering has its own endpoint,\n``PUT /checkpoint/reorder``." }, "CheckinRequest": { "properties": { "token": { "type": "string", "title": "Token" } }, "type": "object", "required": [ "token" ], "title": "CheckinRequest" }, "CheckinResponse": { "properties": { "team_id": { "type": "integer", "title": "Team Id" }, "checkpoint_id": { "type": "integer", "title": "Checkpoint Id" }, "checkpoint_order": { "type": "integer", "title": "Checkpoint Order" } }, "type": "object", "required": [ "team_id", "checkpoint_id", "checkpoint_order" ], "title": "CheckinResponse" }, "CheckpointAssignmentUpdate": { "properties": { "checkpoint_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Checkpoint Id" } }, "type": "object", "title": "CheckpointAssignmentUpdate" }, "CheckpointGuideIndication": { "properties": { "hint": { "type": "string", "minLength": 1, "title": "Hint" }, "question": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Question" }, "expected_answer": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Expected Answer" }, "order": { "type": "integer", "title": "Order", "default": 0 }, "id": { "type": "integer", "title": "Id" }, "checkpoint_id": { "type": "integer", "title": "Checkpoint Id" } }, "type": "object", "required": [ "hint", "id", "checkpoint_id" ], "title": "CheckpointGuideIndication" }, "CheckpointGuideIndicationCreate": { "properties": { "hint": { "type": "string", "minLength": 1, "title": "Hint" }, "question": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Question" }, "expected_answer": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Expected Answer" }, "order": { "type": "integer", "title": "Order", "default": 0 } }, "type": "object", "required": [ "hint" ], "title": "CheckpointGuideIndicationCreate" }, "CheckpointGuideIndicationUpdate": { "properties": { "hint": { "anyOf": [ { "type": "string", "minLength": 1 }, { "type": "null" } ], "title": "Hint" }, "question": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Question" }, "expected_answer": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Expected Answer" }, "order": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Order" } }, "type": "object", "title": "CheckpointGuideIndicationUpdate" }, "CheckpointMediaResponse": { "properties": { "kind": { "$ref": "#/components/schemas/MediaKind" }, "caption": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Caption" }, "order": { "type": "integer", "title": "Order", "default": 0 }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Title" }, "content_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Content Url" }, "content_text": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Content Text" }, "id": { "type": "integer", "title": "Id" }, "checkpoint_id": { "type": "integer", "title": "Checkpoint Id" }, "image_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Image Url" } }, "type": "object", "required": [ "kind", "id", "checkpoint_id" ], "title": "CheckpointMediaResponse" }, "CheckpointPenalties": { "properties": { "checkpoint_order": { "type": "integer", "title": "Checkpoint Order" }, "checkpoint_id": { "type": "integer", "title": "Checkpoint Id" }, "hints_cost": { "type": "integer", "title": "Hints Cost", "default": 0 }, "skip_cost": { "type": "integer", "title": "Skip Cost", "default": 0 }, "activity_penalties": { "type": "integer", "title": "Activity Penalties", "default": 0 }, "total": { "type": "integer", "title": "Total", "default": 0 } }, "type": "object", "required": [ "checkpoint_order", "checkpoint_id" ], "title": "CheckpointPenalties", "description": "Points a team lost at one post, broken down by cause.\n\n``hints_cost`` is what the team paid unlocking guide indications there,\n``skip_cost`` the give-up penalty, ``activity_penalties`` the sum of the\nactivity-level deductions (v\u00f3mitos, n\u00e3o-beber, contadores din\u00e2micos).\nEvery field is negative or zero, the same sign convention as the rest of\nthe app. Only posts with at least one non-zero penalty are emitted, keyed\nby ``checkpoint_id`` (with ``checkpoint_order`` for display), matching\n``DetailedTeam.checkpoints``." }, "CheckpointProgress": { "properties": { "checkpoint_id": { "type": "integer", "title": "Checkpoint Id" }, "checkpoint_order": { "type": "integer", "title": "Checkpoint Order" }, "status": { "type": "string", "enum": [ "pending", "arrived", "completed", "skipped" ], "title": "Status" }, "arrived_at": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Arrived At" }, "completed_at": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Completed At" }, "score": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Score" }, "skip_cost": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Skip Cost" } }, "type": "object", "required": [ "checkpoint_id", "checkpoint_order", "status" ], "title": "CheckpointProgress", "description": "One team's state at one post, keyed by the post's stable id.\n\nBuilt from the identity-keyed rows (arrivals, skips, activity results)\nrather than from ``Team``'s positional arrays, so reordering or drafting\nposts mid-event never reassigns a team's data to a different post.\n``checkpoint_order`` is the post's current route position, for display.\n``score`` and ``skip_cost`` are ``None`` when scores are hidden." }, "CheckpointSkipped": { "properties": { "checkpoint_id": { "type": "integer", "title": "Checkpoint Id" }, "cost": { "type": "integer", "title": "Cost" }, "next_checkpoint_order": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Next Checkpoint Order" } }, "type": "object", "required": [ "checkpoint_id", "cost" ], "title": "CheckpointSkipped" }, "ClaimMembershipRequest": { "properties": { "access_code": { "type": "string", "title": "Access Code" } }, "type": "object", "required": [ "access_code" ], "title": "ClaimMembershipRequest", "description": "Proof that the claimer belongs to the placeholder member's team.\n\nThe OIDC bearer identifies the caller but not their team, so the team's\naccess code (the same secret ``/profile/claimable`` requires) must be\npresented again when acting on a placeholder." }, "ClaimableMember": { "properties": { "id": { "type": "integer", "title": "Id" }, "name": { "type": "string", "title": "Name" }, "is_captain": { "type": "boolean", "title": "Is Captain", "default": false } }, "type": "object", "required": [ "id", "name" ], "title": "ClaimableMember", "description": "A name-only placeholder member a person can claim as themselves." }, "ClaimableTeam": { "properties": { "team_id": { "type": "integer", "title": "Team Id" }, "team_name": { "type": "string", "title": "Team Name" }, "members": { "items": { "$ref": "#/components/schemas/ClaimableMember" }, "type": "array", "title": "Members", "default": [] } }, "type": "object", "required": [ "team_id", "team_name" ], "title": "ClaimableTeam", "description": "A team (resolved by access code) and its claimable placeholder members." }, "CloneStructureResponse": { "properties": { "event_id": { "type": "integer", "title": "Event Id" }, "source_event_id": { "type": "integer", "title": "Source Event Id" }, "created": { "additionalProperties": { "type": "integer" }, "type": "object", "title": "Created" } }, "type": "object", "required": [ "event_id", "source_event_id", "created" ], "title": "CloneStructureResponse", "description": "How many rows of each kind the clone created." }, "ConfigurationIssueResponse": { "properties": { "code": { "type": "string", "title": "Code" }, "severity": { "type": "string", "title": "Severity" }, "message": { "type": "string", "title": "Message" }, "fields": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Fields" }, "entity_type": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Entity Type" }, "entity_ids": { "anyOf": [ { "items": { "type": "integer" }, "type": "array" }, { "type": "null" } ], "title": "Entity Ids" }, "suggestion": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Suggestion" }, "autofix": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Autofix" } }, "type": "object", "required": [ "code", "severity", "message" ], "title": "ConfigurationIssueResponse" }, "ConfigurationStatusResponse": { "properties": { "event_type": { "type": "string", "title": "Event Type" }, "event_profile": { "type": "string", "title": "Event Profile" }, "ready": { "type": "boolean", "title": "Ready" }, "capabilities": { "additionalProperties": { "$ref": "#/components/schemas/EffectiveCapabilityResponse" }, "type": "object", "title": "Capabilities" }, "issues": { "items": { "$ref": "#/components/schemas/ConfigurationIssueResponse" }, "type": "array", "title": "Issues" } }, "type": "object", "required": [ "event_type", "event_profile", "ready", "capabilities", "issues" ], "title": "ConfigurationStatusResponse" }, "ContestRequest": { "properties": { "reason": { "type": "string", "maxLength": 1000, "minLength": 1, "title": "Reason" } }, "type": "object", "required": [ "reason" ], "title": "ContestRequest", "description": "A team's dispute of a result. The reason is required and bounded." }, "DeferredResultResponse": { "properties": { "id": { "type": "integer", "title": "Id" }, "activity_id": { "type": "integer", "title": "Activity Id" }, "team_id": { "type": "integer", "title": "Team Id" }, "judgment_status": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Judgment Status" }, "media_urls": { "items": { "type": "string" }, "type": "array", "title": "Media Urls" }, "final_score": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Final Score" }, "is_completed": { "type": "boolean", "title": "Is Completed" } }, "type": "object", "required": [ "id", "activity_id", "team_id", "media_urls", "is_completed" ], "title": "DeferredResultResponse" }, "DetailedCheckPoint": { "properties": { "name": { "type": "string", "title": "Name" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "latitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Latitude" }, "longitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Longitude" }, "order": { "type": "integer", "title": "Order" }, "arrival_radius_m": { "type": "integer", "title": "Arrival Radius M", "default": 50 }, "clue": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Clue" }, "clue_media_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Clue Media Url" }, "stage_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Stage Id" }, "available_from": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Available From" }, "available_until": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Available Until" }, "id": { "type": "integer", "title": "Id" }, "is_redacted": { "type": "boolean", "title": "Is Redacted", "default": false }, "search_latitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Search Latitude" }, "search_longitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Search Longitude" }, "search_radius_m": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Search Radius M" }, "is_reachable": { "type": "boolean", "title": "Is Reachable", "default": false } }, "type": "object", "required": [ "name", "order", "id" ], "title": "DetailedCheckPoint" }, "DetailedTeam": { "properties": { "last_checkpoint_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Last Checkpoint Number" }, "current_checkpoint_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Current Checkpoint Number" }, "resolved_checkpoint_orders": { "items": { "type": "integer" }, "type": "array", "title": "Resolved Checkpoint Orders", "default": [] }, "open_checkpoint_orders": { "items": { "type": "integer" }, "type": "array", "title": "Open Checkpoint Orders", "default": [] }, "is_route_finished": { "type": "boolean", "title": "Is Route Finished", "default": false }, "started_at": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Started At" }, "elapsed_seconds": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Elapsed Seconds" }, "finished_at": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Finished At" }, "id": { "type": "integer", "title": "Id" }, "name": { "type": "string", "title": "Name" }, "total": { "type": "integer", "title": "Total" }, "classification": { "type": "integer", "title": "Classification" }, "versus_group_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Versus Group Id" }, "photo_url": { "type": "string", "title": "Photo Url", "default": "" }, "start_offset_minutes": { "type": "integer", "title": "Start Offset Minutes", "default": 0 }, "checkpoints": { "items": { "$ref": "#/components/schemas/CheckpointProgress" }, "type": "array", "title": "Checkpoints", "default": [] }, "members": { "items": { "$ref": "#/components/schemas/ListingUser" }, "type": "array", "title": "Members" }, "total_checkpoints": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Total Checkpoints" }, "penalties_per_checkpoint": { "items": { "$ref": "#/components/schemas/CheckpointPenalties" }, "type": "array", "title": "Penalties Per Checkpoint", "default": [] } }, "type": "object", "required": [ "id", "name", "total", "classification", "members" ], "title": "DetailedTeam" }, "DynamicAwardCreate": { "properties": { "team_id": { "type": "integer", "title": "Team Id" }, "points": { "type": "number", "title": "Points" }, "reason": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Reason" } }, "type": "object", "required": [ "team_id", "points" ], "title": "DynamicAwardCreate" }, "DynamicAwardResponse": { "properties": { "id": { "type": "integer", "title": "Id" }, "team_id": { "type": "integer", "title": "Team Id" }, "event_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Event Id" }, "activity_result_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Activity Result Id" }, "points": { "type": "number", "title": "Points" }, "reason": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Reason" }, "is_active": { "type": "boolean", "title": "Is Active" } }, "type": "object", "required": [ "id", "team_id", "points", "is_active" ], "title": "DynamicAwardResponse" }, "DynamicRuleCreate": { "properties": { "name": { "type": "string", "title": "Name" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "rule_type": { "type": "string", "enum": [ "penalty_counter", "bonus_counter" ], "title": "Rule Type", "default": "penalty_counter" }, "points": { "type": "number", "title": "Points", "default": 0.0 }, "max_points": { "anyOf": [ { "type": "number", "minimum": 0.0 }, { "type": "null" } ], "title": "Max Points" }, "is_active": { "type": "boolean", "title": "Is Active", "default": true } }, "type": "object", "required": [ "name" ], "title": "DynamicRuleCreate", "description": "A global counter shown to staff at every checkpoint.\n\n``rule_type`` picks the side: ``penalty_counter`` (\"cada X = -N pontos\") or\n``bonus_counter`` (\"cada X = +N pontos\"). ``points`` is the magnitude\napplied per occurrence, always positive. Defaults to a penalty counter, so\nclients written before bonus rules existed keep working unchanged." }, "DynamicRuleResponse": { "properties": { "id": { "type": "integer", "title": "Id" }, "event_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Event Id" }, "name": { "type": "string", "title": "Name" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "rule_type": { "type": "string", "title": "Rule Type" }, "points": { "type": "number", "title": "Points" }, "max_points": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Max Points" }, "is_active": { "type": "boolean", "title": "Is Active" } }, "type": "object", "required": [ "id", "name", "rule_type", "points", "is_active" ], "title": "DynamicRuleResponse" }, "DynamicRuleUpdate": { "properties": { "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Name" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "points": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Points" }, "max_points": { "anyOf": [ { "type": "number", "minimum": 0.0 }, { "type": "null" } ], "title": "Max Points" }, "is_active": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Is Active" } }, "type": "object", "title": "DynamicRuleUpdate", "description": "No ``rule_type``: the type is fixed at creation (see the service)." }, "EarnedBadge": { "properties": { "code": { "type": "string", "title": "Code" }, "awarded_at": { "type": "string", "format": "date-time", "title": "Awarded At" }, "meta": { "additionalProperties": true, "type": "object", "title": "Meta", "default": {} } }, "type": "object", "required": [ "code", "awarded_at" ], "title": "EarnedBadge", "description": "A badge a team has earned, keyed by definition code." }, "EffectiveCapabilityResponse": { "properties": { "policy": { "type": "string", "title": "Policy" }, "configured": { "type": "boolean", "title": "Configured" }, "available": { "type": "boolean", "title": "Available" }, "effective": { "type": "boolean", "title": "Effective" } }, "type": "object", "required": [ "policy", "configured", "available", "effective" ], "title": "EffectiveCapabilityResponse" }, "EvaluationHistoryEntry": { "properties": { "id": { "type": "integer", "title": "Id" }, "result_id": { "type": "integer", "title": "Result Id" }, "action": { "type": "string", "title": "Action" }, "editor_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Editor Id" }, "editor_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Editor Name" }, "changes": { "additionalProperties": true, "type": "object", "title": "Changes" }, "note": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Note" }, "created_at": { "type": "string", "format": "date-time", "title": "Created At" } }, "type": "object", "required": [ "id", "result_id", "action", "created_at" ], "title": "EvaluationHistoryEntry", "description": "One audit-trail row: who changed what (or contested), and when." }, "EventProfile": { "type": "string", "enum": [ "custom", "autonomous", "guided", "staffed", "self_checkin", "rotation" ], "title": "EventProfile" }, "EventType": { "type": "string", "enum": [ "rally_tascas", "peddy_paper", "generic", "olympic" ], "title": "EventType", "description": "Kind of event. Drives terminology and which mechanics are available.\n\n- ``rally_tascas``: the classic pub-crawl rally (drinking mechanics:\n pukes/skips/extra shots apply).\n- ``peddy_paper``: a city route / treasure-hunt style game (no drinking\n mechanics).\n- ``generic``: any other checkpoint-based competition." }, "GlobalRanking": { "properties": { "rankings": { "items": { "$ref": "#/components/schemas/TeamRanking" }, "type": "array", "title": "Rankings" }, "last_updated": { "type": "string", "format": "date-time", "title": "Last Updated" } }, "type": "object", "required": [ "rankings", "last_updated" ], "title": "GlobalRanking", "description": "Schema for global team ranking" }, "GuideArrivalRequest": { "properties": { "team_id": { "type": "integer", "title": "Team Id" } }, "type": "object", "required": [ "team_id" ], "title": "GuideArrivalRequest" }, "GuideArrivalResponse": { "properties": { "team_id": { "type": "integer", "title": "Team Id" }, "checkpoint_id": { "type": "integer", "title": "Checkpoint Id" }, "already_registered": { "type": "boolean", "title": "Already Registered" }, "auto_completed": { "type": "boolean", "title": "Auto Completed" } }, "type": "object", "required": [ "team_id", "checkpoint_id", "already_registered", "auto_completed" ], "title": "GuideArrivalResponse" }, "GuideCheckpointResponse": { "properties": { "id": { "type": "integer", "title": "Id" }, "name": { "type": "string", "title": "Name" }, "order": { "type": "integer", "title": "Order" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "clue": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Clue" }, "clue_media_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Clue Media Url" }, "staff_script": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Staff Script" }, "challenge_brief": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Challenge Brief" }, "latitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Latitude" }, "longitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Longitude" }, "media": { "items": { "$ref": "#/components/schemas/GuideMediaItem" }, "type": "array", "title": "Media" }, "indications": { "items": { "$ref": "#/components/schemas/GuideIndicationItem" }, "type": "array", "title": "Indications" }, "is_current": { "type": "boolean", "title": "Is Current", "default": false } }, "type": "object", "required": [ "id", "name", "order", "media", "indications" ], "title": "GuideCheckpointResponse" }, "GuideIndicationItem": { "properties": { "id": { "type": "integer", "title": "Id" }, "hint": { "type": "string", "title": "Hint" }, "question": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Question" }, "expected_answer": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Expected Answer" }, "order": { "type": "integer", "title": "Order" } }, "type": "object", "required": [ "id", "hint", "order" ], "title": "GuideIndicationItem" }, "GuideMediaItem": { "properties": { "id": { "type": "integer", "title": "Id" }, "kind": { "type": "string", "title": "Kind" }, "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Url" }, "caption": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Caption" }, "display_order": { "type": "integer", "title": "Display Order" } }, "type": "object", "required": [ "id", "kind", "display_order" ], "title": "GuideMediaItem" }, "GuideTeamAtCheckpoint": { "properties": { "team_id": { "type": "integer", "title": "Team Id" }, "team_name": { "type": "string", "title": "Team Name" }, "arrived_at": { "type": "string", "format": "date-time", "title": "Arrived At" }, "arrived_by_guide": { "type": "boolean", "title": "Arrived By Guide" }, "revealed_indication_ids": { "items": { "type": "integer" }, "type": "array", "title": "Revealed Indication Ids" } }, "type": "object", "required": [ "team_id", "team_name", "arrived_at", "arrived_by_guide", "revealed_indication_ids" ], "title": "GuideTeamAtCheckpoint" }, "HTTPValidationError": { "properties": { "detail": { "items": { "$ref": "#/components/schemas/ValidationError" }, "type": "array", "title": "Detail" } }, "type": "object", "title": "HTTPValidationError" }, "HintReveal": { "properties": { "checkpoint_id": { "type": "integer", "title": "Checkpoint Id" }, "indication_id": { "type": "integer", "title": "Indication Id" }, "hint": { "type": "string", "title": "Hint" }, "cost": { "type": "integer", "title": "Cost" }, "remaining": { "type": "integer", "title": "Remaining" } }, "type": "object", "required": [ "checkpoint_id", "indication_id", "hint", "cost", "remaining" ], "title": "HintReveal" }, "HomeSection": { "properties": { "key": { "type": "string", "title": "Key" }, "visible": { "type": "boolean", "title": "Visible", "default": true } }, "type": "object", "required": [ "key" ], "title": "HomeSection" }, "JudgeRequest": { "properties": { "points": { "type": "number", "title": "Points" }, "notes": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Notes" } }, "type": "object", "required": [ "points" ], "title": "JudgeRequest" }, "ListingTeam": { "properties": { "last_checkpoint_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Last Checkpoint Number" }, "current_checkpoint_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Current Checkpoint Number" }, "resolved_checkpoint_orders": { "items": { "type": "integer" }, "type": "array", "title": "Resolved Checkpoint Orders", "default": [] }, "open_checkpoint_orders": { "items": { "type": "integer" }, "type": "array", "title": "Open Checkpoint Orders", "default": [] }, "is_route_finished": { "type": "boolean", "title": "Is Route Finished", "default": false }, "started_at": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Started At" }, "elapsed_seconds": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Elapsed Seconds" }, "finished_at": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Finished At" }, "id": { "type": "integer", "title": "Id" }, "name": { "type": "string", "title": "Name" }, "total": { "type": "integer", "title": "Total" }, "classification": { "type": "integer", "title": "Classification" }, "versus_group_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Versus Group Id" }, "photo_url": { "type": "string", "title": "Photo Url", "default": "" }, "start_offset_minutes": { "type": "integer", "title": "Start Offset Minutes", "default": 0 }, "num_members": { "type": "integer", "title": "Num Members" }, "last_checkpoint_time": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Last Checkpoint Time" }, "last_checkpoint_score": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Last Checkpoint Score" }, "last_checkpoint_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Last Checkpoint Name" } }, "type": "object", "required": [ "id", "name", "total", "classification", "num_members", "last_checkpoint_time" ], "title": "ListingTeam", "description": "The schema returned when listing multiple teams" }, "ListingUser": { "properties": { "name": { "type": "string", "title": "Name" }, "team_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Team Id" }, "is_captain": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Is Captain", "default": false }, "id": { "type": "integer", "title": "Id" }, "is_linked": { "type": "boolean", "title": "Is Linked", "default": false } }, "type": "object", "required": [ "name", "id" ], "title": "ListingUser" }, "ManualBadgeAwardCreate": { "properties": { "team_id": { "type": "integer", "title": "Team Id" }, "badge_code": { "type": "string", "title": "Badge Code" }, "activity_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Activity Id" }, "checkpoint_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Checkpoint Id" } }, "type": "object", "required": [ "team_id", "badge_code" ], "title": "ManualBadgeAwardCreate" }, "MediaKind": { "type": "string", "enum": [ "photo", "fun_fact", "qr", "spotify", "link" ], "title": "MediaKind" }, "MetricsSummary": { "properties": { "requests_total": { "type": "number", "title": "Requests Total" }, "errors_5xx": { "type": "number", "title": "Errors 5Xx" }, "rate_limit_rejections": { "type": "number", "title": "Rate Limit Rejections" }, "request_duration_seconds_sum": { "type": "number", "title": "Request Duration Seconds Sum" }, "request_duration_seconds_count": { "type": "number", "title": "Request Duration Seconds Count" } }, "type": "object", "required": [ "requests_total", "errors_5xx", "rate_limit_rejections", "request_duration_seconds_sum", "request_duration_seconds_count" ], "title": "MetricsSummary", "description": "Prometheus counters aggregated for the admin panel.\n\n``request_duration_seconds_sum`` / ``_count`` are the raw histogram\naccumulators rather than a pre-computed average: the panel diffs\nsuccessive polls to derive the latency of the interval between them,\nwhich the average alone cannot express." }, "OidcUserSearchResult": { "properties": { "id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Id" }, "name": { "type": "string", "title": "Name" }, "email": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Email" }, "authentik_sub": { "type": "string", "title": "Authentik Sub" } }, "type": "object", "required": [ "name", "authentik_sub" ], "title": "OidcUserSearchResult", "description": "A NEI account that can be linked to a placeholder member.\n\n``id`` is the local mirror user id when the account has already logged in\n(else null). ``authentik_sub`` is the stable identifier used to link." }, "PaceRanking": { "properties": { "event_id": { "type": "integer", "title": "Event Id" }, "entries": { "items": { "$ref": "#/components/schemas/TeamPaceEntry" }, "type": "array", "title": "Entries" } }, "type": "object", "required": [ "event_id", "entries" ], "title": "PaceRanking" }, "Page_RallyGuideAssignmentWithTeam_": { "properties": { "items": { "items": { "$ref": "#/components/schemas/RallyGuideAssignmentWithTeam" }, "type": "array", "title": "Items" }, "total": { "type": "integer", "title": "Total" }, "page": { "type": "integer", "title": "Page" }, "page_size": { "type": "integer", "title": "Page Size" } }, "type": "object", "required": [ "items", "total", "page", "page_size" ], "title": "Page[RallyGuideAssignmentWithTeam]" }, "Page_RallyStaffAssignmentWithCheckpoint_": { "properties": { "items": { "items": { "$ref": "#/components/schemas/RallyStaffAssignmentWithCheckpoint" }, "type": "array", "title": "Items" }, "total": { "type": "integer", "title": "Total" }, "page": { "type": "integer", "title": "Page" }, "page_size": { "type": "integer", "title": "Page Size" } }, "type": "object", "required": [ "items", "total", "page", "page_size" ], "title": "Page[RallyStaffAssignmentWithCheckpoint]" }, "ParticipationEntry": { "properties": { "event_id": { "type": "integer", "title": "Event Id" }, "event_name": { "type": "string", "title": "Event Name" }, "event_type": { "type": "string", "title": "Event Type" }, "team_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Team Id" }, "team_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Team Name" }, "team_total": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Team Total" }, "team_classification": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Team Classification" }, "is_captain": { "type": "boolean", "title": "Is Captain", "default": false }, "joined_at": { "type": "string", "format": "date-time", "title": "Joined At" } }, "type": "object", "required": [ "event_id", "event_name", "event_type", "joined_at" ], "title": "ParticipationEntry", "description": "One event a person took part in, with their team and result." }, "PrivilegedDetailedTeam": { "properties": { "last_checkpoint_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Last Checkpoint Number" }, "current_checkpoint_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Current Checkpoint Number" }, "resolved_checkpoint_orders": { "items": { "type": "integer" }, "type": "array", "title": "Resolved Checkpoint Orders", "default": [] }, "open_checkpoint_orders": { "items": { "type": "integer" }, "type": "array", "title": "Open Checkpoint Orders", "default": [] }, "is_route_finished": { "type": "boolean", "title": "Is Route Finished", "default": false }, "started_at": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Started At" }, "elapsed_seconds": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Elapsed Seconds" }, "finished_at": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Finished At" }, "id": { "type": "integer", "title": "Id" }, "name": { "type": "string", "title": "Name" }, "total": { "type": "integer", "title": "Total" }, "classification": { "type": "integer", "title": "Classification" }, "versus_group_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Versus Group Id" }, "photo_url": { "type": "string", "title": "Photo Url", "default": "" }, "start_offset_minutes": { "type": "integer", "title": "Start Offset Minutes", "default": 0 }, "checkpoints": { "items": { "$ref": "#/components/schemas/CheckpointProgress" }, "type": "array", "title": "Checkpoints", "default": [] }, "members": { "items": { "$ref": "#/components/schemas/ListingUser" }, "type": "array", "title": "Members" }, "total_checkpoints": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Total Checkpoints" }, "penalties_per_checkpoint": { "items": { "$ref": "#/components/schemas/CheckpointPenalties" }, "type": "array", "title": "Penalties Per Checkpoint", "default": [] }, "access_code": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Access Code" } }, "type": "object", "required": [ "id", "name", "total", "classification", "members" ], "title": "PrivilegedDetailedTeam", "description": "DetailedTeam plus the team's access code.\n\nThe access code is the sole authentication factor for team login, so it is\nonly ever exposed to the team itself or to admin/staff-scoped callers.\nIt is None whenever the caller is not entitled to see it." }, "ProfileResponse": { "properties": { "authentik_sub": { "type": "string", "title": "Authentik Sub" }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Name" }, "email": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Email" }, "scopes": { "items": { "type": "string" }, "type": "array", "title": "Scopes", "default": [] }, "current_team_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Current Team Id" }, "participations": { "items": { "$ref": "#/components/schemas/ParticipationEntry" }, "type": "array", "title": "Participations", "default": [] } }, "type": "object", "required": [ "authentik_sub" ], "title": "ProfileResponse", "description": "A person's rally profile: identity + participation history." }, "ProximityReading": { "properties": { "checkpoint_id": { "type": "integer", "title": "Checkpoint Id" }, "band": { "type": "string", "title": "Band" }, "is_within_radius": { "type": "boolean", "title": "Is Within Radius" }, "direction": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Direction" } }, "type": "object", "required": [ "checkpoint_id", "band", "is_within_radius" ], "title": "ProximityReading" }, "ProximityRequest": { "properties": { "latitude": { "type": "number", "maximum": 90.0, "minimum": -90.0, "title": "Latitude" }, "longitude": { "type": "number", "maximum": 180.0, "minimum": -180.0, "title": "Longitude" } }, "type": "object", "required": [ "latitude", "longitude" ], "title": "ProximityRequest" }, "PushBroadcastRequest": { "properties": { "title": { "type": "string", "maxLength": 100, "minLength": 1, "title": "Title" }, "body": { "type": "string", "maxLength": 500, "minLength": 1, "title": "Body" }, "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Url" } }, "type": "object", "required": [ "title", "body" ], "title": "PushBroadcastRequest", "description": "An admin announcement sent to every subscribed device at once." }, "PushBroadcastResult": { "properties": { "sent": { "type": "integer", "title": "Sent" } }, "type": "object", "required": [ "sent" ], "title": "PushBroadcastResult" }, "PushCheckpointAnnouncementRequest": { "properties": { "body": { "type": "string", "maxLength": 500, "minLength": 1, "title": "Body" }, "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Url" } }, "type": "object", "required": [ "body" ], "title": "PushCheckpointAnnouncementRequest", "description": "A staff announcement about their own post. No `title` \u2014 the post's\nname is stamped on automatically, so the announcement can't masquerade\nas being about a different checkpoint or as a generic admin broadcast." }, "PushSubscriptionCreate": { "properties": { "endpoint": { "type": "string", "title": "Endpoint" }, "keys": { "$ref": "#/components/schemas/PushSubscriptionKeys" } }, "type": "object", "required": [ "endpoint", "keys" ], "title": "PushSubscriptionCreate", "description": "Body shape of the browser's `PushSubscription.toJSON()`." }, "PushSubscriptionKeys": { "properties": { "p256dh": { "type": "string", "title": "P256Dh" }, "auth": { "type": "string", "title": "Auth" } }, "type": "object", "required": [ "p256dh", "auth" ], "title": "PushSubscriptionKeys" }, "PushSubscriptionRead": { "properties": { "id": { "type": "integer", "title": "Id" }, "endpoint": { "type": "string", "title": "Endpoint" } }, "type": "object", "required": [ "id", "endpoint" ], "title": "PushSubscriptionRead" }, "PushSubscriptionUnsubscribe": { "properties": { "endpoint": { "type": "string", "title": "Endpoint" } }, "type": "object", "required": [ "endpoint" ], "title": "PushSubscriptionUnsubscribe" }, "RallyEventCreate": { "properties": { "name": { "type": "string", "maxLength": 255, "minLength": 1, "title": "Name" }, "slug": { "anyOf": [ { "type": "string", "maxLength": 120 }, { "type": "null" } ], "title": "Slug" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "event_type": { "$ref": "#/components/schemas/EventType", "default": "rally_tascas" }, "event_profile": { "anyOf": [ { "$ref": "#/components/schemas/EventProfile" }, { "type": "null" } ] }, "config": { "additionalProperties": true, "type": "object", "title": "Config" }, "is_active": { "type": "boolean", "title": "Is Active", "default": true }, "is_current": { "type": "boolean", "title": "Is Current", "default": false }, "start_time": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Start Time" }, "end_time": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "End Time" } }, "type": "object", "required": [ "name" ], "title": "RallyEventCreate", "description": "Schema for creating a rally event" }, "RallyEventResponse": { "properties": { "name": { "type": "string", "maxLength": 255, "minLength": 1, "title": "Name" }, "slug": { "anyOf": [ { "type": "string", "maxLength": 120 }, { "type": "null" } ], "title": "Slug" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "event_type": { "$ref": "#/components/schemas/EventType", "default": "rally_tascas" }, "event_profile": { "anyOf": [ { "$ref": "#/components/schemas/EventProfile" }, { "type": "null" } ] }, "config": { "additionalProperties": true, "type": "object", "title": "Config" }, "is_active": { "type": "boolean", "title": "Is Active", "default": true }, "is_current": { "type": "boolean", "title": "Is Current", "default": false }, "start_time": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Start Time" }, "end_time": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "End Time" }, "id": { "type": "integer", "title": "Id" }, "created_at": { "type": "string", "format": "date-time", "title": "Created At" }, "updated_at": { "type": "string", "format": "date-time", "title": "Updated At" } }, "type": "object", "required": [ "name", "id", "created_at", "updated_at" ], "title": "RallyEventResponse", "description": "Schema for rally event response" }, "RallyEventUpdate": { "properties": { "name": { "anyOf": [ { "type": "string", "maxLength": 255, "minLength": 1 }, { "type": "null" } ], "title": "Name" }, "slug": { "anyOf": [ { "type": "string", "maxLength": 120 }, { "type": "null" } ], "title": "Slug" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "config": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Config" }, "is_active": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Is Active" }, "is_current": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Is Current" }, "start_time": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Start Time" }, "end_time": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "End Time" } }, "additionalProperties": false, "type": "object", "title": "RallyEventUpdate", "description": "Schema for updating a rally event" }, "RallyGuideAssignmentWithTeam": { "properties": { "user_id": { "type": "integer", "title": "User Id" }, "team_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Team Id" }, "id": { "type": "integer", "title": "Id" }, "team_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Team Name" }, "user_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User Name" }, "user_email": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User Email" } }, "type": "object", "required": [ "user_id", "id" ], "title": "RallyGuideAssignmentWithTeam", "description": "Guide assignment with team details" }, "RallySettingsResponse": { "properties": { "max_teams": { "type": "integer", "minimum": 1.0, "title": "Max Teams" }, "max_members_per_team": { "type": "integer", "minimum": 1.0, "title": "Max Members Per Team" }, "enable_versus": { "type": "boolean", "title": "Enable Versus" }, "penalty_per_puke": { "type": "integer", "maximum": 0.0, "title": "Penalty Per Puke" }, "penalty_per_not_drinking": { "type": "integer", "maximum": 0.0, "title": "Penalty Per Not Drinking" }, "bonus_per_extra_shot": { "type": "integer", "title": "Bonus Per Extra Shot" }, "max_extra_shots_per_member": { "type": "integer", "minimum": 0.0, "title": "Max Extra Shots Per Member" }, "default_max_bonus_points": { "anyOf": [ { "type": "integer", "minimum": 0.0 }, { "type": "null" } ], "title": "Default Max Bonus Points" }, "checkpoint_order_matters": { "type": "boolean", "title": "Checkpoint Order Matters" }, "enable_staff_scoring": { "type": "boolean", "title": "Enable Staff Scoring" }, "show_live_leaderboard": { "type": "boolean", "title": "Show Live Leaderboard" }, "show_team_details": { "type": "boolean", "title": "Show Team Details" }, "show_checkpoint_map": { "type": "boolean", "title": "Show Checkpoint Map" }, "participant_view_enabled": { "type": "boolean", "title": "Participant View Enabled" }, "show_route_mode": { "type": "string", "enum": [ "focused", "complete" ], "title": "Show Route Mode" }, "show_score_mode": { "type": "string", "enum": [ "hidden", "individual", "competitive" ], "title": "Show Score Mode" }, "rally_theme": { "type": "string", "title": "Rally Theme" }, "event_name": { "type": "string", "title": "Event Name", "default": "Rally Tascas" }, "event_subtitle": { "type": "string", "title": "Event Subtitle", "default": "" }, "accent_color": { "type": "string", "title": "Accent Color", "default": "" }, "button_style": { "type": "string", "title": "Button Style", "default": "plain" }, "background_style": { "type": "string", "title": "Background Style", "default": "plain" }, "visual_presets": { "items": { "$ref": "#/components/schemas/VisualPreset" }, "type": "array", "title": "Visual Presets", "default": [] }, "public_access_enabled": { "type": "boolean", "title": "Public Access Enabled" }, "allow_staff_registration": { "type": "boolean", "title": "Allow Staff Registration", "default": false }, "allow_photo_as_team_photo": { "type": "boolean", "title": "Allow Photo As Team Photo", "default": false }, "gps_checkin_enabled": { "type": "boolean", "title": "Gps Checkin Enabled", "default": false }, "reveal_next_checkpoint": { "type": "boolean", "title": "Reveal Next Checkpoint", "default": true }, "hint_penalty": { "type": "integer", "maximum": 0.0, "title": "Hint Penalty", "default": 0 }, "skip_penalty": { "type": "integer", "maximum": 0.0, "title": "Skip Penalty", "default": 0 }, "hints_enabled": { "type": "boolean", "title": "Hints Enabled", "default": true }, "skip_enabled": { "type": "boolean", "title": "Skip Enabled", "default": true }, "guide_manual_arrival_enabled": { "type": "boolean", "title": "Guide Manual Arrival Enabled", "default": true }, "reveal_on_arrival": { "type": "boolean", "title": "Reveal On Arrival", "default": true }, "proximity_enabled": { "type": "boolean", "title": "Proximity Enabled", "default": false }, "compass_enabled": { "type": "boolean", "title": "Compass Enabled", "default": false }, "search_radius_m": { "type": "integer", "minimum": 0.0, "title": "Search Radius M", "default": 0 }, "route_stages_enabled": { "type": "boolean", "title": "Route Stages Enabled", "default": false }, "checkpoint_hours_enabled": { "type": "boolean", "title": "Checkpoint Hours Enabled", "default": true }, "leg_time_scoring_enabled": { "type": "boolean", "title": "Leg Time Scoring Enabled", "default": false }, "leg_time_target_minutes": { "type": "integer", "minimum": 0.0, "title": "Leg Time Target Minutes", "default": 10 }, "leg_time_points_per_minute": { "type": "integer", "title": "Leg Time Points Per Minute", "default": 0 }, "leg_time_max_adjustment": { "type": "integer", "minimum": 0.0, "title": "Leg Time Max Adjustment", "default": 20 }, "guide_mode_enabled": { "type": "boolean", "title": "Guide Mode Enabled", "default": false }, "guide_mode_active": { "type": "boolean", "title": "Guide Mode Active", "default": false }, "badges_enabled": { "type": "boolean", "title": "Badges Enabled", "default": true }, "home_layout": { "items": { "$ref": "#/components/schemas/HomeSection" }, "type": "array", "title": "Home Layout", "default": [ { "key": "home_hero", "visible": true }, { "key": "rally_marquee", "visible": true }, { "key": "event_stats", "visible": true }, { "key": "live_top5", "visible": true }, { "key": "how_it_works", "visible": true }, { "key": "postos_preview", "visible": true }, { "key": "home_bottom_banner", "visible": true } ] }, "ticker_items": { "items": { "type": "string" }, "type": "array", "title": "Ticker Items", "default": [ "RALLY TASCAS 2026", "NEI", "EQUIPAS", "POSTOS", "PONTUA\u00c7\u00c3O" ] }, "rules_sections": { "items": { "$ref": "#/components/schemas/RuleSection" }, "type": "array", "title": "Rules Sections", "default": [] }, "rally_start_time": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Rally Start Time" }, "rally_end_time": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Rally End Time" }, "event_type": { "type": "string", "title": "Event Type", "default": "rally_tascas" }, "event_profile": { "type": "string", "title": "Event Profile", "default": "custom" }, "effective_capabilities": { "additionalProperties": { "type": "boolean" }, "type": "object", "title": "Effective Capabilities" }, "banner_url": { "type": "string", "title": "Banner Url", "default": "" }, "logo_url": { "type": "string", "title": "Logo Url", "default": "" }, "favicon_url": { "type": "string", "title": "Favicon Url", "default": "" }, "rules_pdf_url": { "type": "string", "title": "Rules Pdf Url", "default": "" } }, "type": "object", "required": [ "max_teams", "max_members_per_team", "enable_versus", "penalty_per_puke", "penalty_per_not_drinking", "bonus_per_extra_shot", "max_extra_shots_per_member", "checkpoint_order_matters", "enable_staff_scoring", "show_live_leaderboard", "show_team_details", "show_checkpoint_map", "participant_view_enabled", "show_route_mode", "show_score_mode", "rally_theme", "public_access_enabled" ], "title": "RallySettingsResponse" }, "RallySettingsUpdate": { "properties": { "max_teams": { "type": "integer", "minimum": 1.0, "title": "Max Teams" }, "max_members_per_team": { "type": "integer", "minimum": 1.0, "title": "Max Members Per Team" }, "enable_versus": { "type": "boolean", "title": "Enable Versus" }, "penalty_per_puke": { "type": "integer", "maximum": 0.0, "title": "Penalty Per Puke" }, "penalty_per_not_drinking": { "type": "integer", "maximum": 0.0, "title": "Penalty Per Not Drinking" }, "bonus_per_extra_shot": { "type": "integer", "title": "Bonus Per Extra Shot" }, "max_extra_shots_per_member": { "type": "integer", "minimum": 0.0, "title": "Max Extra Shots Per Member" }, "default_max_bonus_points": { "anyOf": [ { "type": "integer", "minimum": 0.0 }, { "type": "null" } ], "title": "Default Max Bonus Points" }, "checkpoint_order_matters": { "type": "boolean", "title": "Checkpoint Order Matters" }, "enable_staff_scoring": { "type": "boolean", "title": "Enable Staff Scoring" }, "show_live_leaderboard": { "type": "boolean", "title": "Show Live Leaderboard" }, "show_team_details": { "type": "boolean", "title": "Show Team Details" }, "show_checkpoint_map": { "type": "boolean", "title": "Show Checkpoint Map" }, "participant_view_enabled": { "type": "boolean", "title": "Participant View Enabled" }, "show_route_mode": { "type": "string", "enum": [ "focused", "complete" ], "title": "Show Route Mode" }, "show_score_mode": { "type": "string", "enum": [ "hidden", "individual", "competitive" ], "title": "Show Score Mode" }, "rally_theme": { "type": "string", "title": "Rally Theme" }, "event_name": { "type": "string", "title": "Event Name", "default": "Rally Tascas" }, "event_subtitle": { "type": "string", "title": "Event Subtitle", "default": "" }, "accent_color": { "type": "string", "title": "Accent Color", "default": "" }, "button_style": { "type": "string", "title": "Button Style", "default": "plain" }, "background_style": { "type": "string", "title": "Background Style", "default": "plain" }, "visual_presets": { "items": { "$ref": "#/components/schemas/VisualPreset" }, "type": "array", "title": "Visual Presets", "default": [] }, "public_access_enabled": { "type": "boolean", "title": "Public Access Enabled" }, "allow_staff_registration": { "type": "boolean", "title": "Allow Staff Registration", "default": false }, "allow_photo_as_team_photo": { "type": "boolean", "title": "Allow Photo As Team Photo", "default": false }, "gps_checkin_enabled": { "type": "boolean", "title": "Gps Checkin Enabled", "default": false }, "reveal_next_checkpoint": { "type": "boolean", "title": "Reveal Next Checkpoint", "default": true }, "hint_penalty": { "type": "integer", "maximum": 0.0, "title": "Hint Penalty", "default": 0 }, "skip_penalty": { "type": "integer", "maximum": 0.0, "title": "Skip Penalty", "default": 0 }, "hints_enabled": { "type": "boolean", "title": "Hints Enabled", "default": true }, "skip_enabled": { "type": "boolean", "title": "Skip Enabled", "default": true }, "guide_manual_arrival_enabled": { "type": "boolean", "title": "Guide Manual Arrival Enabled", "default": true }, "reveal_on_arrival": { "type": "boolean", "title": "Reveal On Arrival", "default": true }, "proximity_enabled": { "type": "boolean", "title": "Proximity Enabled", "default": false }, "compass_enabled": { "type": "boolean", "title": "Compass Enabled", "default": false }, "search_radius_m": { "type": "integer", "minimum": 0.0, "title": "Search Radius M", "default": 0 }, "route_stages_enabled": { "type": "boolean", "title": "Route Stages Enabled", "default": false }, "checkpoint_hours_enabled": { "type": "boolean", "title": "Checkpoint Hours Enabled", "default": true }, "leg_time_scoring_enabled": { "type": "boolean", "title": "Leg Time Scoring Enabled", "default": false }, "leg_time_target_minutes": { "type": "integer", "minimum": 0.0, "title": "Leg Time Target Minutes", "default": 10 }, "leg_time_points_per_minute": { "type": "integer", "title": "Leg Time Points Per Minute", "default": 0 }, "leg_time_max_adjustment": { "type": "integer", "minimum": 0.0, "title": "Leg Time Max Adjustment", "default": 20 }, "guide_mode_enabled": { "type": "boolean", "title": "Guide Mode Enabled", "default": false }, "guide_mode_active": { "type": "boolean", "title": "Guide Mode Active", "default": false }, "badges_enabled": { "type": "boolean", "title": "Badges Enabled", "default": true }, "home_layout": { "items": { "$ref": "#/components/schemas/HomeSection" }, "type": "array", "title": "Home Layout", "default": [ { "key": "home_hero", "visible": true }, { "key": "rally_marquee", "visible": true }, { "key": "event_stats", "visible": true }, { "key": "live_top5", "visible": true }, { "key": "how_it_works", "visible": true }, { "key": "postos_preview", "visible": true }, { "key": "home_bottom_banner", "visible": true } ] }, "ticker_items": { "items": { "type": "string" }, "type": "array", "title": "Ticker Items", "default": [ "RALLY TASCAS 2026", "NEI", "EQUIPAS", "POSTOS", "PONTUA\u00c7\u00c3O" ] }, "rules_sections": { "items": { "$ref": "#/components/schemas/RuleSection" }, "type": "array", "title": "Rules Sections", "default": [] } }, "type": "object", "required": [ "max_teams", "max_members_per_team", "enable_versus", "penalty_per_puke", "penalty_per_not_drinking", "bonus_per_extra_shot", "max_extra_shots_per_member", "checkpoint_order_matters", "enable_staff_scoring", "show_live_leaderboard", "show_team_details", "show_checkpoint_map", "participant_view_enabled", "show_route_mode", "show_score_mode", "rally_theme", "public_access_enabled" ], "title": "RallySettingsUpdate" }, "RallyStaffAssignmentWithCheckpoint": { "properties": { "user_id": { "type": "integer", "title": "User Id" }, "checkpoint_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Checkpoint Id" }, "id": { "type": "integer", "title": "Id" }, "checkpoint_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Checkpoint Name" }, "checkpoint_description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Checkpoint Description" }, "user_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User Name" }, "user_email": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User Email" } }, "type": "object", "required": [ "user_id", "id" ], "title": "RallyStaffAssignmentWithCheckpoint", "description": "Staff assignment with checkpoint details" }, "RankRequest": { "properties": { "ordered_result_ids": { "items": { "type": "integer" }, "type": "array", "title": "Ordered Result Ids" }, "notes": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "null" } ], "title": "Notes" } }, "type": "object", "required": [ "ordered_result_ids" ], "title": "RankRequest" }, "Readiness": { "properties": { "status": { "type": "string", "title": "Status" }, "db": { "type": "string", "title": "Db" }, "redis": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Redis" }, "workers": { "items": { "$ref": "#/components/schemas/WorkerHealth" }, "type": "array", "title": "Workers" } }, "type": "object", "required": [ "status", "db", "workers" ], "title": "Readiness", "description": "Aggregated dependency health.\n\n``redis`` is absent when the realtime subsystem is disabled, in which case\nno Redis connection is expected and its state says nothing about\nreadiness." }, "RevealedHint": { "properties": { "indication_id": { "type": "integer", "title": "Indication Id" }, "hint": { "type": "string", "title": "Hint" }, "cost": { "type": "integer", "title": "Cost" }, "revealed_at": { "type": "string", "format": "date-time", "title": "Revealed At" } }, "type": "object", "required": [ "indication_id", "hint", "cost", "revealed_at" ], "title": "RevealedHint" }, "RotationScheduleResponse": { "properties": { "event_id": { "type": "integer", "title": "Event Id" }, "rounds": { "items": { "items": { "additionalProperties": true, "type": "object" }, "type": "array" }, "type": "array", "title": "Rounds" } }, "type": "object", "required": [ "event_id", "rounds" ], "title": "RotationScheduleResponse" }, "RouteStageCreate": { "properties": { "name": { "type": "string", "maxLength": 120, "minLength": 1, "title": "Name" }, "order": { "type": "integer", "minimum": 1.0, "title": "Order" }, "order_matters": { "type": "boolean", "title": "Order Matters", "default": true }, "required_count": { "anyOf": [ { "type": "integer", "minimum": 0.0 }, { "type": "null" } ], "title": "Required Count" } }, "type": "object", "required": [ "name", "order" ], "title": "RouteStageCreate" }, "RouteStageResponse": { "properties": { "name": { "type": "string", "maxLength": 120, "minLength": 1, "title": "Name" }, "order": { "type": "integer", "minimum": 1.0, "title": "Order" }, "order_matters": { "type": "boolean", "title": "Order Matters", "default": true }, "required_count": { "anyOf": [ { "type": "integer", "minimum": 0.0 }, { "type": "null" } ], "title": "Required Count" }, "id": { "type": "integer", "title": "Id" }, "checkpoint_ids": { "items": { "type": "integer" }, "type": "array", "title": "Checkpoint Ids", "default": [] } }, "type": "object", "required": [ "name", "order", "id" ], "title": "RouteStageResponse" }, "RouteStageUpdate": { "properties": { "name": { "anyOf": [ { "type": "string", "maxLength": 120, "minLength": 1 }, { "type": "null" } ], "title": "Name" }, "order": { "anyOf": [ { "type": "integer", "minimum": 1.0 }, { "type": "null" } ], "title": "Order" }, "order_matters": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Order Matters" }, "required_count": { "anyOf": [ { "type": "integer", "minimum": 0.0 }, { "type": "null" } ], "title": "Required Count" } }, "type": "object", "title": "RouteStageUpdate" }, "RouteStatus": { "properties": { "published_count": { "type": "integer", "title": "Published Count" }, "draft_count": { "type": "integer", "title": "Draft Count" }, "incomplete_published_ids": { "items": { "type": "integer" }, "type": "array", "title": "Incomplete Published Ids", "default": [] }, "checkpoints": { "items": { "$ref": "#/components/schemas/AdminCheckPoint" }, "type": "array", "title": "Checkpoints", "default": [] } }, "type": "object", "required": [ "published_count", "draft_count" ], "title": "RouteStatus", "description": "Whether the event's route as a whole is ready to run." }, "RuleSection": { "properties": { "id": { "type": "string", "title": "Id" }, "title": { "type": "string", "title": "Title", "default": "" }, "icon": { "type": "string", "title": "Icon", "default": "HelpCircle" }, "body": { "type": "string", "title": "Body", "default": "" } }, "type": "object", "required": [ "id" ], "title": "RuleSection", "description": "One admin-authored section of the public /rules page." }, "SetTeamPhotoRequest": { "properties": { "image_url": { "type": "string", "title": "Image Url" } }, "type": "object", "required": [ "image_url" ], "title": "SetTeamPhotoRequest" }, "SetTeamPhotoResponse": { "properties": { "team_id": { "type": "integer", "title": "Team Id" }, "photo_url": { "type": "string", "title": "Photo Url" } }, "type": "object", "required": [ "team_id", "photo_url" ], "title": "SetTeamPhotoResponse" }, "StaffCheckinRequest": { "properties": { "team_code": { "type": "string", "title": "Team Code" }, "checkpoint_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Checkpoint Id" } }, "type": "object", "required": [ "team_code" ], "title": "StaffCheckinRequest", "description": "A staff member identifies/checks an arriving team in by its access code." }, "StaffCheckinResponse": { "properties": { "team_id": { "type": "integer", "title": "Team Id" }, "team_name": { "type": "string", "title": "Team Name" }, "checkpoint_id": { "type": "integer", "title": "Checkpoint Id" }, "checkpoint_order": { "type": "integer", "title": "Checkpoint Order" }, "status": { "type": "string", "title": "Status" } }, "type": "object", "required": [ "team_id", "team_name", "checkpoint_id", "checkpoint_order", "status" ], "title": "StaffCheckinResponse", "description": "Result of a staff scan: who the team is, plus what happened to arrival.\n\nThe scan's primary job is *identification* \u2014 letting staff jump straight to\nthe correct team's evaluation without mistakes. Marking arrival is a\nsecondary, best-effort side effect, so the team is always returned even when\narrival was not (re)registered (already here, or scanned too early)." }, "TeamAssignmentUpdate": { "properties": { "team_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Team Id" } }, "type": "object", "title": "TeamAssignmentUpdate" }, "TeamBadgeRead": { "properties": { "id": { "type": "integer", "title": "Id" }, "team_id": { "type": "integer", "title": "Team Id" }, "badge_type": { "type": "string", "title": "Badge Type" }, "activity_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Activity Id" }, "checkpoint_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Checkpoint Id" }, "meta": { "additionalProperties": true, "type": "object", "title": "Meta", "default": {} }, "awarded_at": { "type": "string", "format": "date-time", "title": "Awarded At" } }, "type": "object", "required": [ "id", "team_id", "badge_type", "awarded_at" ], "title": "TeamBadgeRead", "description": "A single badge a team holds." }, "TeamCreate": { "properties": { "name": { "type": "string", "title": "Name" } }, "type": "object", "required": [ "name" ], "title": "TeamCreate" }, "TeamHintSummary": { "properties": { "revealed": { "items": { "$ref": "#/components/schemas/RevealedHint" }, "type": "array", "title": "Revealed" }, "total_spent": { "type": "integer", "title": "Total Spent" } }, "type": "object", "required": [ "revealed", "total_spent" ], "title": "TeamHintSummary", "description": "Every hint this team has bought, across the whole event.\n\nThe per-checkpoint listing only covers the post the team is looking at, so\nwithout this a team that spent points at three posts has no way to add\nthem up \u2014 the DynamicAward rows carrying the charges are admin-only." }, "TeamHints": { "properties": { "checkpoint_id": { "type": "integer", "title": "Checkpoint Id" }, "revealed": { "items": { "$ref": "#/components/schemas/RevealedHint" }, "type": "array", "title": "Revealed" }, "remaining": { "type": "integer", "title": "Remaining" }, "next_cost": { "type": "integer", "title": "Next Cost" } }, "type": "object", "required": [ "checkpoint_id", "revealed", "remaining", "next_cost" ], "title": "TeamHints" }, "TeamLoginRequest": { "properties": { "access_code": { "type": "string", "pattern": "^[A-Z0-9]{4}-[A-Z0-9]{4}$", "title": "Access Code" } }, "type": "object", "required": [ "access_code" ], "title": "TeamLoginRequest", "description": "Request schema for team login" }, "TeamLoginResponse": { "properties": { "access_token": { "type": "string", "title": "Access Token" }, "token_type": { "type": "string", "title": "Token Type", "default": "bearer" }, "team_id": { "type": "integer", "title": "Team Id" }, "team_name": { "type": "string", "title": "Team Name" } }, "type": "object", "required": [ "access_token", "team_id", "team_name" ], "title": "TeamLoginResponse", "description": "Response schema for team login" }, "TeamMemberAdd": { "properties": { "name": { "type": "string", "title": "Name" }, "email": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Email" }, "is_captain": { "type": "boolean", "title": "Is Captain", "default": false } }, "type": "object", "required": [ "name" ], "title": "TeamMemberAdd" }, "TeamMemberLink": { "properties": { "authentik_sub": { "type": "string", "title": "Authentik Sub" }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Name" }, "email": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Email" } }, "type": "object", "required": [ "authentik_sub" ], "title": "TeamMemberLink", "description": "Link a name-only placeholder member to a real NEI (OIDC) account.\n\nIdentified by the account's Authentik subject. ``name``/``email`` are used to\npopulate the local mirror when the account has never logged in yet." }, "TeamMemberLinkSelf": { "properties": { "access_code": { "type": "string", "title": "Access Code" } }, "type": "object", "required": [ "access_code" ], "title": "TeamMemberLinkSelf", "description": "Self-serve claim of a placeholder member by the caller's OIDC account.\n\nThe access code is the proof that the caller belongs to the team: the OIDC\nbearer identifies *who* is calling but says nothing about *which* team they\nmay claim a slot in, so it must be presented explicitly here." }, "TeamMemberResponse": { "properties": { "id": { "type": "integer", "title": "Id" }, "name": { "type": "string", "title": "Name" }, "email": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Email" }, "is_captain": { "type": "boolean", "title": "Is Captain", "default": false }, "is_linked": { "type": "boolean", "title": "Is Linked", "default": false } }, "type": "object", "required": [ "id", "name" ], "title": "TeamMemberResponse" }, "TeamMemberUpdate": { "properties": { "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Name" }, "email": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Email" }, "is_captain": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Is Captain" } }, "type": "object", "title": "TeamMemberUpdate" }, "TeamPaceEntry": { "properties": { "id": { "type": "integer", "title": "Id" }, "name": { "type": "string", "title": "Name" }, "rank": { "type": "integer", "title": "Rank" }, "elapsed_seconds": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Elapsed Seconds" }, "elapsed_display": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Elapsed Display" }, "started_at": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Started At" }, "last_progress_at": { "anyOf": [ { "type": "string", "format": "date-time" }, { "type": "null" } ], "title": "Last Progress At" }, "resolved_count": { "type": "integer", "title": "Resolved Count" }, "total_checkpoints": { "type": "integer", "title": "Total Checkpoints" }, "is_finished": { "type": "boolean", "title": "Is Finished" } }, "type": "object", "required": [ "id", "name", "rank", "elapsed_seconds", "elapsed_display", "started_at", "last_progress_at", "resolved_count", "total_checkpoints", "is_finished" ], "title": "TeamPaceEntry" }, "TeamRanking": { "properties": { "team_id": { "type": "integer", "title": "Team Id" }, "team_name": { "type": "string", "title": "Team Name" }, "total_score": { "type": "number", "title": "Total Score" }, "activities_completed": { "type": "integer", "title": "Activities Completed" }, "rank": { "type": "integer", "title": "Rank" } }, "type": "object", "required": [ "team_id", "team_name", "total_score", "activities_completed", "rank" ], "title": "TeamRanking", "description": "Schema for team ranking" }, "TeamTokenData": { "properties": { "team_id": { "type": "integer", "title": "Team Id" }, "team_name": { "type": "string", "title": "Team Name" } }, "type": "object", "required": [ "team_id", "team_name" ], "title": "TeamTokenData", "description": "Data stored in team JWT token" }, "TeamUpdate": { "properties": { "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Name" }, "access_code": { "anyOf": [ { "type": "string", "pattern": "^[A-Z0-9]{4}-[A-Z0-9]{4}$" }, { "type": "null" } ], "title": "Access Code" }, "start_offset_minutes": { "anyOf": [ { "type": "integer", "maximum": 1440.0, "minimum": 0.0 }, { "type": "null" } ], "title": "Start Offset Minutes" } }, "type": "object", "title": "TeamUpdate" }, "UpdateEventCapabilitiesRequest": { "properties": { "qr_arrival": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Qr Arrival" }, "drinking_scoring": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Drinking Scoring" } }, "type": "object", "title": "UpdateEventCapabilitiesRequest" }, "ValidationError": { "properties": { "loc": { "items": { "anyOf": [ { "type": "string" }, { "type": "integer" } ] }, "type": "array", "title": "Location" }, "msg": { "type": "string", "title": "Message" }, "type": { "type": "string", "title": "Error Type" }, "input": { "title": "Input" }, "ctx": { "type": "object", "title": "Context" } }, "type": "object", "required": [ "loc", "msg", "type" ], "title": "ValidationError" }, "VapidPublicKey": { "properties": { "public_key": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Public Key" } }, "type": "object", "required": [ "public_key" ], "title": "VapidPublicKey" }, "VersusGroupListResponse": { "properties": { "groups": { "items": { "$ref": "#/components/schemas/VersusPairResponse" }, "type": "array", "title": "Groups" } }, "type": "object", "required": [ "groups" ], "title": "VersusGroupListResponse" }, "VersusOpponentResponse": { "properties": { "opponent_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Opponent Id" }, "opponent_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Opponent Name" } }, "type": "object", "required": [ "opponent_id", "opponent_name" ], "title": "VersusOpponentResponse" }, "VersusPairCreate": { "properties": { "team_a_id": { "type": "integer", "title": "Team A Id" }, "team_b_id": { "type": "integer", "title": "Team B Id" } }, "type": "object", "required": [ "team_a_id", "team_b_id" ], "title": "VersusPairCreate" }, "VersusPairResponse": { "properties": { "group_id": { "type": "integer", "title": "Group Id" }, "team_a_id": { "type": "integer", "title": "Team A Id" }, "team_b_id": { "type": "integer", "title": "Team B Id" } }, "type": "object", "required": [ "group_id", "team_a_id", "team_b_id" ], "title": "VersusPairResponse" }, "VisualPreset": { "properties": { "id": { "type": "string", "title": "Id" }, "name": { "type": "string", "title": "Name" }, "accent_color": { "type": "string", "title": "Accent Color", "default": "" }, "button_style": { "type": "string", "title": "Button Style", "default": "plain" }, "background_style": { "type": "string", "title": "Background Style", "default": "plain" } }, "type": "object", "required": [ "id", "name" ], "title": "VisualPreset" }, "WorkerHealth": { "properties": { "name": { "type": "string", "title": "Name" }, "alive": { "type": "boolean", "title": "Alive" }, "last_beat": { "type": "number", "title": "Last Beat" } }, "type": "object", "required": [ "name", "alive", "last_beat" ], "title": "WorkerHealth", "description": "Liveness of one background worker." } }, "securitySchemes": { "HTTPBearer": { "type": "http", "scheme": "bearer" } } } }