feat: seed team contract configs + audit player overrides #322

Closed
opened 2026-04-03 23:50:34 +00:00 by forgejo_admin · 3 comments

Type

Feature

Lineage

Sub-ticket of forgejo_admin/westside-contracts#34 — data-driven contract rendering system. Wave 2. Board note: board-34-data-driven-contracts.

Dispatch Gate

DO NOT dispatch until basketball-api#319 (contract_config column) and basketball-api#321 (contract_overrides column) are MERGED and deployed. Both columns must exist before this data migration runs.

Repo

forgejo_admin/basketball-api

User Story

As the contract rendering system, I need each team's contract_config populated with structured data AND every player with custom terms to have contract_overrides set, so that the frontend renders correct contracts for all players.

Context

Two-part data migration:

Part 1 — Team configs. Extract hardcoded HTML content from westside-contracts Svelte template into JSONB for all 7 teams. 3 variants: boys-travel, girls-travel, local. Queens schedule: Wednesday Granger 6:30-7:30 (not Friday BWill).

Part 2 — Player override audit. 12+ players have custom fees, notes, or non-standard deals needing structured contract_overrides.

Team Config JSON Schema

Each team gets a contract_config JSONB value following this shape:

{
  "season": "Spring / Summer 2026",
  "variant": "girls-travel",
  "monthly_fee_default": 200,
  "tournaments": [
    {
      "id": "utah-girls-invitational",
      "name": "Utah Girls Invitational",
      "dates": "April 10-11, 2026",
      "local": true,
      "cost": 70
    },
    {
      "id": "denver",
      "name": "Trip 1: Denver",
      "dates": "May 7-10, 2026",
      "local": false,
      "entry_fee": 60,
      "travel": {
        "transportation": 50,
        "gas": 40,
        "coaches_fee": 50,
        "lodging": 178,
        "total": 320
      }
    }
  ],
  "practices": [
    { "day": "Tuesday", "location": "West High Field House", "time": "6-8 PM" },
    { "day": "Thursday", "location": "LCA", "time": "5-6 PM weights", "optional": true },
    { "day": "Wednesday", "location": "Granger High School", "time": "6:30-7:30 PM" }
  ],
  "payments": [
    { "label": "Jersey order", "date": "ASAP" },
    { "label": "First monthly fee — prorated", "date": "April 6", "use_prorated_fee": true },
    { "label": "Monthly fee (ongoing)", "date": "1st of each month" }
  ],
  "sections": {
    "jersey": true,
    "live_periods": true,
    "recruiting": false,
    "fundraising": true,
    "roster_flexibility": true,
    "age_reassignment": true,
    "rules_of_conduct": true,
    "commitment": true,
    "communication": true
  },
  "static_content": {
    "live_periods": "The Nike EYBL Tournament...",
    "fundraising": "Westside has partnered with Vertical Raise...",
    "roster_flexibility": "Westside Queens is actively building...",
    "age_reassignment": "The Westside Queens program includes..."
  }
}

Variant assignments:

  • boys-travel: 17U Elite Kings (id=1), 17U Select Kings (id=2), 16U Elite Kings (id=3)
  • girls-travel: 17U Elite Queens (id=4), 16U Elite Queens (id=5)
  • local: 17U Local Kings (id=6), 16U Local Kings (id=7)

IMPORTANT: Read the full tournament, practice, and payment details from src/routes/contract/[token]/+page.svelte in the westside-contracts repo. The hardcoded HTML is the source of truth. Each tournament needs a stable kebab-case id field.

Player Override JSON Schema

Player overrides are sparse — only fields that differ from team defaults:

{
  "tournaments": ["mesa-az", "nike-vegas"],
  "practices": [
    { "day": "Wednesday", "location": "Granger High School", "time": "6:30-7:30 PM" }
  ],
  "payments": [
    { "label": "Jersey order", "date": "ASAP" },
    { "label": "Monthly fee (ongoing)", "date": "1st of each month" }
  ],
  "note": "Tournament fees paid separately. 1 practice per week.",
  "sections": {
    "roster_flexibility": false,
    "age_reassignment": false
  }
}

Players Needing Overrides

