feat: add contract signing backend (status, endpoints, migration) #97

Closed
opened 2026-03-18 14:57:26 +00:00 by forgejo_admin · 0 comments

Lineage

plan-wkq -> Phase 14 (Program Contract Flow)

Repo

forgejo_admin/basketball-api

User Story

As a parent
I want to digitally sign my child's program contract
So that my child can be activated for the basketball program

Context

Phase 14 introduces a digital contract signing flow for player program enrollment. Parents must sign a contract before their child's subscription can be activated. This issue covers only the backend: model changes, migration, and API endpoints. The frontend UI and Stripe subscription activation are separate steps.

The contract signing follows the same digital signature pattern already established by Parent.waiver_signed / waiver_signed_at / waiver_signed_ip and Coach.contractor_agreement_signed / OnboardingStatus. The contract_status field uses a three-state enum (none, offered, signed) to track the contract lifecycle.

File Targets

Files to modify or create:

  • src/basketball_api/models.py -- add ContractStatus enum, add contract fields to Player
  • alembic/versions/010_add_contract_fields.py -- migration for new columns
  • src/basketball_api/routes/players.py -- add POST/GET contract endpoints
  • src/basketball_api/routes/account.py -- add contract_status to AccountPlayerResponse
  • src/basketball_api/routes/admin.py -- add contract_status to AdminPlayerItem
  • tests/test_contract.py -- new test file for contract endpoints

Acceptance Criteria

  • Player model has contract_status (enum: none, offered, signed), contract_signed_at, contract_signed_by, contract_signed_ip fields
  • Alembic migration creates the new columns with correct defaults
  • POST /players/{id}/contract accepts {signature_name, accepted}, sets contract_status to signed, records timestamp/signer/IP
  • POST /players/{id}/contract requires auth: must be the player's parent (email match) or admin
  • GET /players/{id}/contract returns contract status for any authenticated user
  • /account/players response includes contract_status
  • /admin/players response includes contract_status

Test Expectations

  • Unit test: POST contract signs successfully as parent
  • Unit test: POST contract signs successfully as admin
  • Unit test: POST contract rejected without accepted=true
  • Unit test: POST contract 403 for non-parent non-admin
  • Unit test: POST contract 409 if already signed
  • Unit test: GET contract returns correct status
  • Unit test: account players includes contract_status
  • Unit test: admin players includes contract_status
  • Run command: pytest tests/ -v

Constraints

  • Follow existing digital signature pattern (Parent.waiver_signed_at, Coach.contractor_agreement_signed)
  • Use get_current_user dependency for auth, matching existing route patterns
  • Do NOT integrate Stripe subscription creation -- that is a separate step
  • Migration down_revision must chain from 009

Checklist

  • PR opened
  • Tests pass
  • No unrelated changes
### Lineage `plan-wkq` -> Phase 14 (Program Contract Flow) ### Repo `forgejo_admin/basketball-api` ### User Story As a parent I want to digitally sign my child's program contract So that my child can be activated for the basketball program ### Context Phase 14 introduces a digital contract signing flow for player program enrollment. Parents must sign a contract before their child's subscription can be activated. This issue covers only the backend: model changes, migration, and API endpoints. The frontend UI and Stripe subscription activation are separate steps. The contract signing follows the same digital signature pattern already established by `Parent.waiver_signed` / `waiver_signed_at` / `waiver_signed_ip` and `Coach.contractor_agreement_signed` / `OnboardingStatus`. The `contract_status` field uses a three-state enum (none, offered, signed) to track the contract lifecycle. ### File Targets Files to modify or create: - `src/basketball_api/models.py` -- add ContractStatus enum, add contract fields to Player - `alembic/versions/010_add_contract_fields.py` -- migration for new columns - `src/basketball_api/routes/players.py` -- add POST/GET contract endpoints - `src/basketball_api/routes/account.py` -- add contract_status to AccountPlayerResponse - `src/basketball_api/routes/admin.py` -- add contract_status to AdminPlayerItem - `tests/test_contract.py` -- new test file for contract endpoints ### Acceptance Criteria - [ ] Player model has `contract_status` (enum: none, offered, signed), `contract_signed_at`, `contract_signed_by`, `contract_signed_ip` fields - [ ] Alembic migration creates the new columns with correct defaults - [ ] `POST /players/{id}/contract` accepts `{signature_name, accepted}`, sets contract_status to signed, records timestamp/signer/IP - [ ] `POST /players/{id}/contract` requires auth: must be the player's parent (email match) or admin - [ ] `GET /players/{id}/contract` returns contract status for any authenticated user - [ ] `/account/players` response includes `contract_status` - [ ] `/admin/players` response includes `contract_status` ### Test Expectations - [ ] Unit test: POST contract signs successfully as parent - [ ] Unit test: POST contract signs successfully as admin - [ ] Unit test: POST contract rejected without accepted=true - [ ] Unit test: POST contract 403 for non-parent non-admin - [ ] Unit test: POST contract 409 if already signed - [ ] Unit test: GET contract returns correct status - [ ] Unit test: account players includes contract_status - [ ] Unit test: admin players includes contract_status - Run command: `pytest tests/ -v` ### Constraints - Follow existing digital signature pattern (Parent.waiver_signed_at, Coach.contractor_agreement_signed) - Use `get_current_user` dependency for auth, matching existing route patterns - Do NOT integrate Stripe subscription creation -- that is a separate step - Migration down_revision must chain from `009` ### Checklist - [ ] PR opened - [ ] Tests pass - [ ] No unrelated changes ### Related - `westside-app` -- frontend project consuming these endpoints - Parent issue: forgejo_admin/westside-app#39
forgejo_admin 2026-03-18 15:07:33 +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#97
No description provided.