feat(db): schema 0002 master data tables #58
No reviewers
Labels
No labels
in-progress
in-review
ready-for-agent
seam-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
patrick/Polaris!58
Loading…
Reference in a new issue
No description provided.
Delete branch "feature/db-schema-master-data"
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?
PH1.1 — issue #9
Migration
0002and matching typed SQLAlchemy mapped classes for every master-data table indocs/08-data-model.md:vehicle,ingest_record,site,presence_block,presence_window, catalogue (service_type,skill,service_type_skill,reason_code,site_suitability),job,person(withpreferred_username),crew,crew_member,crew_skill,shift. Notoolingtable/joins, perdocs/adr/0001-remove-tooling-catalogue.md.Branch history note: started from
origin/develop(at the timemainhad nobackend/yet — onlydevelophad #4/#51 API-skeleton merged). While this was in flight,developwas merged intomainand retired in favour of a single-trunk workflow (CLAUDE.md's Git section, commit1a1dfc2/81e2f4c). Rebased this branch onto the newmainbefore opening this PR, which now targetsmainper the updated workflow.What's in here
job/shift/site_suitabilitygetcreated_at/updated_at/created_by/updated_byonly (nodeleted_at) — their lifecycle is a status transition, matching the doc's "audit columns" phrasing for those three.geography(POINT|POLYGON, 4326)via a smallUserDefinedType(db/models/_types.py) instead of addinggeoalchemy2topyproject.toml, which is outside this ticket's owned paths..valueviadb/models/_enum.py'snative_enum()helper —sqlalchemy.Enum(SomePyEnum)defaults to the member.name, not.value, which silently disagrees with the hand-written lowercase labels in the Alembic migration otherwise (see the second commit below — this exact bug is why it needed fixing).Auditable; composite-PK tables overrideaudit_entity_idwith a crc32 of their key (same approach asSetting).docs/08-data-model.mdfor these aggregates.Also in here: a seam fix (
db/audit.py)Building this surfaced a real bug in
polaris/db/audit.py(outside this ticket's owned paths,backend/src/polaris/db/models/**/backend/alembic/versions/**only):Auditable'sbefore_flushhook and its defaultaudit_entity_idnever actually work for a server-generated identity PK — exactly the PK conventiondocs/08-data-model.mdmandates for every table in this migration. It was latent before becauseSetting(0001) has a client-supplied string PK and bypasses both code paths, andtaskopts out ofAuditableentirely.Fixed directly here (first commit) rather than opening a separate PR and blocking on it, since it would otherwise ship PH1.1 broken; full writeup and rationale in the commit message and in seam-request issue #57 (opened for traceability, not as a blocker — already resolved). Existing
tests/integration/db/test_audit_hook.pycases pass unchanged.Tests
backend/tests/conftest.pyandtests/integration/db/test_migrations.pyswitch the testcontainers Postgres image topostgis/postgis:17-3.4—conftest.py's own header comment anticipated this as the first ticket to introduce geography columns.test_migrations.pygains a dedicated0002upgrade-head /downgrade -1/upgrade +1round-trip test (the ticket's own acceptance criterion) alongside the existing full-chain upgrade/downgrade-base test.tests/integration/db/test_master_data_models.pyexercises the whole PH1.1 aggregate end to end: FK wiring across all sixteen tables, geography WKT round-trip, enums stored lower-case, the job priority check constraint, the shift partial-unique-excluding-cancelled index, and soft-delete (row survivesdeleted_atbeing set).Verified
mypy --strictclean (47 source files).ruff check/ruff format --checkclean.alembic upgrade head/downgrade -1/upgrade +1all pass against a real Postgres+PostGIS (testcontainers).All four acceptance-criteria checkboxes ticked on #9.
Closes #9
🤖 Generated with Claude Code
https://claude.ai/code/session_01LoNrSy7Reyp7evkfcdHeLX