Files
mixmaker/openapi/openapi.yaml
lemintare ae19c03542
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
CI / compose (push) Has been cancelled
Add Discord event announcement functionality to backend
This commit introduces a new Discord event announcer to the backend, allowing for event announcements via Discord. It includes the addition of new environment variables for Discord configuration in `.env.example` and `compose.yaml`. The `main.go` file has been updated to initialize the announcer, and a new `discord` package has been created, containing the announcer logic and tests. Additionally, the service layer has been modified to support bracket draft management, enhancing the overall event workflow. Integration tests have been updated to ensure proper functionality of the new features.
2026-07-19 11:21:11 +03:00

1342 lines
42 KiB
YAML

openapi: 3.1.0
info:
title: Mixmaker API
version: 0.1.0
description: API for Overwatch community scrims.
servers:
- url: /
security:
- cookieAuth: []
tags:
- name: Auth
- name: Players
- name: Events
- name: Teams
- name: Series
- name: Tournaments
paths:
/healthz:
get:
security: []
operationId: health
responses:
"200":
description: Healthy
/readyz:
get:
security: []
operationId: ready
responses:
"200":
description: Ready
"503":
description: Not ready
/api/auth/discord:
get:
security: []
tags: [Auth]
operationId: startDiscordLogin
responses:
"302":
description: Redirect to Discord
/api/auth/discord/callback:
get:
security: []
tags: [Auth]
operationId: finishDiscordLogin
parameters:
- name: code
in: query
required: true
schema:
type: string
- name: state
in: query
required: true
schema:
type: string
responses:
"302":
description: Session created
/api/auth/me:
get:
tags: [Auth]
operationId: getCurrentAccount
responses:
"200":
description: Current account
content:
application/json:
schema:
$ref: "#/components/schemas/Session"
"401":
$ref: "#/components/responses/Unauthorized"
/api/auth/logout:
post:
tags: [Auth]
operationId: logout
responses:
"204":
description: Logged out
/api/me/player:
patch:
tags: [Players]
operationId: updateMyPlayer
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PlayerUpdate"
responses:
"200":
description: Updated profile
content:
application/json:
schema:
$ref: "#/components/schemas/Player"
"422":
$ref: "#/components/responses/ValidationError"
/api/players:
get:
tags: [Players]
operationId: listPlayers
responses:
"200":
description: Players
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Player"
/api/accounts:
get:
tags: [Admin]
operationId: listAccounts
responses:
"200":
description: Accounts visible to administrators
content:
application/json:
schema:
type: array
items: { $ref: "#/components/schemas/Account" }
"403": { $ref: "#/components/responses/Forbidden" }
/api/accounts/{accountId}/moderator:
patch:
tags: [Admin]
operationId: setModerator
parameters:
- name: accountId
in: path
required: true
schema: { type: string }
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [moderator]
properties:
moderator: { type: boolean }
responses:
"200": { description: Updated account, content: { application/json: { schema: { $ref: "#/components/schemas/Account" } } } }
"403": { $ref: "#/components/responses/Forbidden" }
/api/events:
get:
tags: [Events]
operationId: listEvents
parameters:
- name: from
in: query
schema:
type: string
format: date-time
responses:
"200":
description: Events
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Event"
post:
tags: [Events]
operationId: createEvent
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/EventInput"
responses:
"201":
description: Event created
content:
application/json:
schema:
$ref: "#/components/schemas/Event"
"403":
$ref: "#/components/responses/Forbidden"
/api/events/{eventId}:
get:
tags: [Events]
operationId: getEvent
parameters:
- $ref: "#/components/parameters/EventId"
responses:
"200":
description: Event details
content:
application/json:
schema:
$ref: "#/components/schemas/Event"
"404":
$ref: "#/components/responses/NotFound"
put:
tags: [Events]
operationId: updateEvent
parameters:
- $ref: "#/components/parameters/EventId"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/EventInput"
responses:
"200":
description: Event updated
content:
application/json:
schema:
$ref: "#/components/schemas/Event"
delete:
tags: [Events]
operationId: deleteEvent
description: Permanently removes the event and all event-scoped data.
parameters:
- $ref: "#/components/parameters/EventId"
responses:
"204": { description: Event deleted }
"403": { $ref: "#/components/responses/Forbidden" }
"404": { $ref: "#/components/responses/NotFound" }
/api/events/{eventId}/cancel:
post:
tags: [Events]
operationId: cancelEvent
parameters:
- $ref: "#/components/parameters/EventId"
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/VersionCommand" } } }
responses:
"200": { description: Event cancelled, content: { application/json: { schema: { $ref: "#/components/schemas/Event" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/events/{eventId}/tournament:
get:
tags: [Tournaments]
operationId: getEventTournament
description: Returns the tournament bracket hydrated with the latest state of every persisted series.
parameters:
- $ref: "#/components/parameters/EventId"
responses:
"200": { description: Live tournament bracket, content: { application/json: { schema: { $ref: "#/components/schemas/Tournament" } } } }
"404": { $ref: "#/components/responses/NotFound" }
/api/events/{eventId}/bracket-draft:
get:
tags: [Tournaments]
operationId: getBracketDraft
parameters: [{ $ref: "#/components/parameters/EventId" }]
responses:
"200": { description: Editable bracket graph, content: { application/json: { schema: { $ref: "#/components/schemas/BracketDraft" } } } }
put:
tags: [Tournaments]
operationId: updateBracketDraft
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/BracketUpdateCommand" } } }
responses:
"200": { description: Updated graph, content: { application/json: { schema: { $ref: "#/components/schemas/BracketDraft" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/events/{eventId}/bracket-draft/initialize:
post:
tags: [Tournaments]
operationId: initializeBracketDraft
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/VersionCommand" } } } }
responses:
"201": { description: Default bracket graph, content: { application/json: { schema: { $ref: "#/components/schemas/BracketDraft" } } } }
/api/events/{eventId}/bracket-draft/reset:
post:
tags: [Tournaments]
operationId: resetBracketDraft
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/VersionCommand" } } } }
responses:
"200": { description: Reset bracket graph, content: { application/json: { schema: { $ref: "#/components/schemas/BracketDraft" } } } }
/api/events/{eventId}/bracket-draft/confirm:
post:
tags: [Tournaments]
operationId: confirmBracketDraft
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody: { required: true, content: { application/json: { schema: { $ref: "#/components/schemas/VersionCommand" } } } }
responses:
"200": { description: Confirmed bracket graph, content: { application/json: { schema: { $ref: "#/components/schemas/BracketDraft" } } } }
/api/events/{eventId}/rsvps:
get:
tags: [Events]
operationId: listRegistrations
parameters:
- $ref: "#/components/parameters/EventId"
responses:
"200":
description: Registrations
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/EventRegistration"
/api/events/{eventId}/participants:
post:
tags: [Events]
operationId: createGuestParticipant
parameters:
- $ref: "#/components/parameters/EventId"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [displayName, ratings, status]
properties:
displayName:
type: string
minLength: 1
ratings:
$ref: "#/components/schemas/Ratings"
status:
type: string
enum: [Going, Maybe, NotGoing]
responses:
"201":
description: Guest participant created and registered
content:
application/json:
schema:
type: object
required: [player, rsvp]
properties:
player:
$ref: "#/components/schemas/Player"
rsvp:
$ref: "#/components/schemas/EventRegistration"
"403":
$ref: "#/components/responses/Forbidden"
/api/events/{eventId}/rsvps/{playerId}:
put:
tags: [Events]
operationId: adminSetRegistration
parameters:
- $ref: "#/components/parameters/EventId"
- $ref: "#/components/parameters/PlayerId"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/RegistrationInput"
responses:
"200":
description: Registration updated by admin
content:
application/json:
schema:
$ref: "#/components/schemas/EventRegistration"
"403":
$ref: "#/components/responses/Forbidden"
delete:
tags: [Events]
operationId: removeParticipantFromEvent
parameters:
- $ref: "#/components/parameters/EventId"
- $ref: "#/components/parameters/PlayerId"
responses:
"204":
description: Participant removed from the event
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
/api/events/{eventId}/balance:
post:
tags: [Teams]
operationId: generateBalanceCandidates
parameters:
- $ref: "#/components/parameters/EventId"
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
seed:
type: integer
format: int64
responses:
"200":
description: Three best candidates
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/BalanceCandidate"
/api/events/{eventId}/registration/close:
post:
tags: [Events]
operationId: closeRegistration
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CloseRegistrationCommand"
responses:
"200": { description: Registration closed, content: { application/json: { schema: { $ref: "#/components/schemas/Event" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/events/{eventId}/workflow/back:
post:
tags: [Events]
operationId: revertEventWorkflowStage
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/VersionCommand" } } }
responses:
"200": { description: Workflow moved back one stage, content: { application/json: { schema: { $ref: "#/components/schemas/Event" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/events/{eventId}/balance/generate:
post:
tags: [Teams]
operationId: generateWorkflowBalance
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/VersionCommand" } } }
responses:
"200":
description: Event and generated candidates
content:
application/json:
schema:
type: object
required: [event, candidates]
properties:
event: { $ref: "#/components/schemas/Event" }
candidates: { type: array, items: { $ref: "#/components/schemas/BalanceCandidate" } }
"409": { $ref: "#/components/responses/Conflict" }
/api/events/{eventId}/roster:
get:
tags: [Teams]
operationId: getRosterDraft
parameters: [{ $ref: "#/components/parameters/EventId" }]
responses:
"200": { description: Roster draft, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
put:
tags: [Teams]
operationId: selectWorkflowBalance
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [candidate, expectedVersion]
properties:
candidate: { $ref: "#/components/schemas/BalanceCandidate" }
expectedVersion: { type: integer }
responses:
"200": { description: Roster draft created, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/events/{eventId}/roster/swap:
post:
tags: [Teams]
operationId: swapRosterPlayers
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/RosterSwapCommand" } } }
responses:
"200": { description: Updated roster, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/events/{eventId}/roster/move:
post:
tags: [Teams]
operationId: moveRosterPlayer
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/RosterMoveCommand" } } }
responses:
"200": { description: Updated roster, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
/api/events/{eventId}/roster/place-reserve:
post:
tags: [Teams]
operationId: placeReserveRosterPlayer
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/RosterPlaceReserveCommand" } } }
responses:
"200": { description: Updated roster, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
/api/events/{eventId}/roster/remove:
post:
tags: [Teams]
operationId: removeRosterPlayer
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/RosterRemoveCommand" } } }
responses:
"200": { description: Updated roster, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
/api/events/{eventId}/roster/substitute:
post:
tags: [Teams]
operationId: substituteRosterPlayer
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/RosterSubstitutionCommand" } } }
responses:
"200": { description: Updated roster, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
/api/events/{eventId}/roster/emergency-substitute:
post:
tags: [Teams]
operationId: emergencySubstituteRosterPlayer
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/RosterSubstitutionCommand" } } }
responses:
"200": { description: Updated live roster, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
/api/events/{eventId}/roster/captain:
put:
tags: [Teams]
operationId: setRosterCaptain
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [teamId, playerId, expectedVersion]
properties:
teamId: { type: string }
playerId: { type: string }
expectedVersion: { type: integer }
responses:
"200": { description: Updated roster, content: { application/json: { schema: { $ref: "#/components/schemas/RosterDraft" } } } }
/api/events/{eventId}/roster/confirm:
post:
tags: [Teams]
operationId: confirmRosters
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [expectedVersion, expectedRosterVersion]
properties:
expectedVersion: { type: integer }
expectedRosterVersion: { type: integer }
responses:
"200": { description: Rosters confirmed, content: { application/json: { schema: { $ref: "#/components/schemas/Event" } } } }
/api/events/{eventId}/start:
post:
tags: [Events]
operationId: startScrim
parameters: [{ $ref: "#/components/parameters/EventId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/VersionCommand" } } }
responses:
"201":
description: Scrim started
content:
application/json:
schema:
type: object
required: [event]
properties:
event: { $ref: "#/components/schemas/Event" }
series: { $ref: "#/components/schemas/Series" }
tournament: { $ref: "#/components/schemas/Tournament" }
/api/teams/{teamId}/captain:
put:
tags: [Teams]
operationId: assignCaptain
parameters:
- $ref: "#/components/parameters/TeamId"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [playerId]
properties:
playerId:
type: string
format: uuid
responses:
"200":
description: Captain assigned
content:
application/json:
schema:
$ref: "#/components/schemas/Team"
"422":
$ref: "#/components/responses/ValidationError"
/api/teams/{teamId}/name:
put:
tags: [Teams]
operationId: renameLiveTeam
parameters:
- $ref: "#/components/parameters/TeamId"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name]
properties:
name: { type: string, minLength: 2, maxLength: 32 }
responses:
"200": { description: Team renamed, content: { application/json: { schema: { $ref: "#/components/schemas/Team" } } } }
"403": { $ref: "#/components/responses/Forbidden" }
"409": { $ref: "#/components/responses/Conflict" }
/api/coin-toss:
post:
tags: [Series]
operationId: tossCoin
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [teamAId, teamBId, seed, eventId, actingTeamId]
properties:
teamAId: { type: string }
teamBId: { type: string }
seed: { type: string }
eventId: { type: string }
actingTeamId: { type: string }
responses:
"200":
description: Coin toss result
content:
application/json:
schema:
type: object
/api/drafts/{seriesId}/map-bans:
post:
tags: [Series]
operationId: banMap
parameters:
- $ref: "#/components/parameters/SeriesId"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [teamId, map, eventId, version]
properties:
teamId: { type: string }
map: { type: string }
eventId: { type: string }
version:
type: integer
responses:
"200":
description: Updated series
content:
application/json:
schema:
$ref: "#/components/schemas/Series"
"409":
$ref: "#/components/responses/Conflict"
/api/drafts/{seriesId}/hero-bans:
post:
tags: [Series]
operationId: banHero
parameters:
- $ref: "#/components/parameters/SeriesId"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [teamId, hero, eventId, version]
properties:
teamId: { type: string }
hero: { type: string }
eventId: { type: string }
version:
type: integer
responses:
"200":
description: Updated series
content:
application/json:
schema:
$ref: "#/components/schemas/Series"
"409":
$ref: "#/components/responses/Conflict"
/api/series/{seriesId}:
get:
tags: [Series]
operationId: getSeries
parameters: [{ $ref: "#/components/parameters/SeriesId" }]
responses:
"200": { description: Full live series state, content: { application/json: { schema: { $ref: "#/components/schemas/Series" } } } }
/api/series/{seriesId}/coin-toss:
post:
tags: [Series]
operationId: tossSeriesCoin
parameters: [{ $ref: "#/components/parameters/SeriesId" }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [seed, actingTeamId, expectedVersion]
properties:
seed: { type: string }
actingTeamId: { type: string }
expectedVersion: { type: integer }
responses:
"200": { description: Updated series, content: { application/json: { schema: { $ref: "#/components/schemas/Series" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/series/{seriesId}/map-bans:
post:
tags: [Series]
operationId: banSeriesMap
parameters: [{ $ref: "#/components/parameters/SeriesId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/SeriesBanCommand" } } }
responses:
"200": { description: Updated series, content: { application/json: { schema: { $ref: "#/components/schemas/Series" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/series/{seriesId}/map-pick:
post:
tags: [Series]
operationId: pickSeriesMap
description: The previous map loser picks the next map directly.
parameters: [{ $ref: "#/components/parameters/SeriesId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/SeriesBanCommand" } } }
responses:
"200": { description: Updated series with hero bans started, content: { application/json: { schema: { $ref: "#/components/schemas/Series" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/series/{seriesId}/hero-bans:
post:
tags: [Series]
operationId: banSeriesHero
parameters: [{ $ref: "#/components/parameters/SeriesId" }]
requestBody:
required: true
content: { application/json: { schema: { $ref: "#/components/schemas/SeriesBanCommand" } } }
responses:
"200": { description: Updated series, content: { application/json: { schema: { $ref: "#/components/schemas/Series" } } } }
"409": { $ref: "#/components/responses/Conflict" }
/api/series/{seriesId}/map-result:
post:
tags: [Series]
operationId: recordSeriesMapResult
parameters: [{ $ref: "#/components/parameters/SeriesId" }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [outcome, actingTeamId, expectedVersion]
properties:
outcome: { type: string, enum: [TeamAWin, TeamBWin, Draw] }
actingTeamId: { type: string }
expectedVersion: { type: integer }
responses:
"200": { description: Updated series, content: { application/json: { schema: { $ref: "#/components/schemas/Series" } } } }
/api/series/{seriesId}/results:
post:
tags: [Series]
operationId: recordMapResult
parameters:
- $ref: "#/components/parameters/SeriesId"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MapResultInput"
responses:
"200":
description: Result recorded
content:
application/json:
schema:
$ref: "#/components/schemas/Series"
/api/events/stream:
get:
tags: [Series]
operationId: subscribeSeries
parameters:
- name: topic
in: query
schema:
type: string
responses:
"200":
description: Server-sent event stream
content:
text/event-stream:
schema:
type: string
/api/tournaments/{tournamentId}:
get:
tags: [Tournaments]
operationId: getTournament
parameters:
- $ref: "#/components/parameters/TournamentId"
responses:
"200":
description: Tournament bracket
content:
application/json:
schema:
$ref: "#/components/schemas/Tournament"
components:
securitySchemes:
cookieAuth:
type: apiKey
in: cookie
name: mixmaker_session
parameters:
EventId:
name: eventId
in: path
required: true
schema:
type: string
format: uuid
PlayerId:
name: playerId
in: path
required: true
schema:
type: string
format: uuid
TeamId:
name: teamId
in: path
required: true
schema:
type: string
format: uuid
SeriesId:
name: seriesId
in: path
required: true
schema:
type: string
format: uuid
TournamentId:
name: tournamentId
in: path
required: true
schema:
type: string
format: uuid
responses:
Unauthorized:
description: Authentication required
content:
application/json:
schema:
$ref: "#/components/schemas/Problem"
Forbidden:
description: Insufficient permission
content:
application/json:
schema:
$ref: "#/components/schemas/Problem"
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: "#/components/schemas/Problem"
Conflict:
description: State version conflict
content:
application/json:
schema:
$ref: "#/components/schemas/Problem"
ValidationError:
description: Invalid command
content:
application/json:
schema:
$ref: "#/components/schemas/Problem"
schemas:
Session:
type: object
required: [account, player]
properties:
account:
$ref: "#/components/schemas/Account"
player:
$ref: "#/components/schemas/Player"
Account:
type: object
required: [id, discordId, username, role, createdAt]
properties:
id:
type: string
format: uuid
discordId:
type: string
username:
type: string
avatarUrl:
type: [string, "null"]
format: uri
role:
type: string
enum: [player, moderator, admin]
createdAt:
type: string
format: date-time
Ratings:
type: object
required: [tank, damage, support]
properties:
tank:
type: integer
minimum: 1
maximum: 40
description: Bronze 5 = 1, Champion 1 = 40
damage:
type: integer
minimum: 1
maximum: 40
description: Bronze 5 = 1, Champion 1 = 40
support:
type: integer
minimum: 1
maximum: 40
description: Bronze 5 = 1, Champion 1 = 40
Player:
type: object
required: [id, accountId, displayName, ratings, preferredRoles, preferredPlayerIds, avoidedPlayerIds, updatedAt]
properties:
id:
type: string
format: uuid
accountId:
type: string
format: uuid
displayName:
type: string
ratings:
$ref: "#/components/schemas/Ratings"
preferredRoles:
type: array
items:
type: string
enum: [Tank, Damage, Support]
preferredPlayerIds:
type: array
maxItems: 3
items:
type: string
avoidedPlayerIds:
type: array
maxItems: 3
description: Soft preference to place these players on another team.
items:
type: string
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
PlayerUpdate:
type: object
required: [ratings]
properties:
displayName:
type: string
ratings:
$ref: "#/components/schemas/Ratings"
preferredRoles:
type: array
items:
type: string
enum: [Tank, Damage, Support]
preferredPlayerIds:
type: array
maxItems: 3
items:
type: string
avoidedPlayerIds:
type: array
maxItems: 3
items:
type: string
EventInput:
type: object
required: [name, startsAt, endsAt, registrationDeadline]
properties:
name:
type: string
minLength: 1
description:
type: string
startsAt:
type: string
format: date-time
endsAt:
type: string
format: date-time
registrationDeadline:
type: string
format: date-time
description: Synchronized by the server to startsAt.
Event:
allOf:
- $ref: "#/components/schemas/EventInput"
- type: object
required: [id, createdBy, createdAt, updatedAt, state, version, rulesetId, activeSeriesId, tournamentId]
properties:
id:
type: string
format: uuid
createdBy:
type: string
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
state:
type: string
enum: [RegistrationOpen, RegistrationClosed, Balancing, RostersDraft, RostersConfirmed, BracketDraft, Live, Completed, Cancelled]
version: { type: integer }
rulesetId: { type: string }
activeSeriesId: { type: string }
tournamentId: { type: string }
RegistrationInput:
type: object
required: [status]
properties:
status:
type: string
enum: [Going, Maybe, NotGoing]
EventRegistration:
type: object
required: [eventId, playerId, status, actorAccountId, source, updatedAt]
properties:
eventId:
type: string
format: uuid
playerId:
type: string
format: uuid
status:
type: string
enum: [Going, Maybe, NotGoing]
actorAccountId:
type: string
format: uuid
source:
type: string
enum: [player, admin]
updatedAt:
type: string
format: date-time
TeamSlot:
type: object
required: [playerId, role, rating]
properties:
playerId:
type: string
role:
type: string
enum: [Tank, Damage, Support]
rating:
type: integer
Team:
type: object
required: [id, eventId, name, captainPlayerId, slots]
properties:
id:
type: string
eventId:
type: string
name:
type: string
captainPlayerId:
type: string
slots:
type: array
minItems: 5
maxItems: 5
items:
$ref: "#/components/schemas/TeamSlot"
BalanceCandidate:
type: object
required: [score, teams, reserve]
properties:
score:
type: integer
teams:
type: array
items:
$ref: "#/components/schemas/Team"
reserve:
type: array
items:
type: string
VersionCommand:
type: object
required: [expectedVersion]
properties:
expectedVersion: { type: integer }
CloseRegistrationCommand:
type: object
required: [rulesetId, expectedVersion]
properties:
rulesetId: { type: string }
expectedVersion: { type: integer }
RosterDraft:
type: object
required: [eventId, teams, reserve, version, confirmed]
properties:
eventId: { type: string }
teams: { type: array, minItems: 2, items: { $ref: "#/components/schemas/Team" } }
reserve: { type: array, items: { type: string } }
version: { type: integer }
confirmed: { type: boolean }
RosterSwapCommand:
type: object
required: [teamAId, playerAId, teamBId, playerBId, expectedVersion]
properties:
teamAId: { type: string }
playerAId: { type: string }
teamBId: { type: string }
playerBId: { type: string }
expectedVersion: { type: integer }
RosterMoveCommand:
type: object
required: [fromTeamId, playerId, toTeamId, role, expectedVersion]
properties:
fromTeamId: { type: string }
playerId: { type: string }
toTeamId: { type: string }
role: { type: string, enum: [Tank, Damage, Support] }
expectedVersion: { type: integer }
RosterPlaceReserveCommand:
type: object
required: [teamId, reservePlayerId, role, expectedVersion]
properties:
teamId: { type: string }
reservePlayerId: { type: string }
role: { type: string, enum: [Tank, Damage, Support] }
expectedVersion: { type: integer }
RosterRemoveCommand:
type: object
required: [teamId, playerId, expectedVersion]
properties:
teamId: { type: string }
playerId: { type: string }
expectedVersion: { type: integer }
RosterSubstitutionCommand:
type: object
required: [teamId, outgoingPlayerId, reservePlayerId, expectedVersion]
properties:
teamId: { type: string }
outgoingPlayerId: { type: string }
reservePlayerId: { type: string }
expectedVersion: { type: integer }
SeriesBanCommand:
type: object
required: [teamId, expectedVersion]
properties:
teamId: { type: string }
map: { type: string }
hero: { type: string }
expectedVersion: { type: integer }
MapResultInput:
type: object
required: [mapName, outcome, expectedVersion]
properties:
mapName:
type: string
outcome:
type: string
enum: [TeamAWin, TeamBWin, Draw]
expectedVersion:
type: integer
Series:
type: object
required: [id, eventId, tournamentId, teamAId, teamBId, winnerTeamId, bestOf, rulesetId, phase, playedMaps, seriesBans, maps, audit, results, version]
properties:
id:
type: string
eventId:
type: string
tournamentId:
type: string
teamAId:
type: string
teamBId:
type: string
winnerTeamId:
type: string
bestOf:
type: integer
rulesetId: { type: string }
phase:
type: string
enum: [CoinTossPending, MapBan, MapPick, HeroBan, Playing, Completed]
coinToss: { type: [object, "null"] }
mapDraft: { type: [object, "null"] }
heroDraft: { type: [object, "null"] }
currentMap: { type: string }
playedMaps: { type: array, items: { type: string } }
nextMapPickerId: { type: string }
availableMaps: { type: array, items: { type: string } }
seriesBans:
type: object
additionalProperties:
type: array
items: { type: string }
maps:
type: array
items:
type: object
required: [number, name, heroBans]
properties:
number: { type: integer }
name: { type: string }
heroBans:
type: array
items:
type: object
required: [teamId, value, actorAccountId, at]
properties:
teamId: { type: string }
value: { type: string }
actorAccountId: { type: string }
at: { type: string, format: date-time }
result: { type: [object, "null"] }
audit: { type: array, items: { type: object } }
results:
type: array
items:
type: object
version:
type: integer
BracketSlotSource:
type: object
required: [kind]
properties:
kind: { type: string, enum: [Team, Winner, Loser] }
teamId: { type: string }
matchId: { type: string }
BracketMatch:
type: object
required: [id, round, order, slotA, slotB]
properties:
id: { type: string }
round: { type: integer, minimum: 0 }
order: { type: integer, minimum: 0 }
slotA: { $ref: "#/components/schemas/BracketSlotSource" }
slotB: { $ref: "#/components/schemas/BracketSlotSource" }
seriesId: { type: string }
teamAId: { type: string }
teamBId: { type: string }
winnerTeamId: { type: string }
series: { $ref: "#/components/schemas/Series" }
BracketDraft:
type: object
required: [eventId, teamIds, matches, version, confirmed]
properties:
eventId: { type: string }
teamIds: { type: array, items: { type: string } }
matches: { type: array, items: { $ref: "#/components/schemas/BracketMatch" } }
version: { type: integer }
confirmed: { type: boolean }
BracketUpdateCommand:
type: object
required: [matches, expectedVersion]
properties:
matches: { type: array, items: { $ref: "#/components/schemas/BracketMatch" } }
expectedVersion: { type: integer }
Tournament:
type: object
required: [id, eventId, name, winnerTeamId, teamIds, matches, rounds, version]
properties:
id:
type: string
eventId:
type: string
name:
type: string
winnerTeamId:
type: string
teamIds:
type: array
items:
type: string
matches:
type: array
items:
$ref: "#/components/schemas/BracketMatch"
rounds:
type: array
items:
type: array
items:
$ref: "#/components/schemas/Series"
version: { type: integer }
Problem:
type: object
required: [error]
properties:
error:
type: string