Add contract_token and contract_signature_url columns to Player model #152

Closed
opened 2026-03-24 00:49:52 +00:00 by forgejo_admin · 2 comments

Type

Feature

Lineage

plan-wkq → Phase 14 (Billing Tiers & Contracts) → E-Sign Contract Page prerequisite

Repo

forgejo_admin/basketball-api

User Story

As the contract signing system
I want a contract_token on the Player model to resolve tokenized email links, and a contract_signature_url to store the drawn signature image
So that the westside-contracts service can authenticate and record e-signatures without Keycloak login

Context

The new westside-contracts SvelteKit service (westside-app #72) needs two columns that don't exist yet:

  1. contract_token — a secrets.token_urlsafe(32) string, same pattern as Parent.registration_token and Coach.invite_token. Used in email links so parents can access the contract page without logging in. One token per player. No expiry needed (contract is a one-time sign).

  2. contract_signature_url — stores the MinIO URL of the drawn signature image (PNG). Written by westside-contracts after the parent signs.

This is a blocking prerequisite for westside-app #72.

File Targets

Files to modify:

  • src/basketball_api/models.py — add contract_token (String(100), unique, nullable) and contract_signature_url (String(500), nullable) to Player model
  • alembic/versions/NNN_add_contract_token_and_signature_url.py — new migration

Files NOT to touch:

  • src/basketball_api/routes/players.py — existing contract endpoints stay as-is, westside-contracts handles the new token flow
  • src/basketball_api/routes/admin.py — token generation will be triggered by westside-contracts or a future admin endpoint, not this ticket

Acceptance Criteria

  • contract_token column exists on players table (String(100), unique, nullable)
  • contract_signature_url column exists on players table (String(500), nullable)
  • Migration runs cleanly against existing data (all existing rows get NULL for both columns)
  • Model changes match existing patterns (see registration_token, invite_token)

Test Expectations

  • Migration up/down works: alembic upgrade head and alembic downgrade -1
  • Existing contract tests still pass: pytest tests/test_contract.py
  • Full suite passes: pytest tests/
  • Run command: pytest tests/ -v

Constraints

  • Follow existing token pattern: String(100), unique=True, nullable=True
  • contract_signature_url is String(500) to accommodate MinIO URLs
  • No route changes — this is schema only
  • No default values — both columns nullable

Checklist

  • PR opened
  • Tests pass
  • No unrelated changes
  • project-westside-basketball — project
  • westside-app #72 — parent ticket (E-Sign Contract Page), blocked by this
  • plan-wkq → Phase 14 — Billing Tiers & Contracts
### Type Feature ### Lineage `plan-wkq` → Phase 14 (Billing Tiers & Contracts) → E-Sign Contract Page prerequisite ### Repo `forgejo_admin/basketball-api` ### User Story As the contract signing system I want a `contract_token` on the Player model to resolve tokenized email links, and a `contract_signature_url` to store the drawn signature image So that the westside-contracts service can authenticate and record e-signatures without Keycloak login ### Context The new westside-contracts SvelteKit service (westside-app #72) needs two columns that don't exist yet: 1. `contract_token` — a `secrets.token_urlsafe(32)` string, same pattern as `Parent.registration_token` and `Coach.invite_token`. Used in email links so parents can access the contract page without logging in. One token per player. No expiry needed (contract is a one-time sign). 2. `contract_signature_url` — stores the MinIO URL of the drawn signature image (PNG). Written by westside-contracts after the parent signs. This is a blocking prerequisite for westside-app #72. ### File Targets Files to modify: - `src/basketball_api/models.py` — add `contract_token` (String(100), unique, nullable) and `contract_signature_url` (String(500), nullable) to Player model - `alembic/versions/NNN_add_contract_token_and_signature_url.py` — new migration Files NOT to touch: - `src/basketball_api/routes/players.py` — existing contract endpoints stay as-is, westside-contracts handles the new token flow - `src/basketball_api/routes/admin.py` — token generation will be triggered by westside-contracts or a future admin endpoint, not this ticket ### Acceptance Criteria - [ ] `contract_token` column exists on players table (String(100), unique, nullable) - [ ] `contract_signature_url` column exists on players table (String(500), nullable) - [ ] Migration runs cleanly against existing data (all existing rows get NULL for both columns) - [ ] Model changes match existing patterns (see `registration_token`, `invite_token`) ### Test Expectations - [ ] Migration up/down works: `alembic upgrade head` and `alembic downgrade -1` - [ ] Existing contract tests still pass: `pytest tests/test_contract.py` - [ ] Full suite passes: `pytest tests/` - Run command: `pytest tests/ -v` ### Constraints - Follow existing token pattern: `String(100), unique=True, nullable=True` - `contract_signature_url` is `String(500)` to accommodate MinIO URLs - No route changes — this is schema only - No default values — both columns nullable ### Checklist - [ ] PR opened - [ ] Tests pass - [ ] No unrelated changes ### Related - `project-westside-basketball` — project - westside-app #72 — parent ticket (E-Sign Contract Page), blocked by this - `plan-wkq` → Phase 14 — Billing Tiers & Contracts
Author
Owner

QA review in progress for PR #153.

QA review in progress for PR #153.
Author
Owner

Scope Update

monthly_fee (Integer, nullable) was added to this ticket during the session at Lucas's direction. Per-player monthly fee supports tiered pricing ($200 standard, $180 LCA, $160 Cyprus girls). Contract page reads this field to render the correct amount.

This is not scope creep — it was a deliberate addition during contract design. Updating issue description would require re-creation; documenting here instead.

## Scope Update `monthly_fee` (Integer, nullable) was added to this ticket during the session at Lucas's direction. Per-player monthly fee supports tiered pricing ($200 standard, $180 LCA, $160 Cyprus girls). Contract page reads this field to render the correct amount. This is not scope creep — it was a deliberate addition during contract design. Updating issue description would require re-creation; documenting here instead.
forgejo_admin 2026-03-24 07:09:49 +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#152
No description provided.