feat: jersey size selection in checkout flow #141

Closed
opened 2026-03-21 21:03:54 +00:00 by forgejo_admin · 0 comments

Type

Feature

Lineage

plan-wkq → Phase 11 (Girls Tryout) → discovered during jersey email blast 2026-03-21
Parent reported no size option on jersey checkout page.

Repo

forgejo_admin/basketball-api

User Story

As a parent, I want to select a jersey size during checkout so that my child gets the right fit

Context

The jersey checkout flow has no size selection. Parents pick an option ($90/$130/opt-out) but never specify a size. Size is carried as Stripe session metadata alongside jersey_option and player_id — no new Stripe Products or Prices needed. The webhook reads it back on payment confirmation and saves to a new jersey_size column on the players table.

File Targets

Files the agent should modify:

  • src/basketball_api/routes/jersey.py — accept size param in POST /jersey/checkout, pass to Stripe session metadata
  • src/basketball_api/routes/webhooks.py — read jersey_size from Stripe metadata on checkout.session.completed, save to player
  • src/basketball_api/models.py (or wherever Player model lives) — add jersey_size column (string enum: YS, YM, YL, YXL, AS, AM, AL, AXL)
  • alembic/versions/ — new migration adding jersey_size column to players table
  • src/basketball_api/routes/jersey.py — add GET /jersey/sizes endpoint returning available sizes

Files the agent should NOT touch:

  • src/basketball_api/services/email.py — email templates are separate
  • src/basketball_api/routes/admin.py — admin endpoints unrelated

Acceptance Criteria

  • POST /jersey/checkout accepts size param and passes it as Stripe session metadata jersey_size
  • POST /jersey/checkout rejects requests without size (except opt-out)
  • Webhook reads jersey_size from metadata and saves to player.jersey_size
  • GET /jersey/sizes returns available sizes (YS, YM, YL, YXL, AS, AM, AL, AXL)
  • Opt-out flow unchanged — no size required
  • New alembic migration adds jersey_size column

Test Expectations

  • Unit test: checkout with size passes size in Stripe metadata
  • Unit test: checkout without size returns 422 (except opt-out)
  • Unit test: webhook saves jersey_size from metadata
  • Unit test: sizes endpoint returns all options
  • Run command: pytest tests/ -k jersey

Constraints

  • Size is a string enum: YS, YM, YL, YXL, AS, AM, AL, AXL
  • Size stored in Stripe session metadata — NOT a separate Stripe Product
  • Price does not change based on size
  • Opt-out does not require size

Checklist

  • PR opened
  • Tests pass
  • No unrelated changes
  • plan-wkq — Phase 11
  • project-westside-basketball
  • basketball-api #137 — related jersey_option timing fix
### Type Feature ### Lineage `plan-wkq` → Phase 11 (Girls Tryout) → discovered during jersey email blast 2026-03-21 Parent reported no size option on jersey checkout page. ### Repo `forgejo_admin/basketball-api` ### User Story As a parent, I want to select a jersey size during checkout so that my child gets the right fit ### Context The jersey checkout flow has no size selection. Parents pick an option ($90/$130/opt-out) but never specify a size. Size is carried as Stripe session metadata alongside `jersey_option` and `player_id` — no new Stripe Products or Prices needed. The webhook reads it back on payment confirmation and saves to a new `jersey_size` column on the players table. ### File Targets Files the agent should modify: - `src/basketball_api/routes/jersey.py` — accept `size` param in `POST /jersey/checkout`, pass to Stripe session metadata - `src/basketball_api/routes/webhooks.py` — read `jersey_size` from Stripe metadata on `checkout.session.completed`, save to player - `src/basketball_api/models.py` (or wherever Player model lives) — add `jersey_size` column (string enum: YS, YM, YL, YXL, AS, AM, AL, AXL) - `alembic/versions/` — new migration adding `jersey_size` column to players table - `src/basketball_api/routes/jersey.py` — add `GET /jersey/sizes` endpoint returning available sizes Files the agent should NOT touch: - `src/basketball_api/services/email.py` — email templates are separate - `src/basketball_api/routes/admin.py` — admin endpoints unrelated ### Acceptance Criteria - [ ] `POST /jersey/checkout` accepts `size` param and passes it as Stripe session metadata `jersey_size` - [ ] `POST /jersey/checkout` rejects requests without `size` (except opt-out) - [ ] Webhook reads `jersey_size` from metadata and saves to `player.jersey_size` - [ ] `GET /jersey/sizes` returns available sizes (YS, YM, YL, YXL, AS, AM, AL, AXL) - [ ] Opt-out flow unchanged — no size required - [ ] New alembic migration adds `jersey_size` column ### Test Expectations - [ ] Unit test: checkout with size passes size in Stripe metadata - [ ] Unit test: checkout without size returns 422 (except opt-out) - [ ] Unit test: webhook saves jersey_size from metadata - [ ] Unit test: sizes endpoint returns all options - Run command: `pytest tests/ -k jersey` ### Constraints - Size is a string enum: YS, YM, YL, YXL, AS, AM, AL, AXL - Size stored in Stripe session metadata — NOT a separate Stripe Product - Price does not change based on size - Opt-out does not require size ### Checklist - [ ] PR opened - [ ] Tests pass - [ ] No unrelated changes ### Related - `plan-wkq` — Phase 11 - `project-westside-basketball` - basketball-api #137 — related jersey_option timing fix
forgejo_admin 2026-03-21 21:13:32 +00:00
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/basketball-api#141
No description provided.