Player ID Name Team Fee Override Needed
184 Kiana Sikander 17U Elite Queens $100 tournaments:["mesa-az","nike-vegas"], 1 practice, custom note
190 Kelsie Stevens 16U Elite Queens $200 variant:"local" — local tournaments + scrimmages only
107 Sophie Furse 16U Elite Queens $200 variant:"local" — same as Kelsie
128 Natalie Garcia 17U Elite Queens $160 Clear "Custom contract needed" flag after review
186 Analeigh Apaisa 16U Elite Queens $58 Note stays in custom_notes (age 11 eligibility) — no rendering override
111 Aleiyah Apaisa 17U Elite Queens $59 Note stays in custom_notes (dual-team) — no rendering override
112 Ayvah Apaisa 17U Elite Queens $58 Note stays in custom_notes (dual-team) — no rendering override
100 Carter Milbourn 17U Elite Kings $200 Note stays in custom_notes (gas stipend display) — no rendering override
115 Tristen Thorn 17U Elite Kings $200 Note stays in custom_notes (gas stipend display) — no rendering override
110 Austin Porter 17U Select Kings $200 Note stays in custom_notes (gas stipend display) — no rendering override
138 Hunter Froebe 17U Local Kings $0 Note stays in custom_notes (gas stipend display) — no rendering override
158 Max Jordan 17U Local Kings $0 Note stays in custom_notes (gas stipend display) — no rendering override

Rules:

  • contract_overrides = rendering config (what the page should show differently)
  • custom_notes = display-only "Additional Terms" text (stays as-is for eligibility/stipend notes)
  • Internal flags like "Custom contract needed" or "Going to be local - custom contract" → clear after override is set

File Targets

  • alembic/versions/NNN_seed_team_contract_configs.py — team config data migration
  • alembic/versions/NNN_set_player_contract_overrides.py — player overrides + custom_notes cleanup

Acceptance Criteria

  • All 7 teams have non-NULL contract_config with correct variant
  • Each tournament has a stable kebab-case ID
  • Queens team configs have Wednesday Granger practice (not Friday BWill)
  • Kiana: overrides with tournament filter + 1 practice + note
  • Kelsie + Sophie: overrides with variant:local
  • Apaisa sisters: eligibility notes stay in custom_notes, no rendering override
  • Gas stipend players: notes stay in custom_notes
  • "Custom contract needed" / "Going to be local" cleared after override set
  • Both migrations reversible

Test Expectations

  • alembic upgrade head clean
  • alembic downgrade -1 clean for both
  • Spot check: SELECT contract_config->'variant' FROM teams
  • Spot check: SELECT contract_overrides FROM players WHERE id IN (184, 190, 107)
  • Run command: pytest tests/

Constraints

  • Must exactly reproduce current hardcoded content for team configs
  • Tournament IDs must be stable (player overrides reference them)
  • custom_notes cleanup: preserve display text, clear internal flags only
  • Read westside-contracts +page.svelte for the source of truth on tournament/practice/payment data

Checklist

  • PR opened
  • Tests pass
  • No unrelated changes
  • westside-basketball — parent project
  • forgejo_admin/westside-contracts#34 — parent issue
  • Architecture: arch-contracts-westside-basketball
  • Depends on: basketball-api #319 (T1), basketball-api #321 (T2)
