1226 lines
37 KiB
YAML
1226 lines
37 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}/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
|
|
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, 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, 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 } }
|
|
maps: { type: array, items: { type: object } }
|
|
audit: { type: array, items: { type: object } }
|
|
results:
|
|
type: array
|
|
items:
|
|
type: object
|
|
version:
|
|
type: integer
|
|
Tournament:
|
|
type: object
|
|
required: [id, eventId, name, winnerTeamId, teamIds, rounds]
|
|
properties:
|
|
id:
|
|
type: string
|
|
eventId:
|
|
type: string
|
|
name:
|
|
type: string
|
|
winnerTeamId:
|
|
type: string
|
|
teamIds:
|
|
type: array
|
|
items:
|
|
type: string
|
|
rounds:
|
|
type: array
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/Series"
|
|
Problem:
|
|
type: object
|
|
required: [error]
|
|
properties:
|
|
error:
|
|
type: string
|