Merge branch 'codex/tur-225-api-docs' into 'master'

TUR-225: Document account API additions

See merge request turniere/turniere-backend!83
This commit is contained in:
Daniel Schädler 2026-05-06 09:29:51 +00:00
commit e26d4b1b20
3 changed files with 547 additions and 0 deletions

View File

@ -30,6 +30,10 @@ bundle exec rspec
Leader/follower tournament sync docs: Leader/follower tournament sync docs:
- [doc/leader_follower.md](doc/leader_follower.md) - [doc/leader_follower.md](doc/leader_follower.md)
- [doc/account_profiles_api.md](doc/account_profiles_api.md)
- [doc/tournament_management_api.md](doc/tournament_management_api.md)
- [doc/match_metadata_api.md](doc/match_metadata_api.md)
- [doc/team_action_lists_api.md](doc/team_action_lists_api.md)
- [doc/timer_api.md](doc/timer_api.md) - [doc/timer_api.md](doc/timer_api.md)
- [doc/beamer_live_updates.md](doc/beamer_live_updates.md) - [doc/beamer_live_updates.md](doc/beamer_live_updates.md)
- [doc/tournament_live_updates.md](doc/tournament_live_updates.md) - [doc/tournament_live_updates.md](doc/tournament_live_updates.md)

350
doc/account_profiles_api.md Normal file
View File

@ -0,0 +1,350 @@
# Account Profiles And Team Players API
This API lets public pages show player account profiles and lets tournament
owners associate one or more player accounts with teams.
Terminology:
- account: existing `User` record
- player account: user account associated with one or more tournament teams
- tournament owner: organizer account that owns the tournament
- team player: account linked to a team through the `players` array
There is no separate organizer-only "create player" endpoint. Organizers create
or reuse player accounts by sending player email values through the tournament
or team endpoints below.
## Public Account Profile
Use this for public-facing player profile pages.
Endpoint:
- `GET /accounts/:id`
Authentication:
- optional
- anonymous callers see only public tournament/team profile data
- the account owner sees their own private tournament/team profile data too
Example response:
```json
{
"id": 42,
"name": "alice",
"username": "alice",
"tournaments": [
{
"id": 11,
"name": "Summer Cup",
"code": "a1b2c3",
"public": true
}
],
"created_tournaments": [
{
"id": 12,
"name": "Alice Open",
"code": "d4e5f6",
"public": true
}
],
"teams": [
{
"id": 99,
"name": "Team Alpha",
"tournament": {
"id": 11,
"name": "Summer Cup",
"code": "a1b2c3",
"public": true
}
}
]
}
```
Response fields:
- `id`: account id
- `name`: same value as `username`, for public display
- `username`: account username
- `tournaments`: tournaments where this account is linked to at least one team
- `created_tournaments`: tournaments created by this account
- `teams`: teams linked to this account
Visibility:
- anonymous/profile visitors see only public tournaments and teams in public tournaments
- authenticated profile owner sees public and private tournaments/teams for their own account
Errors:
- `404` when account id does not exist
## Team Read Payload
Teams expose linked player accounts in a `players` array.
Endpoint:
- `GET /teams/:id`
Example response:
```json
{
"id": 99,
"name": "Team Alpha",
"players": [
{
"id": 42,
"name": "alice",
"username": "alice"
},
{
"id": 43,
"name": "bob",
"username": "bob"
}
]
}
```
Empty team-player association:
```json
{
"id": 99,
"name": "Team Alpha",
"players": []
}
```
## Tournament Read Payload
Full tournament reads include the same player summaries on each team.
Endpoint:
- `GET /tournaments/:id`
Relevant response fragment:
```json
{
"id": 11,
"name": "Summer Cup",
"teams": [
{
"id": 99,
"name": "Team Alpha",
"players": [
{
"id": 42,
"name": "alice",
"username": "alice"
}
],
"advancing_from_group_stage": false
}
]
}
```
`GET /tournaments/:id?simple=true` does not include teams.
## Link Players While Creating Teams
Tournament creation accepts player email values inside new team objects.
Endpoint:
- `POST /tournaments`
Authentication:
- tournament owner account required
Single player:
```json
{
"name": "Summer Cup",
"public": true,
"teams": [
{
"name": "Team Alpha",
"player_email": "alice@example.com"
},
{
"name": "Team Beta"
}
]
}
```
Multiple players:
```json
{
"name": "Summer Cup",
"public": true,
"teams": [
{
"name": "Team Alpha",
"player_emails": [
"alice@example.com",
"bob@example.com"
]
}
]
}
```
Behavior:
- existing accounts are reused by case-insensitive email match
- missing accounts are created by email
- no password or token is returned for organizer-created accounts
- teams without player email values remain unlinked
- existing teams passed by `id` keep their existing player associations
Group-stage creation uses the same team object fields:
```json
{
"name": "Summer Cup",
"public": true,
"group_stage": true,
"playoff_teams_amount": 8,
"teams": [
{
"name": "Team Alpha",
"group": 0,
"player_emails": ["alice@example.com", "bob@example.com"]
}
]
}
```
## Link Or Replace Players On Existing Teams
Endpoint:
- `PATCH /teams/:id`
- `PUT /teams/:id`
Authentication:
- tournament owner may rename the team and manage player links
- linked player may rename their own team
- linked player may not change player links
- other authenticated users receive `403`
- read-only follower tournaments receive `423`
### Rename Team
```json
{
"name": "Team Alpha Renamed"
}
```
### Add One Player By Email
```json
{
"player_email": "alice@example.com"
}
```
Behavior:
- existing account is reused
- missing account is created
- player is appended to the team if not already linked
- existing team players stay linked
### Add One Player By Id
```json
{
"player_id": 42
}
```
Behavior:
- player is appended to the team if not already linked
- existing team players stay linked
- unknown id returns `404`
### Replace All Players By Email
```json
{
"player_emails": [
"alice@example.com",
"bob@example.com"
]
}
```
Behavior:
- replaces the full `players` list for the team
- empty array clears all players
- blank email values are ignored
- missing accounts are created
### Replace All Players By Id
```json
{
"player_ids": [42, 43]
}
```
Behavior:
- replaces the full `players` list for the team
- empty array clears all players
- unknown ids return `404`
### Clear All Players
Both single-value forms clear all players when sent blank:
```json
{
"player_email": ""
}
```
```json
{
"player_id": ""
}
```
## Error Handling
Expected statuses:
- `200` team/account read or team update accepted
- `201` tournament created
- `401` authentication required
- `403` authenticated user cannot change this team/tournament
- `404` account, team, tournament, or player id not found
- `422` invalid create/update payload
- `423` follower tournament is read-only
## Sync Behavior
Team-player account links are not part of leader/follower tournament sync
snapshots. Follower tournaments still expose teams, match data, and other synced
tournament data, but account ownership links are managed on the writable source
side.

