Phase 14: Program Contract Flow — Digital Signature + Billing Activation #39

Closed
opened 2026-03-18 06:11:40 +00:00 by forgejo_admin · 0 comments

Lineage

plan-wkq → Phase 14 (Billing Tiers & Contracts)

Repo

forgejo_admin/westside-app + forgejo_admin/basketball-api

User Story

As a parent
I want to review and sign a program contract when my player is offered a team spot
So that billing starts automatically and my player's roster spot is confirmed

Context

After tryouts, Marcus places players on teams via the admin dashboard. Today there's no digital contract — billing would need to be started manually and there's no legal agreement covering the season commitment.

The contract is a state transition gate: player moves from offeredactive only when the parent signs. Signing triggers the Stripe subscription. No contract = no billing = no roster spot confirmed.

Player lifecycle:

registered → tryout_attended → offered → signed (contract) → active

Two distinct legal moments exist:

  1. Registration waiver (already built) — permission to try out, $30 one-time
  2. Program contract (this issue) — commitment to the season, $200/mo recurring

File Targets

Frontend (westside-app):

  • src/routes/my-players/+page.svelte — add contract CTA when player status is offered
  • src/routes/players/[id]/+page.svelte — show contract status on player profile
  • src/lib/api.js — add contract endpoints

Backend (basketball-api):

  • New endpoint: POST /players/{id}/contract — sign contract, trigger Stripe subscription
  • New endpoint: GET /players/{id}/contract — get contract status/terms
  • Player model: add status field lifecycle (registeredofferedsignedactive)
  • Stripe integration: create subscription on contract signature

Files NOT to touch:

  • src/routes/register/+page.svelte — registration waiver is separate, already working

Acceptance Criteria

  • When Marcus places a player on a team, player status becomes offered
  • When parent logs into /my-players, they see "Contract available" for offered players
  • When parent clicks, they see full contract terms (financial, attendance, conduct, cancellation)
  • When parent signs (digital signature — typed name, same UX as registration waiver), contract is recorded
  • When contract is signed, Stripe subscription ($200/mo) starts automatically
  • When contract is signed, player status becomes active on the roster
  • Admin dashboard shows contract status per player (unsigned/signed/date)

Contract Terms (Assumptions — Confirm with Marcus)

  • Monthly dues: $200/mo starting from signature date
  • Season: Through AAU season (roughly March–July)
  • Cancellation: 14-day window after signing for full refund. After that, cancel future months with 30 days notice, no refund for current month.
  • Tournament fees: Separate, split among team, notified in advance
  • Attendance: 3 practices/week + Saturday skills expected. 2+ unexcused absences triggers coach conversation.
  • Jersey deposit: Separate line item, refundable on return
  • Conduct: Player AND parent conduct standards. Dismissal terms.

Test Expectations

  • Unit test: contract signing creates Stripe subscription
  • Unit test: player status transitions correctly through lifecycle
  • Integration test: full flow — place on team → contract appears → sign → billing active
  • Manual: verify on phone that contract CTA renders in /my-players

Constraints

  • Reuse the same digital signature UX from registration (typed name + checkbox)
  • Contract lives in /my-players — no new routes needed, just a state-aware section
  • Must work for both parent-signed (under 18) and self-signed (18+) cases
  • Stripe subscription via keycloak-js Bearer token — same auth pattern as rest of app

Checklist

  • Backend endpoints implemented
  • Player status lifecycle in DB
  • Stripe subscription integration
  • Frontend contract UI in /my-players
  • Admin visibility of contract status
  • PR opened
  • Tests pass
  • phase-wkq-14-billing-tiers — parent phase note
  • westside-app-user-stories — US-6, US-8
  • Phase 15 (this SPA rebuild) — contract UI will be built into the SPA, not the old SSR app
### Lineage `plan-wkq` → Phase 14 (Billing Tiers & Contracts) ### Repo `forgejo_admin/westside-app` + `forgejo_admin/basketball-api` ### User Story As a parent I want to review and sign a program contract when my player is offered a team spot So that billing starts automatically and my player's roster spot is confirmed ### Context After tryouts, Marcus places players on teams via the admin dashboard. Today there's no digital contract — billing would need to be started manually and there's no legal agreement covering the season commitment. The contract is a **state transition gate**: player moves from `offered` → `active` only when the parent signs. Signing triggers the Stripe subscription. No contract = no billing = no roster spot confirmed. Player lifecycle: ``` registered → tryout_attended → offered → signed (contract) → active ``` Two distinct legal moments exist: 1. **Registration waiver** (already built) — permission to try out, $30 one-time 2. **Program contract** (this issue) — commitment to the season, $200/mo recurring ### File Targets Frontend (`westside-app`): - `src/routes/my-players/+page.svelte` — add contract CTA when player status is `offered` - `src/routes/players/[id]/+page.svelte` — show contract status on player profile - `src/lib/api.js` — add contract endpoints Backend (`basketball-api`): - New endpoint: `POST /players/{id}/contract` — sign contract, trigger Stripe subscription - New endpoint: `GET /players/{id}/contract` — get contract status/terms - Player model: add `status` field lifecycle (`registered` → `offered` → `signed` → `active`) - Stripe integration: create subscription on contract signature Files NOT to touch: - `src/routes/register/+page.svelte` — registration waiver is separate, already working ### Acceptance Criteria - [ ] When Marcus places a player on a team, player status becomes `offered` - [ ] When parent logs into `/my-players`, they see "Contract available" for offered players - [ ] When parent clicks, they see full contract terms (financial, attendance, conduct, cancellation) - [ ] When parent signs (digital signature — typed name, same UX as registration waiver), contract is recorded - [ ] When contract is signed, Stripe subscription ($200/mo) starts automatically - [ ] When contract is signed, player status becomes `active` on the roster - [ ] Admin dashboard shows contract status per player (unsigned/signed/date) ### Contract Terms (Assumptions — Confirm with Marcus) - **Monthly dues:** $200/mo starting from signature date - **Season:** Through AAU season (roughly March–July) - **Cancellation:** 14-day window after signing for full refund. After that, cancel future months with 30 days notice, no refund for current month. - **Tournament fees:** Separate, split among team, notified in advance - **Attendance:** 3 practices/week + Saturday skills expected. 2+ unexcused absences triggers coach conversation. - **Jersey deposit:** Separate line item, refundable on return - **Conduct:** Player AND parent conduct standards. Dismissal terms. ### Test Expectations - [ ] Unit test: contract signing creates Stripe subscription - [ ] Unit test: player status transitions correctly through lifecycle - [ ] Integration test: full flow — place on team → contract appears → sign → billing active - [ ] Manual: verify on phone that contract CTA renders in `/my-players` ### Constraints - Reuse the same digital signature UX from registration (typed name + checkbox) - Contract lives in `/my-players` — no new routes needed, just a state-aware section - Must work for both parent-signed (under 18) and self-signed (18+) cases - Stripe subscription via `keycloak-js` Bearer token — same auth pattern as rest of app ### Checklist - [ ] Backend endpoints implemented - [ ] Player status lifecycle in DB - [ ] Stripe subscription integration - [ ] Frontend contract UI in `/my-players` - [ ] Admin visibility of contract status - [ ] PR opened - [ ] Tests pass ### Related - `phase-wkq-14-billing-tiers` — parent phase note - `westside-app-user-stories` — US-6, US-8 - Phase 15 (this SPA rebuild) — contract UI will be built into the SPA, not the old SSR app
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-app#39
No description provided.