docs: add downstream consumer check to migration workflow #199
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!199
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "193-downstream-consumer-check-migration-workflow"
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 documentation to prevent silent breakage of downstream services when basketball-api migrations alter shared tables. Migration 019 dropped
players.team_idwithout updating westside-contracts, causing 2+ days of HTTP 500s. This PR adds a lightweight checklist and shared table registry so that class of failure never recurs.Changes
docs/migrations.md-- Documents downstream consumers (westside-contracts), shared tables with specific columns used, a pre-merge migration checklist, the two-phase column drop approach, and the incident that motivated thisalembic/README.md-- Quick reference for alembic commands, file naming convention, environment setup, and a prominent pointer todocs/migrations.mdfor the downstream consumer checkTest Plan
docs/migrations.mdlists all four shared tables (players, teams, parents, player_teams)alembic/README.mdlinks todocs/migrations.mdReview Checklist
Related Notes
forgejo_admin/westside-contracts #25(migration 019 broke contract pages for 2+ days)QA Review
Scope check: 2 new files, 94 additions, 0 deletions. Documentation only -- no code, no migrations. Clean scope matches issue #193.
Acceptance Criteria (from #193)
docs/migrations.mdalembic/README.mdlinks todocs/migrations.mdwith bold calloutFile Review
docs/migrations.mdrg(correct for this repo's conventions)alembic/README.mdenv.pybehavior (readsBASKETBALL_DATABASE_URL, not alembic.ini DSN)Nits
None.
VERDICT: APPROVE
PR #199 Review
DOMAIN REVIEW
Tech stack: Documentation only (Markdown). Cross-references Python/FastAPI/SQLAlchemy models in basketball-api and raw SQL in westside-contracts (SvelteKit/TypeScript). No code changes.
Accuracy verification: I cross-referenced the documented shared table columns against:
/src/basketball_api/models.pywestside-contracts/src/routes/contract/[token]/+page.server.tsandsign/+server.tsPlayerinterface inwestside-contracts/src/lib/types.tsFindings:
Missing columns in
playersshared table list. The+page.server.tsusesSELECT p.*and then explicitly accessesdate_of_birth(line 33) andcustom_notes(line 41) in the returned object. Both are omitted from the shared column list indocs/migrations.md. If either column were dropped by a migration, the contract page would break -- the exact class of failure this doc exists to prevent.Missing table:
outbox. Thesign/+server.ts(lines 104-108) writes directly to theoutboxtable with an INSERT. If basketball-api altered theoutboxschema (e.g., renamedevent_type, changedtenant_idsemantics), contract signing would break. Theoutboxtable should be listed in the Downstream Consumers / Shared Tables section.The
SELECT p.*pattern. The+page.server.tsquery usesSELECT p.*, meaning westside-contracts implicitly depends on ALL columns of theplayerstable, not just the ones accessed in code. This is worth a note in the doc -- any column drop onplayerswill change the query result shape, and future code changes in westside-contracts could reference any column without updating this doc. Consider noting theSELECT *dependency pattern.BLOCKERS
Missing columns (accuracy gap). The whole point of this document is to be the authoritative registry of downstream column dependencies. Omitting
date_of_birthandcustom_notesundermines that purpose. These must be added to theplayersrow in the Shared Tables section.Missing
outboxtable. westside-contracts writes to theoutboxtable during contract signing. This is a shared table dependency that must be documented. Columns used:tenant_id,event_type,payload,status,created_at.NITS
The grep example in the migration checklist uses
~/westside-contracts/but the repo is at~/westside-contracts(or wherever the developer clones it). Not a real issue, but the path is a best-guess. Consider making it generic:rg "column_name" <path-to-consumer-repo>.teams.division,teams.age_group, andparents.phoneare listed as "columns used downstream" but are not referenced in any westside-contracts SQL query. This is conservative (safe direction), but if the intent is an accurate registry, they should be removed or the doc should note that conservative inclusion is intentional.The
alembic/README.mdreferencesBASKETBALL_DATABASE_URLwhich is confirmed correct viaalembic/env.pyline 27. Good.The alembic
env.pyimports do not include newer models (InterestLead,Order,Product,PasswordResetToken). This is pre-existing and out of scope for this PR, but worth tracking as a separate issue since Alembic autogenerate will miss those tables.SOP COMPLIANCE
193-downstream-consumer-check-migration-workflowreferences #193alembic/README.mdanddocs/migrations.mdaddedPROCESS OBSERVATIONS
This PR directly addresses a real incident (migration 019 causing 2+ days of HTTP 500s in westside-contracts). The documentation is the right approach -- process guardrails to prevent silent cross-service breakage. However, the doc must be accurate to serve its purpose. The missing columns and missing
outboxtable are exactly the kind of gaps that would let the next incident slip through.The
SELECT p.*pattern in westside-contracts is an ongoing risk. Even with perfect documentation, anyplayersschema change is implicitly breaking. A future follow-up could pin the SELECT to explicit columns in westside-contracts to reduce the blast radius.VERDICT: NOT APPROVED
Two accuracy gaps must be fixed before merge: (1) add
date_of_birthandcustom_notesto theplayersshared column list, (2) add theoutboxtable to the Shared Tables section. The document's value depends on completeness.PR #199 Review (Re-review)
DOMAIN REVIEW
Tech stack: Documentation-only PR (Markdown). Two new files:
docs/migrations.mdandalembic/README.md. No code changes, no migrations, no test changes. Cross-references verified against the basketball-api SQLAlchemy models (src/basketball_api/models.py) and the westside-contracts downstream consumer (~/westside-contracts/src/).Previous blocker verification:
Missing
date_of_birthandcustom_notesin shared tables registry -- RESOLVED. Both columns now appear in theplayersrow of the Shared Tables section atdocs/migrations.mdline 23. Cross-referenced against thePlayermodel (line 183:date_of_birth, line 214:custom_notes) and westside-contracts usage (+page.server.tslines 33, 41).Missing
outboxtable in shared tables registry -- RESOLVED. Theoutboxtable now appears in both the Downstream Consumers table (line 12) and the Shared Tables section (line 26) with columnstenant_id,event_type,payload,status,created_at. Cross-referenced against theOutboxmodel (lines 381-392) and the westside-contracts INSERT atsign/+server.tslines 104-108.Accuracy audit of column lists:
Verified by grepping westside-contracts source and reading the TypeScript
Playerinterface (src/lib/types.ts):playerscolumn list: Accurate. Includes all columns referenced by the code plus additional columns returned by theSELECT p.*query in+page.server.ts. The over-inclusive approach (jersey_option,jersey_size,jersey_number,is_public,tenant_idare listed but not explicitly accessed by downstream code) is the safer choice given thatSELECT p.*returns the full row.teamscolumn list: Listsdivisionandage_groupbut westside-contracts only queriesidandname. Conservative/safe.parentscolumn list: Listsphonebut westside-contracts only queriesid,name,email. Conservative/safe.player_teamscolumn list: Exact match --player_idandteam_idare both used in JOINs.outboxcolumn list: Exact match -- all five columns appear in the INSERT statement.BLOCKERS
None. Both previously identified blockers are resolved.
NITS
Over-inclusive column lists for
teamsandparents: The doc liststeams.division,teams.age_group, andparents.phoneas "Columns used downstream (westside-contracts)" but these are not queried by westside-contracts today. TheSELECT p.*rationale applies toplayersbut not toteamsorparents(those use explicit column selects). Consider trimming to actual usage, or add a note that the list includes columns likely to be used as the consumer grows. Non-blocking since over-inclusion is the safe direction.Pre-existing observation (out of scope): westside-contracts
src/lib/types.tsstill definesteam_id: number | nullon thePlayerinterface, but theplayerstable no longer has that column (dropped by migration 019). The+page.server.tsusesSELECT p.*so this field would beundefinedon results rather thannull. This is a westside-contracts issue, not in this PR's scope -- but it is exactly the kind of drift this documentation is designed to prevent.SOP COMPLIANCE
193-downstream-consumer-check-migration-workflowreferences #193forgejo_admin/westside-contracts #25docs: add downstream consumer check to migration workflow)PROCESS OBSERVATIONS
This PR directly addresses a 2+ day production incident where a schema migration broke a downstream consumer silently. The documentation establishes a lightweight but effective guard rail: a shared table registry and pre-merge checklist. The incident reference (migration 019 / westside-contracts #25) provides traceability. This is a high-value, low-risk change that reduces Change Failure Rate by making cross-service dependencies visible at review time.
VERDICT: APPROVED