feat: Team management UI — admin draft board + coach filtered roster (Phase 10b) #16

Closed
opened 2026-03-14 22:20:50 +00:00 by forgejo_admin · 0 comments

Lineage

plan-2026-03-08-tryout-prep → Phase 10 (Team Placement) → Phase 10b (Frontend)

Repo

forgejo_admin/westside-app

User Story

As an admin
I want a draft board page where I can assign players to teams and see team overviews
So that I can organize 45 players into teams before the season starts

As a coach
I want to see only my team's roster when I log in
So that I can focus on my players without sifting through the full roster

Context

Phase 10a (basketball-api Issue #81) adds the Team model and REST endpoints. This issue builds the frontend that consumes those endpoints. The app already has admin/coach/player role-based routing via Keycloak OIDC (Auth.js). All data fetching is server-side via src/lib/server/api.js — the client never calls basketball-api directly.

Key patterns already established:

  • Server-side load in +page.server.js, form actions for mutations
  • use:enhance + invalidateAll() for reactive updates
  • Role guards via session.roles.includes('admin')
  • Dark theme, red accent (#c41230), responsive grid layouts
  • Coach page uses card grid sorted by tryout number

File Targets

Files the agent should create:

  • src/routes/admin/teams/+page.server.js — load teams + unassigned players from basketball-api, form actions for create/assign/unassign
  • src/routes/admin/teams/+page.svelte — admin draft board UI: team cards with player lists, unassigned player pool, assignment controls
  • src/routes/teams/+page.server.js — load team overview (public summary or auth-gated)
  • src/routes/teams/+page.svelte — team overview page (all teams, player counts, coaches)

Files the agent should modify:

  • src/lib/server/api.js — add functions: fetchTeams(), fetchTeam(teamId), fetchTeamOverview(), createTeam(), assignPlayers(teamId, playerIds), unassignPlayer(teamId, playerId), fetchMyTeam(token)
  • src/lib/components/AuthStatus.svelte — add "Teams" nav link for admin role
  • src/routes/coach/+page.server.js — modify to fetch coach's assigned team via GET /api/teams/mine instead of full roster (pass auth token)
  • src/routes/coach/+page.svelte — show team name and coach assignment at top of roster

Files the agent should NOT touch:

  • src/routes/admin/users/ — user management is separate
  • src/lib/server/keycloak-admin.js — no Keycloak changes needed
  • src/routes/player/ — player view is Phase 11

Acceptance Criteria

  • Admin sees "Teams" link in nav when logged in
  • /admin/teams shows all teams with player counts and assigned coach
  • Admin can create a new team (name, division, age_group)
  • Admin can assign a coach to a team via dropdown
  • Unassigned player pool shows all players not on a team
  • Admin can assign players to teams (select players → assign to team)
  • Admin can unassign a player from a team
  • Team overview shows total counts: teams, assigned players, unassigned players
  • Coach page (/coach) shows ONLY their team's roster (filtered by Keycloak identity)
  • Coach page shows team name at top of roster view
  • All pages have proper role guards (admin pages 403 for non-admin, coach page 403 for non-coach)

Test Expectations

  • Manual test: admin creates team → assigns players → coach sees only their team
  • Manual test: admin unassigns player → player moves back to unassigned pool
  • Manual test: coach without team sees empty state message
  • Manual test: non-admin accessing /admin/teams gets 403
  • Run: manual browser testing (no automated frontend tests in this repo yet)

Constraints

  • Follow existing data fetching pattern: all API calls in src/lib/server/api.js, called from +page.server.js
  • Follow existing form action pattern: use:enhance + invalidateAll()
  • Follow existing styling: dark theme, scoped CSS, responsive grids
  • Server-side only — basketball-api calls must use BASKETBALL_API_URL env var from $env/dynamic/private
  • Pass Keycloak JWT to basketball-api for auth-gated endpoints (coach's /api/teams/mine)
  • Run npm run check and npm run lint before committing
  • Woodpecker CI is broken for SvelteKit — manual docker build required for deploy

Checklist

  • PR opened
  • No unrelated changes
  • Styling matches existing pages
  • westside-basketball — project
  • basketball-api Issue #81 (Phase 10a) — backend this consumes
  • Blocks: Phase 11 (Player Profiles), Phase 12 (Stats Collection)
### Lineage `plan-2026-03-08-tryout-prep` → Phase 10 (Team Placement) → Phase 10b (Frontend) ### Repo `forgejo_admin/westside-app` ### User Story As an admin I want a draft board page where I can assign players to teams and see team overviews So that I can organize 45 players into teams before the season starts As a coach I want to see only my team's roster when I log in So that I can focus on my players without sifting through the full roster ### Context Phase 10a (basketball-api Issue #81) adds the Team model and REST endpoints. This issue builds the frontend that consumes those endpoints. The app already has admin/coach/player role-based routing via Keycloak OIDC (Auth.js). All data fetching is server-side via `src/lib/server/api.js` — the client never calls basketball-api directly. Key patterns already established: - Server-side load in `+page.server.js`, form actions for mutations - `use:enhance` + `invalidateAll()` for reactive updates - Role guards via `session.roles.includes('admin')` - Dark theme, red accent (#c41230), responsive grid layouts - Coach page uses card grid sorted by tryout number ### File Targets Files the agent should create: - `src/routes/admin/teams/+page.server.js` — load teams + unassigned players from basketball-api, form actions for create/assign/unassign - `src/routes/admin/teams/+page.svelte` — admin draft board UI: team cards with player lists, unassigned player pool, assignment controls - `src/routes/teams/+page.server.js` — load team overview (public summary or auth-gated) - `src/routes/teams/+page.svelte` — team overview page (all teams, player counts, coaches) Files the agent should modify: - `src/lib/server/api.js` — add functions: `fetchTeams()`, `fetchTeam(teamId)`, `fetchTeamOverview()`, `createTeam()`, `assignPlayers(teamId, playerIds)`, `unassignPlayer(teamId, playerId)`, `fetchMyTeam(token)` - `src/lib/components/AuthStatus.svelte` — add "Teams" nav link for admin role - `src/routes/coach/+page.server.js` — modify to fetch coach's assigned team via `GET /api/teams/mine` instead of full roster (pass auth token) - `src/routes/coach/+page.svelte` — show team name and coach assignment at top of roster Files the agent should NOT touch: - `src/routes/admin/users/` — user management is separate - `src/lib/server/keycloak-admin.js` — no Keycloak changes needed - `src/routes/player/` — player view is Phase 11 ### Acceptance Criteria - [ ] Admin sees "Teams" link in nav when logged in - [ ] `/admin/teams` shows all teams with player counts and assigned coach - [ ] Admin can create a new team (name, division, age_group) - [ ] Admin can assign a coach to a team via dropdown - [ ] Unassigned player pool shows all players not on a team - [ ] Admin can assign players to teams (select players → assign to team) - [ ] Admin can unassign a player from a team - [ ] Team overview shows total counts: teams, assigned players, unassigned players - [ ] Coach page (`/coach`) shows ONLY their team's roster (filtered by Keycloak identity) - [ ] Coach page shows team name at top of roster view - [ ] All pages have proper role guards (admin pages 403 for non-admin, coach page 403 for non-coach) ### Test Expectations - [ ] Manual test: admin creates team → assigns players → coach sees only their team - [ ] Manual test: admin unassigns player → player moves back to unassigned pool - [ ] Manual test: coach without team sees empty state message - [ ] Manual test: non-admin accessing /admin/teams gets 403 - Run: manual browser testing (no automated frontend tests in this repo yet) ### Constraints - Follow existing data fetching pattern: all API calls in `src/lib/server/api.js`, called from `+page.server.js` - Follow existing form action pattern: `use:enhance` + `invalidateAll()` - Follow existing styling: dark theme, scoped CSS, responsive grids - Server-side only — basketball-api calls must use `BASKETBALL_API_URL` env var from `$env/dynamic/private` - Pass Keycloak JWT to basketball-api for auth-gated endpoints (coach's `/api/teams/mine`) - Run `npm run check` and `npm run lint` before committing - Woodpecker CI is broken for SvelteKit — manual docker build required for deploy ### Checklist - [ ] PR opened - [ ] No unrelated changes - [ ] Styling matches existing pages ### Related - `westside-basketball` — project - basketball-api Issue #81 (Phase 10a) — backend this consumes - Blocks: Phase 11 (Player Profiles), Phase 12 (Stats Collection)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
forgejo_admin/westside-landing#16
No description provided.