From 7d007c0415e6e1590c863713bf998d5c100a8edc Mon Sep 17 00:00:00 2001 From: Malaber Date: Wed, 6 May 2026 10:59:28 +0200 Subject: [PATCH] docs(api): document account profile endpoints Cover player account profile flows, team player association payloads, tournament metadata fields, and playoff deletion behavior. --- README.md | 4 + doc/account_profiles_api.md | 350 +++++++++++++++++++++++++++++++ doc/tournament_management_api.md | 193 +++++++++++++++++ 3 files changed, 547 insertions(+) create mode 100644 doc/account_profiles_api.md create mode 100644 doc/tournament_management_api.md diff --git a/README.md b/README.md index 1a42f7f..5cab19a 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,10 @@ bundle exec rspec Leader/follower tournament sync docs: - [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/beamer_live_updates.md](doc/beamer_live_updates.md) - [doc/tournament_live_updates.md](doc/tournament_live_updates.md) diff --git a/doc/account_profiles_api.md b/doc/account_profiles_api.md new file mode 100644 index 0000000..2fd3bc4 --- /dev/null +++ b/doc/account_profiles_api.md @@ -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. diff --git a/doc/tournament_management_api.md b/doc/tournament_management_api.md new file mode 100644 index 0000000..c2d1ddc --- /dev/null +++ b/doc/tournament_management_api.md @@ -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