Add event management features to API, including event cancellation, deletion, registration closure, and workflow balance generation. Introduce new roster management endpoints and enhance participant handling with avoided player preferences. Update database schema and service logic to support these changes.
This commit is contained in:
@@ -180,6 +180,28 @@ paths:
|
||||
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]
|
||||
@@ -254,6 +276,19 @@ paths:
|
||||
$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]
|
||||
@@ -279,6 +314,150 @@ paths:
|
||||
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}/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/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]
|
||||
@@ -385,6 +564,84 @@ paths:
|
||||
$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]
|
||||
@@ -556,7 +813,7 @@ components:
|
||||
description: Bronze 5 = 1, Champion 1 = 40
|
||||
Player:
|
||||
type: object
|
||||
required: [id, accountId, displayName, ratings, preferredRoles, preferredPlayerIds, updatedAt]
|
||||
required: [id, accountId, displayName, ratings, preferredRoles, preferredPlayerIds, avoidedPlayerIds, updatedAt]
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
@@ -578,6 +835,12 @@ components:
|
||||
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
|
||||
@@ -602,6 +865,11 @@ components:
|
||||
maxItems: 3
|
||||
items:
|
||||
type: string
|
||||
avoidedPlayerIds:
|
||||
type: array
|
||||
maxItems: 3
|
||||
items:
|
||||
type: string
|
||||
EventInput:
|
||||
type: object
|
||||
required: [name, startsAt, endsAt, registrationDeadline]
|
||||
@@ -624,7 +892,7 @@ components:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/EventInput"
|
||||
- type: object
|
||||
required: [id, createdBy, createdAt, updatedAt]
|
||||
required: [id, createdBy, createdAt, updatedAt, state, version, rulesetId, activeSeriesId, tournamentId]
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
@@ -637,6 +905,13 @@ components:
|
||||
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]
|
||||
@@ -709,6 +984,51 @@ components:
|
||||
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 }
|
||||
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]
|
||||
@@ -722,10 +1042,12 @@ components:
|
||||
type: integer
|
||||
Series:
|
||||
type: object
|
||||
required: [id, tournamentId, teamAId, teamBId, winnerTeamId, bestOf, results, version]
|
||||
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:
|
||||
@@ -736,6 +1058,19 @@ components:
|
||||
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:
|
||||
|
||||
Reference in New Issue
Block a user