Validation: basketball-api#430 — POST /api/jersey-public-orders endpoint

validation-430-2026-04-11 Doc

validation pass

Validation: basketball-api#430 — POST /api/jersey-public-orders endpoint

Verdict: PASS — 2026-04-11. PR #450 merged via squash. T3 of System B production rollout.

Acceptance criteria

  • ✅ New file src/basketball_api/routes/jersey_public.py (160 lines) with inline Pydantic v2 schemas + POST endpoint
  • ✅ Auth: user: User = Depends(get_current_user) from basketball_api.auth (NOT a fictional keycloak_user)
  • ✅ Inline Pydantic — NO schemas/ directory created
  • ✅ Pydantic v2 syntax (Field(..., pattern=...))
  • submitter_keycloak_sub = user.sub stamped on inserted row
  • player_name + email from request body, NOT overridden by JWT (parent-on-behalf-of-child use case preserved, dedicated test verifies)
  • ✅ CHECK constraint patterns enforced for kq, tier, sizes, preferred numbers (regex ^(0|00|[1-9][0-9]?)$)
  • submission_ip populated from X-Forwarded-For (first entry) or request.client.host, parsed via ipaddress.ip_address()
  • ✅ Returns 201 with {id, status, created_at}
  • main.py change is exactly 2 lines (import + include_router with /api/jersey-public-orders prefix)
  • ✅ CORS allowlist includes westsidekingsandqueens.tail5b443a.ts.net
  • ✅ Files NOT touched: routes/checkout.py, routes/jersey.py, routes/__init__.py, models.py, auth.py, alembic/versions/*
  • ✅ 24 unit tests pass in 2.75s (unauth/happy/row-check/all validation paths/body-not-overridden/XFF)
  • ✅ Tests mock get_current_user via FastAPI dependency_overrides — no real Keycloak in CI
  • ✅ Ruff format + check clean

Production verification still needed

After basketball-api ArgoCD reconciles (image build → Harbor push → kustomize tag bump → ArgoCD sync → pod restart), verify:
  • POST /api/jersey-public-orders with valid JWT returns 201 + row in jersey_public_orders
  • POST without auth returns 401
  • End-to-end test from westsidekingsandqueens.tail5b443a.ts.net/jersey-public form → backend insert

Cosmetic nits captured for plan Epilogue per `feedback_nits_to_epilogue.md`

  • Whitespace-only player_name/team edge case
  • Optional EmailStr upgrade (was str + pattern)
  • Tighten 422 assertion specificity in tests

Process flag (raised by QA)

Per feedback_qa_ci_blockers.md: PR body left "CI: full test suite runs with service-container Postgres" unchecked. inet/UUID/CHECK constraint coverage is not real on SQLite. The next CI pipeline run on basketball-api should be checked to confirm tests pass against real Postgres before this validation note can move to pass with full confidence. (Marked PASS provisionally based on dev agent report; will update if CI flags issues.)

What this unblocks

  • T4 (#431) Gmail notification — depends on T3's POST handler existing (now does)
  • T5 (#432) GET admin endpoint — modifies the same routes/jersey_public.py file T3 just created
  • End-to-end System B flow — frontend (T1) can now successfully POST and get 201
  • arch-jersey-intake
  • story:WS-S31
  • validation-429-2026-04-11 — sister validation for the migration this endpoint writes to