docs(examples): Alembic migration scaffold for v3 reference seller#390
docs(examples): Alembic migration scaffold for v3 reference seller#390
Conversation
Refs #382. Adds production migration tooling while keeping create_all as the default fast-iteration boot path (per DX review). https://claude.ai/code/session_01SnEYzkwXDnJEFpj7zNVSY6
- env.py: narrow _db_url to str via os.environ[key] (no mypy Any) - migrate.py: redact DB password before printing URL - test_migrations.py: drop psycopg2 assumption; use sqlalchemy async engine for all schema inspection (asyncpg already installed) - test_migrations.py: ensure downgrade test starts from head state https://claude.ai/code/session_01SnEYzkwXDnJEFpj7zNVSY6
|
Heads-up before merge: Issue #421 (filed by same author after PR #408 landed) flags a schema gap in this PR's migration coverage. PR #408 (merged ~30 min ago) added three items that aren't in this PR's
If this PR merges with the initial migration as-is, a Suggested fold: Update This is a triage suggestion, not a blocker from the bot — CODEOWNERS and human review govern merge. Raised by Claude Code triage for issue #421. Session: https://claude.ai/code/session_015VqV8vGd49wgLG3HPGch3F Generated by Claude Code |
PR #408 merged three schema additions that were not covered by the 0001 initial migration: `media_buys.invoice_recipient` (JSON, nullable), the `creatives` table (idempotency-keyed on tenant_id + creative_id), and the `performance_feedback` table (FK'd to media_buys.id). Without this migration, `alembic upgrade head` against a database created after #408 would produce drift that `alembic check` flags in CI and on every production deploy. Adds `0002_broadening_cycle.py` (revises 0001) covering all three additions, and updates the integration test to expect all eight tables. Refs #382 https://claude.ai/code/session_0121TgqHyzzjyZnQiGGmjrRu
|
Fixed in commit 6228736. Added
Downgrade reverses all three in FK-safe order (performance_feedback → creatives → drop column). Also updated Generated by Claude Code Generated by Claude Code |
|
Noted — Generated by Claude Code Generated by Claude Code |
|
Thanks for the review, @bokelley — noted that Generated by Claude Code Generated by Claude Code |
Refs #382
Adds a complete Alembic migration scaffold to
examples/v3_reference_seller/so production adopters have a real schema-evolution story instead ofcreate_all.What changed
New files:
alembic.ini— Alembic config;DATABASE_URLread from env (never hardcoded)alembic/env.py— async engine setup (asyncpg); explicitly imports bothsrc.modelsandsrc.auditso all 5 tables appear in autogeneratealembic/script.py.mako— standard migration templatealembic/versions/0001_initial_schema.py— hand-written initial migration covering all 5 tables (tenants, buyer_agents, accounts, media_buys, audit_events) with indexes, FKs, and CHECK constraintsmigrate.py— standalone script that runsalembic upgrade head; redacts DB password before loggingtests/test_migrations.py— two@pytest.mark.integrationtests (skipped withoutDATABASE_URL); use SQLAlchemy async engine for all inspection (no psycopg2 dependency)Modified:
README.md— removed Alembic from "What's NOT wired" bullet; added## Migrationssection with install, apply, generate, rollback, and test-run instructionsDeliberate deviation from acceptance criterion #3
The issue asks the boot path to call
alembic upgrade headinstead ofcreate_all. DX review flagged this as a blocker: making Alembic a hard runtime dependency at boot produces opaque errors for first-time adopters and silently breaks any checkout without Alembic installed (the example has norequirements.txt). Instead:src/app.pyboot path is unchanged (create_all— fast iteration default)migrate.pyprovides the production migration path as an explicit step## Migrationssection explains the two-path model clearly, with thecreate_allwarning prominentWhat was tested
pytest examples/v3_reference_seller/tests/test_smoke.py -v— 7/7 passedruff check examples/v3_reference_seller/— cleanmypynot run (no SDK type changes; examples/ is not in mypy scope)test_migrations.py) require a live Postgres instance; skipped in this environmentPre-PR review
integrationmarker pre-declared in pyproject.toml (no fork friction)Nits noted (not fixed — left for reviewer discretion)
revision: str = "0001"is a non-UUID revision ID; future autogenerate IDs will be UUID-style (visual mismatch inalembic history— not a correctness issue)scope="module"ondb_urlfixture;scope="session"would be marginally cleaner if tests expandecho "alembic" >> requirements.txtinstall example is a one-liner anti-pattern; could be rephrasedSession: https://claude.ai/code/session_01SnEYzkwXDnJEFpj7zNVSY6
Generated by Claude Code