### Type Feature ### Lineage Sub-ticket of `forgejo_admin/westside-contracts#34` — data-driven contract rendering system. Wave 2. Board note: `board-34-data-driven-contracts`. ### Dispatch Gate DO NOT dispatch until basketball-api#319 (contract_config column) and basketball-api#321 (contract_overrides column) are MERGED and deployed. Both columns must exist before this data migration runs. ### Repo `forgejo_admin/basketball-api` ### User Story As the contract rendering system, I need each team's contract_config populated with structured data AND every player with custom terms to have contract_overrides set, so that the frontend renders correct contracts for all players. ### Context Two-part data migration: **Part 1 — Team configs.** Extract hardcoded HTML content from westside-contracts Svelte template into JSONB for all 7 teams. 3 variants: boys-travel, girls-travel, local. Queens schedule: Wednesday Granger 6:30-7:30 (not Friday BWill). **Part 2 — Player override audit.** 12+ players have custom fees, notes, or non-standard deals needing structured contract_overrides. ### Team Config JSON Schema Each team gets a `contract_config` JSONB value following this shape: ```json { "season": "Spring / Summer 2026", "variant": "girls-travel", "monthly_fee_default": 200, "tournaments": [ { "id": "utah-girls-invitational", "name": "Utah Girls Invitational", "dates": "April 10-11, 2026", "local": true, "cost": 70 }, { "id": "denver", "name": "Trip 1: Denver", "dates": "May 7-10, 2026", "local": false, "entry_fee": 60, "travel": { "transportation": 50, "gas": 40, "coaches_fee": 50, "lodging": 178, "total": 320 } } ], "practices": [ { "day": "Tuesday", "location": "West High Field House", "time": "6-8 PM" }, { "day": "Thursday", "location": "LCA", "time": "5-6 PM weights", "optional": true }, { "day": "Wednesday", "location": "Granger High School", "time": "6:30-7:30 PM" } ], "payments": [ { "label": "Jersey order", "date": "ASAP" }, { "label": "First monthly fee — prorated", "date": "April 6", "use_prorated_fee": true }, { "label": "Monthly fee (ongoing)", "date": "1st of each month" } ], "sections": { "jersey": true, "live_periods": true, "recruiting": false, "fundraising": true, "roster_flexibility": true, "age_reassignment": true, "rules_of_conduct": true, "commitment": true, "communication": true }, "static_content": { "live_periods": "The Nike EYBL Tournament...", "fundraising": "Westside has partnered with Vertical Raise...", "roster_flexibility": "Westside Queens is actively building...", "age_reassignment": "The Westside Queens program includes..." } } ``` **Variant assignments:** - `boys-travel`: 17U Elite Kings (id=1), 17U Select Kings (id=2), 16U Elite Kings (id=3) - `girls-travel`: 17U Elite Queens (id=4), 16U Elite Queens (id=5) - `local`: 17U Local Kings (id=6), 16U Local Kings (id=7) **IMPORTANT:** Read the full tournament, practice, and payment details from `src/routes/contract/[token]/+page.svelte` in the westside-contracts repo. The hardcoded HTML is the source of truth. Each tournament needs a stable kebab-case `id` field. ### Player Override JSON Schema Player overrides are sparse — only fields that differ from team defaults: ```json { "tournaments": ["mesa-az", "nike-vegas"], "practices": [ { "day": "Wednesday", "location": "Granger High School", "time": "6:30-7:30 PM" } ], "payments": [ { "label": "Jersey order", "date": "ASAP" }, { "label": "Monthly fee (ongoing)", "date": "1st of each month" } ], "note": "Tournament fees paid separately. 1 practice per week.", "sections": { "roster_flexibility": false, "age_reassignment": false } } ``` ### Players Needing Overrides | Player ID | Name | Team | Fee | Override Needed | |-----------|------|------|-----|----------------| | 184 | Kiana Sikander | 17U Elite Queens | $100 | tournaments:["mesa-az","nike-vegas"], 1 practice, custom note | | 190 | Kelsie Stevens | 16U Elite Queens | $200 | variant:"local" — local tournaments + scrimmages only | | 107 | Sophie Furse | 16U Elite Queens | $200 | variant:"local" — same as Kelsie | | 128 | Natalie Garcia | 17U Elite Queens | $160 | Clear "Custom contract needed" flag after review | | 186 | Analeigh Apaisa | 16U Elite Queens | $58 | Note stays in custom_notes (age 11 eligibility) — no rendering override | | 111 | Aleiyah Apaisa | 17U Elite Queens | $59 | Note stays in custom_notes (dual-team) — no rendering override | | 112 | Ayvah Apaisa | 17U Elite Queens | $58 | Note stays in custom_notes (dual-team) — no rendering override | | 100 | Carter Milbourn | 17U Elite Kings | $200 | Note stays in custom_notes (gas stipend display) — no rendering override | | 115 | Tristen Thorn | 17U Elite Kings | $200 | Note stays in custom_notes (gas stipend display) — no rendering override | | 110 | Austin Porter | 17U Select Kings | $200 | Note stays in custom_notes (gas stipend display) — no rendering override | | 138 | Hunter Froebe | 17U Local Kings | $0 | Note stays in custom_notes (gas stipend display) — no rendering override | | 158 | Max Jordan | 17U Local Kings | $0 | Note stays in custom_notes (gas stipend display) — no rendering override | **Rules:** - `contract_overrides` = rendering config (what the page should show differently) - `custom_notes` = display-only "Additional Terms" text (stays as-is for eligibility/stipend notes) - Internal flags like "Custom contract needed" or "Going to be local - custom contract" → clear after override is set ### File Targets - `alembic/versions/NNN_seed_team_contract_configs.py` — team config data migration - `alembic/versions/NNN_set_player_contract_overrides.py` — player overrides + custom_notes cleanup ### Acceptance Criteria - [ ] All 7 teams have non-NULL contract_config with correct variant - [ ] Each tournament has a stable kebab-case ID - [ ] Queens team configs have Wednesday Granger practice (not Friday BWill) - [ ] Kiana: overrides with tournament filter + 1 practice + note - [ ] Kelsie + Sophie: overrides with variant:local - [ ] Apaisa sisters: eligibility notes stay in custom_notes, no rendering override - [ ] Gas stipend players: notes stay in custom_notes - [ ] "Custom contract needed" / "Going to be local" cleared after override set - [ ] Both migrations reversible ### Test Expectations - [ ] `alembic upgrade head` clean - [ ] `alembic downgrade -1` clean for both - [ ] Spot check: `SELECT contract_config->'variant' FROM teams` - [ ] Spot check: `SELECT contract_overrides FROM players WHERE id IN (184, 190, 107)` - Run command: `pytest tests/` ### Constraints - Must exactly reproduce current hardcoded content for team configs - Tournament IDs must be stable (player overrides reference them) - custom_notes cleanup: preserve display text, clear internal flags only - Read westside-contracts +page.svelte for the source of truth on tournament/practice/payment data ### Checklist - [ ] PR opened - [ ] Tests pass - [ ] No unrelated changes ### Related - `westside-basketball` — parent project - `forgejo_admin/westside-contracts#34` — parent issue - Architecture: `arch-contracts-westside-basketball` - Depends on: basketball-api #319 (T1), basketball-api #321 (T2)
forgejo_admin changed title from feat: seed team contract configs from hardcoded HTML to feat: seed team contract configs + audit player overrides 2026-04-04 20:13:56 +00:00
Author
Owner

