feat: add GET /public/coaches endpoint with allowlisted fields #180

Merged
forgejo_admin merged 1 commit from 177-public-coaches-endpoint into main 2026-03-28 00:07:50 +00:00

Summary

Adds unauthenticated GET /public/coaches endpoint returning only allowlisted fields (id, name, role, slug). Enables the dynamic staff page on westside-app without requiring authentication.

Changes

  • src/basketball_api/routes/public.py — Added PublicCoachResponse and PublicCoachesResponse schemas with strict field allowlist. Added /coaches endpoint to existing public router. Queries coaches filtered by tenant_id=1, returns role as raw enum string, derives slug at runtime via name.lower().replace(" ", "-").
  • tests/test_public.py — Added 8 tests across 4 test classes: unauthenticated access (200 without auth, empty response), field allowlist verification, sensitive field exclusion (email, phone, stripe, onboarding, etc.), slug kebab-case derivation, and role enum value correctness.

Test Plan

  • GET /public/coaches returns 200 without Bearer token
  • Response contains only allowlisted fields: id, name, role, slug
  • Sensitive fields (email, phone, stripe_connect_account_id, onboarding_status, etc.) not exposed
  • Slug correctly kebab-cased from name (e.g. "Coach Williams" -> "coach-williams")
  • Role returns raw enum value string (e.g. "head_coach", not "CoachRole.head_coach")
  • All 3 CoachRole enum values tested
  • Full test suite: 611 passed (3 pre-existing failures in test_reconciliation.py due to missing groupme_sdk)
  • ruff format + ruff check clean
  • Forgejo issue: #177
  • Consumes: westside-playground staff.html data contract
  • Sibling: GET /public/teams (same router)
## Summary Adds unauthenticated `GET /public/coaches` endpoint returning only allowlisted fields (id, name, role, slug). Enables the dynamic staff page on westside-app without requiring authentication. ## Changes - `src/basketball_api/routes/public.py` — Added `PublicCoachResponse` and `PublicCoachesResponse` schemas with strict field allowlist. Added `/coaches` endpoint to existing public router. Queries coaches filtered by tenant_id=1, returns role as raw enum string, derives slug at runtime via `name.lower().replace(" ", "-")`. - `tests/test_public.py` — Added 8 tests across 4 test classes: unauthenticated access (200 without auth, empty response), field allowlist verification, sensitive field exclusion (email, phone, stripe, onboarding, etc.), slug kebab-case derivation, and role enum value correctness. ## Test Plan - [x] `GET /public/coaches` returns 200 without Bearer token - [x] Response contains only allowlisted fields: id, name, role, slug - [x] Sensitive fields (email, phone, stripe_connect_account_id, onboarding_status, etc.) not exposed - [x] Slug correctly kebab-cased from name (e.g. "Coach Williams" -> "coach-williams") - [x] Role returns raw enum value string (e.g. "head_coach", not "CoachRole.head_coach") - [x] All 3 CoachRole enum values tested - [x] Full test suite: 611 passed (3 pre-existing failures in test_reconciliation.py due to missing groupme_sdk) - [x] ruff format + ruff check clean ## Related - Forgejo issue: #177 - Consumes: westside-playground staff.html data contract - Sibling: GET /public/teams (same router)
feat: add public coaches endpoint (GET /public/coaches)
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
58e69221f6
Alembic migration 025 adds bio (TEXT), photo_url (VARCHAR 500), and
is_public (BOOLEAN DEFAULT true) to the coaches table. The new endpoint
returns only allowlisted fields for unauthenticated visitors, with a
computed kebab-case slug for anchor links. Coaches where is_public=false
are filtered out. 10 new tests cover auth-free access, field allowlist,
slug format, is_public filtering, role serialization, and nullable fields.

Closes #177

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
forgejo_admin force-pushed 177-public-coaches-endpoint from 58e69221f6
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
to d147f0eff8
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
2026-03-27 22:16:53 +00:00
Compare
forgejo_admin changed title from feat: add public coaches endpoint (GET /public/coaches) to feat: add GET /public/coaches endpoint with allowlisted fields 2026-03-27 22:17:14 +00:00
forgejo_admin deleted branch 177-public-coaches-endpoint 2026-03-28 00:07:50 +00:00
Sign in to join this conversation.
No description provided.