View File

@ -0,0 +1,193 @@
# Tournament Management API Additions
This document covers tournament API additions that are not specific to timers,
team action lists, or match metadata.
Related docs:
- [timer_api.md](timer_api.md)
- [team_action_lists_api.md](team_action_lists_api.md)
- [match_metadata_api.md](match_metadata_api.md)
- [account_profiles_api.md](account_profiles_api.md)
## Tournament Metadata Fields
Tournaments support optional public metadata:
- `location`: venue, city, stream label, or other display location
- `starts_at`: tournament start timestamp
- `ends_at`: tournament end timestamp
- `website_url`: public URL for the tournament or event
These fields are included in:
- `GET /tournaments`
- `GET /tournaments/:id?simple=true`
- `GET /tournaments/:id`
- `POST /tournaments`
- `PATCH /tournaments/:id`
- leader/follower sync snapshots
Full and simple tournament responses include:
```json
{
"id": 11,
"name": "Summer Cup",
"code": "a1b2c3",
"public": true,
"location": "Main Hall",
"starts_at": "2030-06-01T08:00:00Z",
"ends_at": "2030-06-01T16:00:00Z",
"website_url": "https://example.com/summer-cup"
}
```
### Create With Metadata
Endpoint:
- `POST /tournaments`
```json
{
"name": "Summer Cup",
"description": "Annual summer tournament",
"public": true,
"location": "Main Hall",
"starts_at": "2030-06-01T10:00:00+02:00",
"ends_at": "2030-06-01T18:00:00+02:00",
"website_url": "https://example.com/summer-cup",
"teams": [
{
"name": "Team Alpha"
},
{
"name": "Team Beta"
},
{
"name": "Team Gamma"
},
{
"name": "Team Delta"
}
]
}
```
Authentication:
- authenticated user required
- created tournament owner is the authenticated user
### Update Metadata
Endpoint:
- `PATCH /tournaments/:id`
```json
{
"location": "Updated Arena",
"starts_at": "2030-07-01T10:00:00+02:00",
"ends_at": "2030-07-01T18:00:00+02:00",
"website_url": "https://example.com/updated"
}
```
Authentication:
- tournament owner required
- read-only follower tournaments reject normal updates with `423`
Validation:
- `website_url` must be blank or an `http`/`https` URL
- `ends_at` must be after `starts_at` when both are present
- `location` and `website_url` are stripped and stored as `null` when blank
- timestamp responses are serialized as ISO 8601 strings
Expected errors:
- `401` unauthenticated
- `403` authenticated but not owner
- `422` invalid metadata values
- `423` follower tournament is read-only
## Delete Generated Group-Stage Playoffs
Use this endpoint when a tournament owner needs to reopen a finished group stage,
change group-stage results, and regenerate playoffs.
Endpoint:
- `DELETE /tournaments/:id/playoffs`
Authentication:
- tournament owner required
- read-only follower tournaments reject with `423`
Success response:
```json
{
"id": 11,
"stages": [
{
"id": 21,
"level": -1,
"state": "in_progress"
}
]
}
```
Success behavior:
- deletes all playoff stages for the group-stage tournament
- keeps the group stage
- changes the group stage back to `in_progress`
- enqueues tournament sync when configured
- broadcasts the normal tournament live update
Deletion is allowed only when:
- tournament has a group stage
- generated playoff stages exist
- every playoff match is still effectively unplayed
- playoff match states are `not_started`, `not_ready`, or `single_team`
- all playoff match scores and hidden scores are zero
Deletion is rejected after playoff play has started or scores have changed.
Expected statuses:
- `200` playoffs deleted
- `401` unauthenticated
- `403` authenticated but not tournament owner
- `404` tournament not found
- `422` no group stage, no generated playoffs, or playoffs no longer deletable
- `423` follower tournament is read-only
Common `422` errors:
- `Only group-stage playoffs can be deleted`
- `Playoffs have not been generated`
- `Playoffs cannot be deleted after matches have started or scores changed`
## Existing Related Endpoints
Match scheduling/display metadata lives in [match_metadata_api.md](match_metadata_api.md):
- `PATCH /matches/:id`
- `PATCH /tournaments/:tournament_id/matches/metadata`
Player account profile and team ownership APIs live in
[account_profiles_api.md](account_profiles_api.md):
- `GET /accounts/:id`
- `GET /teams/:id`
- `PATCH /teams/:id`
- `PUT /teams/:id`
- `POST /tournaments` team `player_email` / `player_emails` fields