Scope Review: NEEDS_REFINEMENT

Review note: review-774-2026-04-03
Ticket is well-scoped with complete template, full traceability, and verified architecture — two actionable refinements needed before dispatch.

  • [BODY] Cross-repo spec reference (pal-e-platform/docs/superpowers/specs/...) — inline the JSON schema into this issue body so the executing agent is self-contained in basketball-api.
  • [BODY] Add explicit dispatch gate: "Do not dispatch until T1 (#319) and T2 (#321) are merged — columns do not exist yet." Both are currently in QA.
## Scope Review: NEEDS_REFINEMENT Review note: `review-774-2026-04-03` Ticket is well-scoped with complete template, full traceability, and verified architecture — two actionable refinements needed before dispatch. - **[BODY]** Cross-repo spec reference (`pal-e-platform/docs/superpowers/specs/...`) — inline the JSON schema into this issue body so the executing agent is self-contained in basketball-api. - **[BODY]** Add explicit dispatch gate: "Do not dispatch until T1 (#319) and T2 (#321) are merged — columns do not exist yet." Both are currently in QA.
Author
Owner

Scope Review: READY

Review note: review-774-2026-04-03 (updated)

Re-review after refinement. Both previous issues resolved:

  • JSON schema inlined in issue body (no more cross-repo path reference)
  • Explicit dispatch gate added

All traceability legs verified. Arch note arch-contracts-westside-basketball confirmed. Dependencies T1/T2 both merged. Ready for dispatch.

## Scope Review: READY Review note: `review-774-2026-04-03` (updated) Re-review after refinement. Both previous issues resolved: - JSON schema inlined in issue body (no more cross-repo path reference) - Explicit dispatch gate added All traceability legs verified. Arch note `arch-contracts-westside-basketball` confirmed. Dependencies T1/T2 both merged. Ready for dispatch.
Author
Owner

Agent picked up this ticket.

Agent picked up this ticket.
forgejo_admin 2026-04-04 22:54:39 +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#322
No description provided.