Files
mixmaker/openapi/openapi.yaml
lemintare a311b7761d
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
CI / compose (push) Has been cancelled
Refactor bracket validation logic to support draft state
This commit updates the bracket validation process by introducing a new `ValidateDraft` method, allowing for incomplete edits in the draft state. The existing `Validate` method has been modified to enforce complete validation only upon confirmation. Additionally, new tests have been added to ensure that incomplete drafts are accepted until confirmation, while still rejecting invalid references. Documentation has been updated to reflect these changes in the API and architecture.
2026-07-19 13:43:25 +03:00

1353 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/EventCreateInput"
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
description: Saves a structurally valid work-in-progress graph; slots and final layout may remain incomplete until confirmation.
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
description: Validates the complete graph, including filled slots and exactly one final match, then marks it confirmed.
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.
EventCreateInput:
allOf:
- $ref: "#/components/schemas/EventInput"
- type: object
properties:
pingEveryone:
type: boolean
default: true
description: Whether the Discord announcement should notify @everyone. The announcement is still posted when false.
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