docs: update manual team action list API
This commit is contained in:
parent
d69e08a25b
commit
d3589235d9
|
|
@ -176,6 +176,7 @@ Practical rule:
|
|||
|
||||
For team action lists specifically:
|
||||
|
||||
- create lists explicitly through owner-facing HTTP API; do not auto-generate them from stage transitions unless product requirements say so
|
||||
- subscribe by tournament id
|
||||
- channel name is `TournamentTeamActionListsChannel`
|
||||
- broadcast full current list snapshot for that tournament
|
||||
|
|
|
|||
|
|
@ -2,13 +2,19 @@
|
|||
|
||||
## Purpose
|
||||
|
||||
Team action lists let the backend expose checklist-style workflows for teams inside a tournament.
|
||||
Team action lists let tournament owners create checklist-style workflows for teams inside a tournament.
|
||||
|
||||
Current example:
|
||||
Examples:
|
||||
|
||||
- `group_stage_survivor_playoff_tokens`
|
||||
- collect playoff tokens
|
||||
- track team check-in
|
||||
- hand out medals
|
||||
|
||||
That list contains all teams that advanced from the group stage and tracks whether each team already collected a playoff token.
|
||||
Important:
|
||||
|
||||
- lists are not auto-generated by backend tournament events
|
||||
- owner creates a list explicitly through API
|
||||
- backend materializes the initial team items from the chosen `source`
|
||||
|
||||
## Read Flow
|
||||
|
||||
|
|
@ -26,7 +32,7 @@ Example response shape:
|
|||
{
|
||||
"id": 9,
|
||||
"name": "Playoff token collection",
|
||||
"key": "group_stage_survivor_playoff_tokens",
|
||||
"key": "playoff_token_collection",
|
||||
"action_name": "Collect playoff token",
|
||||
"source": "group_stage_survivors",
|
||||
"team_action_items": [
|
||||
|
|
@ -45,6 +51,50 @@ Example response shape:
|
|||
}
|
||||
```
|
||||
|
||||
## Create Flow
|
||||
|
||||
Only tournament owner may create lists.
|
||||
Follower tournaments in `read_only_mode` reject creation with `423`.
|
||||
|
||||
Endpoint:
|
||||
|
||||
- `POST /tournaments/:tournament_id/team_action_lists`
|
||||
|
||||
Request body:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Playoff token collection",
|
||||
"key": "playoff_token_collection",
|
||||
"action_name": "Collect playoff token",
|
||||
"source": "group_stage_survivors"
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
- `201 Created`
|
||||
- response body is the created `TeamActionList` including `team_action_items`
|
||||
|
||||
Current supported sources:
|
||||
|
||||
- `all_tournament_teams`
|
||||
- `group_stage_survivors`
|
||||
|
||||
Current source behavior:
|
||||
|
||||
- `all_tournament_teams` uses all teams currently in tournament
|
||||
- `group_stage_survivors` uses teams currently advancing from a finished group stage
|
||||
|
||||
Creation is snapshot-style:
|
||||
|
||||
- backend resolves teams at create time
|
||||
- backend creates one item per resolved team
|
||||
- backend does not auto-create lists later
|
||||
- backend does not auto-refresh existing list membership later
|
||||
|
||||
If selected source currently resolves to no teams, backend returns `422`.
|
||||
|
||||
## Write Flow
|
||||
|
||||
Only tournament owner may change item status.
|
||||
|
|
@ -79,7 +129,7 @@ Endpoint:
|
|||
|
||||
Example:
|
||||
|
||||
- `PATCH /tournaments/123/team_action_lists/group_stage_survivor_playoff_tokens/teams/55`
|
||||
- `PATCH /tournaments/123/team_action_lists/playoff_token_collection/teams/55`
|
||||
|
||||
Request body:
|
||||
|
||||
|
|
@ -93,7 +143,12 @@ Response body for both write endpoints is the updated `TeamActionItem`.
|
|||
|
||||
## Idempotency Rules
|
||||
|
||||
These endpoints are designed to be idempotent if frontend sends explicit target state.
|
||||
Create endpoint is idempotent by unique business key per tournament:
|
||||
|
||||
- backend enforces unique `(tournament_id, key)`
|
||||
- repeated create with same key returns `422`, not a second list
|
||||
|
||||
Item update endpoints are idempotent if frontend sends explicit target state.
|
||||
|
||||
Good:
|
||||
|
||||
|
|
@ -103,12 +158,12 @@ Good:
|
|||
Avoid:
|
||||
|
||||
- toggle-style client behavior such as "invert current state"
|
||||
- whole-list writeback from stale client state
|
||||
|
||||
Why this is idempotent:
|
||||
Why item updates are idempotent:
|
||||
|
||||
- sending `completed=true` multiple times leaves item in same final state
|
||||
- sending `completed=false` multiple times leaves item in same final state
|
||||
- backend does not create duplicate items
|
||||
- backend stores one unique item per `(team_action_list_id, team_id)`
|
||||
|
||||
`completed_at` behavior:
|
||||
|
|
@ -122,10 +177,10 @@ Why this is idempotent:
|
|||
Recommended frontend flow:
|
||||
|
||||
1. Load tournament via `GET /tournaments/:id`
|
||||
2. Find desired list by stable `key`
|
||||
3. Render `team_action_items`
|
||||
4. On user action, send explicit target state
|
||||
5. Update local UI from response or refetch tournament
|
||||
2. Render current `team_action_lists`
|
||||
3. If owner wants a new checklist, send `POST /tournaments/:id/team_action_lists`
|
||||
4. For item changes, send explicit target state for one item only
|
||||
5. Update local UI from response or websocket snapshot
|
||||
|
||||
Recommended frontend identifiers:
|
||||
|
||||
|
|
@ -135,6 +190,7 @@ Recommended frontend identifiers:
|
|||
|
||||
Recommended optimistic UI:
|
||||
|
||||
- create list only once per intended key
|
||||
- set checkbox immediately to requested target state
|
||||
- revert if API returns error
|
||||
- do not compute next state from stale cached data if multiple clients may edit
|
||||
|
|
@ -143,11 +199,13 @@ Recommended optimistic UI:
|
|||
|
||||
Expected statuses:
|
||||
|
||||
- `200` update accepted
|
||||
- `201` list created
|
||||
- `200` item update accepted
|
||||
- `401` unauthenticated
|
||||
- `403` authenticated but not tournament owner
|
||||
- `404` tournament, list, team, or item not found
|
||||
- `422` invalid create payload, duplicate key, unsupported source, or source with no teams
|
||||
- `423` follower tournament is read-only
|
||||
- `401` unauthenticated
|
||||
|
||||
## Sync / Follower Behavior
|
||||
|
||||
|
|
@ -155,10 +213,12 @@ Team action lists are included in tournament sync snapshots.
|
|||
|
||||
That means:
|
||||
|
||||
- source tournament owner updates item state
|
||||
- source owner creates list on source tournament
|
||||
- backend enqueues tournament sync
|
||||
- follower tournament receives updated list state
|
||||
- follower users can view but not mutate item state while read-only
|
||||
- follower tournament receives created list and all items
|
||||
- source owner updates item state
|
||||
- follower tournament receives updated completion state
|
||||
- follower users can view but not mutate list state while read-only
|
||||
|
||||
## Websocket / Live Update Behavior
|
||||
|
||||
|
|
@ -168,7 +228,7 @@ This is a websocket flow, not a webhook flow.
|
|||
|
||||
- backend pushes updates to subscribed clients over websocket
|
||||
- frontend does not register callback URLs
|
||||
- writes still happen over normal HTTP `PATCH` requests
|
||||
- writes still happen over normal HTTP `POST` and `PATCH` requests
|
||||
|
||||
Endpoint:
|
||||
|
||||
|
|
@ -190,11 +250,12 @@ Subscription identifier example:
|
|||
Behavior:
|
||||
|
||||
- subscription immediately receives current full team-action-list snapshot for that tournament
|
||||
- later list/item changes broadcast updated full snapshot again
|
||||
- later list creation and item changes broadcast updated full snapshot again
|
||||
- same broadcast path is used for:
|
||||
- direct source updates
|
||||
- list creation
|
||||
- direct item updates
|
||||
- follower sync imports
|
||||
- both write endpoints trigger the same backend update path before broadcast:
|
||||
- both item update endpoints trigger the same backend update path before broadcast:
|
||||
- `PATCH /team_action_items/:id`
|
||||
- `PATCH /tournaments/:tournament_id/team_action_lists/:key/teams/:team_id`
|
||||
|
||||
|
|
@ -208,7 +269,7 @@ Payload shape:
|
|||
{
|
||||
"id": 9,
|
||||
"name": "Playoff token collection",
|
||||
"key": "group_stage_survivor_playoff_tokens",
|
||||
"key": "playoff_token_collection",
|
||||
"action_name": "Collect playoff token",
|
||||
"source": "group_stage_survivors",
|
||||
"team_action_items": [
|
||||
|
|
@ -239,20 +300,22 @@ Practical frontend pattern:
|
|||
1. load initial tournament state over HTTP
|
||||
2. open websocket subscription for same tournament id
|
||||
3. render incoming websocket payload as latest live snapshot
|
||||
4. when user checks or unchecks one team, send one idempotent HTTP `PATCH` for that item only
|
||||
5. let websocket keep other viewers in sync
|
||||
4. if owner submits create form, send one HTTP `POST` to create the list
|
||||
5. when user checks or unchecks one team, send one idempotent HTTP `PATCH` for that item only
|
||||
6. let websocket keep other viewers in sync
|
||||
|
||||
This avoids whole-list writebacks and reduces race-condition risk between multiple clients.
|
||||
|
||||
## Future Extension Guidance
|
||||
|
||||
When new lists are added, frontend should not hardcode backend internals beyond:
|
||||
When new sources or list types are added, frontend should not hardcode backend internals beyond:
|
||||
|
||||
- stable list `key`
|
||||
- user-facing `name`
|
||||
- user-facing `action_name`
|
||||
- selected `source`
|
||||
|
||||
New list types should automatically fit the same frontend rendering model:
|
||||
New list types should still fit same frontend rendering model:
|
||||
|
||||
- list metadata
|
||||
- list items
|
||||
|
|
|
|||
Loading…
Reference in New Issue