feat: data-driven contract rendering system #34
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Type
Feature
Lineage
Standalone — discovered during Kiana Sikander contract setup (2026-04-03). Custom player deals can't be rendered by the current hardcoded template system.
Repo
forgejo_admin/westside-contracts(primary),forgejo_admin/basketball-api(migrations + seed)User Story
As a parent receiving a Westside contract, I want to see a player agreement that reflects my child's actual deal — the correct fee, only the tournaments they're committed to, and the practice schedule they agreed to — so that I can sign with confidence the contract matches what was discussed.
As an admin, I want to set up a custom deal for a player (different fee, fewer tournaments, modified schedule) and have the contract page render it correctly — so that I don't need a developer to edit HTML or redeploy.
Context
The contract page has three hardcoded HTML blocks — boys travel (Power 32), girls travel (Prep Hoops Girls), and local. Team name picks the variant via
isLocal/isGirlsflags.monthly_feeis the only dynamic value. Everything else (5 tournaments with full cost breakdowns, 3 practice days, payment schedules) is literal HTML in a 725-line monolithic Svelte component.Kiana Sikander (player_id=184, 17U Elite Queens) agreed to $100/month, 1 practice/week, Arizona + Vegas tournaments only. The current system has no way to render a contract that differs from the team default. The
custom_notesfield renders as a paragraph at the bottom — it can't suppress or replace sections above it.Architecture change: move contract content from hardcoded HTML into structured JSONB data on teams (defaults) and players (overrides). Extract the monolithic Svelte component into focused, data-driven components.
File Targets
basketball-api:
alembic/versions/NNN_add_contract_config_to_teams.py— new migrationalembic/versions/NNN_add_contract_overrides_to_players.py— new migrationalembic/versions/NNN_seed_team_contract_configs.py— data migrationsrc/basketball_api/models.py— add contract_config to Team, contract_overrides to Playerwestside-contracts:
src/routes/contract/[token]/+page.svelte— refactor from 725-line monolith to ~60-line orchestratorsrc/routes/contract/[token]/+page.server.ts— load contract_config + contract_overrides, merge, pass structured datasrc/lib/components/ContractHeader.svelte— newsrc/lib/components/FeeSection.svelte— newsrc/lib/components/TournamentCard.svelte— newsrc/lib/components/TournamentList.svelte— newsrc/lib/components/PracticeSchedule.svelte— newsrc/lib/components/PaymentSchedule.svelte— newsrc/lib/components/StaticSection.svelte— newsrc/lib/components/ContractCallout.svelte— newsrc/lib/components/CustomNote.svelte— newsrc/lib/components/SigningSection.svelte— newsrc/lib/components/SuccessOverlay.svelte— newsrc/lib/components/AlreadySigned.svelte— newsrc/lib/types.ts— add ContractConfig, ContractOverrides, MergedConfig interfacessrc/routes/contract/[token]/sign/+server.ts— read variant from contract_configFiles NOT to touch:
src/lib/validation.ts— signing validation unchangedsrc/lib/minio.ts— signature upload unchangedsrc/lib/db.ts— connection pool unchangedAcceptance Criteria
contract_configset, the contract page renders tournaments, practices, and payments from that datacontract_overrideswith a tournaments filter, only those tournaments appear on the contract pagecontract_overrideswith custom practices, those replace the team default practice schedulecontract_config(NULL), the page falls back to current hardcoded renderingcontract_overrides(NULL), team defaults renderTest Expectations
npm test(westside-contracts),pytest tests/(basketball-api)Constraints
Checklist
Related
westside-agency— parent project for Westside basketball operationspal-e-platform/docs/superpowers/specs/2026-04-03-data-driven-contracts-design.md