feat: add contract token and signature fields to Player #153
No reviewers
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
forgejo_admin/basketball-api!153
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "152-contract-token-signature-fields"
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?
Summary
Adds three nullable columns to the Player model for the E-SIGN contract signing workflow: a secure token for contract links, a MinIO URL for drawn signature PNGs, and a version string for audit trail.
Changes
src/basketball_api/models.py— Addedcontract_token(String 100, unique),contract_signature_url(String 500), andcontract_version(String 100) to the Player model, grouped with the existingcontract_signed_*fieldsalembic/versions/017_add_contract_token_and_signature_fields.py— New migration adding the three columns with a named unique constraint oncontract_tokenTest Plan
ruff checkandruff formatcleanReview Checklist
Related
Review: No findings.
registration_token,invite_token)PR #153 Review
DOMAIN REVIEW
Tech stack: Python / FastAPI / SQLAlchemy / Alembic (basketball-api backend).
This PR adds four nullable columns to the
Playermodel and a corresponding Alembic migration (017). It is a schema-only change -- no new routes, no new endpoints, no behavioral changes. All four columns are nullable so existing data is unaffected.Model changes (
src/basketball_api/models.py):contract_token-- String(100), unique, nullable. Correctly placed after existingcontract_signed_*fields.contract_signature_url-- String(500), nullable. Appropriate length for MinIO URLs.contract_version-- String(100), nullable.monthly_fee-- Integer, nullable. Per-player fee storage for tiered billing.Migration (
alembic/versions/017_add_contract_token_and_signature_fields.py):016->017.uq_players_contract_token-- good practice, enables clean rollback.SQLAlchemy observations:
Integerimport already existed at module level -- no new import needed.unique=Trueon the model'smapped_columnis consistent with the migration'screate_unique_constraint.BLOCKERS
1. No test coverage for new columns (BLOCKER)
Zero tests were added or modified for the four new columns. The existing
tests/test_models.py(TestPlayerNewFields) does not exercisecontract_token,contract_signature_url,contract_version, ormonthly_fee. The existingtests/test_contract.pytests do not reference any of the new fields either. A grep for these field names across the entire test directory returns zero matches.Per BLOCKER criteria: "New functionality with zero test coverage." While these are nullable columns with no route changes yet, the
contract_tokencolumn has a unique constraint -- this is behavioral, not just schema. At minimum, tests should verify:contract_tokenis enforced (duplicate insertion raises IntegrityError).2. Undocumented scope:
monthly_feecolumn (BLOCKER -- scope creep)Issue #152 title: "Add contract_token and contract_signature_url columns to Player model."
PR title: "feat: add contract token and signature fields to Player."
PR Summary: "Adds three nullable columns... a secure token for contract links, a MinIO URL for drawn signature PNGs, and a version string for audit trail."
The
monthly_feecolumn (Integer) is not mentioned in the issue title, PR title, or PR summary, yet it appears in both the migration and the model. The migration docstring does mention it, creating an inconsistency with the PR description. This is either scope creep (belongs in a separate issue per SOP) or an omission from the PR body. Either way:monthly_feeis needed for Phase 14 billing tiers, it should be documented in the PR body and issue.feedback_never_edit_without_ticket.md.NITS
PR Summary undercounts columns -- Summary says "three nullable columns" but four are added. The
monthly_feecolumn is missing from the narrative.Migration filename vs content mismatch -- File is named
017_add_contract_token_and_signature_fields.pybut also addsmonthly_fee. Consider a more inclusive name ifmonthly_feestays in this migration.contract_signature_urllength -- String(500) is generous. If this always points to a MinIO object path (e.g.,signatures/{player_id}.png), a shorter length might be more appropriate. Non-blocking -- 500 provides headroom.No index on
contract_token-- The unique constraint implicitly creates an index in PostgreSQL, so this is fine. Just noting for clarity.SOP COMPLIANCE
152-contract-token-signature-fieldsmatches issue #152)plan-wkq. The work maps to Phase 14 (Billing Tiers & Contracts).monthly_feeis not documented in the issue or PR body (scope creep concern)PROCESS OBSERVATIONS
contract_tokenis testable behavior that should be verified before this column is consumed by routes in a later PR.VERDICT: NOT APPROVED
Two blockers must be addressed:
contract_token, verify null defaults.monthly_feescope -- either add it to the issue #152 description and PR body with justification, or split it to a separate issue. The PR body must accurately describe what it ships.PR #153 Review
Re-review after fixes addressing previous blockers.
DOMAIN REVIEW
Tech stack: Python / FastAPI / SQLAlchemy / Alembic
Model changes (
src/basketball_api/models.py):Player:contract_token(String 100, unique),contract_signature_url(String 500),contract_version(String 100),monthly_fee(Integer). All nullable, all grouped logically with the existingcontract_signed_*fields. Type hints useMapped[... | None]correctly.Integerimport verified present.Migration (
alembic/versions/017_add_contract_token_and_signature_fields.py):down_revision = "016"chains from016_add_jersey_number_to_player.py.uq_players_contract_token-- correct ordering.type_="unique"-- clean rollback.Test coverage (
tests/test_contract.py):TestNewContractColumnscovering all four new columns:contract_token: default None, set value, unique constraint violation (IntegrityError + rollback).contract_signature_url: set value and round-trip.contract_version: set value and round-trip.monthly_fee: default None, set value, tiered pricing (multiple players with different fees).db.expire_all()before re-query -- proper ORM cache bypass.IntegrityErrorand rolls back the session.Pydantic schemas: The existing
ContractStatusResponse,AdminPlayerItem, andAccountPlayerResponseschemas do NOT include the new columns. This is acceptable -- the PR description explicitly states "No route changes -- columns are nullable so no existing behavior affected." The new columns are data-layer preparation for the upcoming E-SIGN contract signing workflow; route exposure will come in a subsequent PR.BLOCKERS
None.
Previous blockers resolved:
NITS
The PR body
## Relatedsection says "Closes #152" but does not reference the plan slugplan-wkq. SOP asks for plan slug reference when work is plan-driven.contract_signature_urlis typed asString(500). If this stores MinIO presigned URLs, those can exceed 500 characters depending on query parameters. If it stores only the object path (e.g.,westside/signatures/abc.png), 500 is generous and fine. Worth confirming the intended content before the route that writes this column is built.The test file imports
IntegrityErrorinline inside the test method (from sqlalchemy.exc import IntegrityError). Consider moving to the module-level imports for consistency with the rest of the file, though this is purely stylistic.SOP COMPLIANCE
152-contract-token-signature-fieldsmatches #152)plan-wkqPROCESS OBSERVATIONS
monthly_feecolumn was originally flagged as scope creep. It has since been documented as intentional scope in the issue, which is the correct process. Future PRs in the plan should expose it through appropriate endpoints.VERDICT: APPROVED