# BAT-025 Design ## D-1. Revision graph and parent 구현 시작 직전 `uv run alembic heads` 및 `uv run alembic history`로 유효 head를 재확인한다. 신규 revision은 그 실제 head 하나를 `down_revision`으로 사용하며, 문서/코드에 20260628_0027을 선결 가정으로 고정하지 않는다. ## D-2. Migration idempotency 신규 revision은 inspector/information_schema 기반으로 table/column 존재를 확인한다. - `portfolio_ledger`가 정상적으로 존재하는 일반 경로에서는 네 컬럼을 추가한다. - runtime `ensure_schema()`가 이미 컬럼을 생성한 경로에서는 컬럼 재생성 없이 nullable/default를 검증·보정한다. - `source`는 upgrade 전에 NULL을 `'broker'`로 backfill하고 이후 `NOT NULL DEFAULT 'broker'`를 보장한다. - 기존 행은 삭제·재작성하지 않으며 upgrade 전후 row count와 business field를 비교한다. - down migration은 운영 forward-only 정책과 충돌하지 않도록 구현 범위를 명시하고, 운영 runbook은 column deletion을 rollback으로 제시하지 않는다. ## D-3. Runtime boundary `app/repositories/postgres.py:ensure_schema()`는 bootstrap safety 경로로 유지한다. Alembic revision은 persistent schema history의 source of truth로 둔다. migration 성공만으로 version table을 임의 stamp하지 않으며, schema와 Alembic current가 함께 일치하는지 검증한다. ## D-4. Test matrix | 시작 상태 | 검증 | | --- | --- | | fresh Alembic schema | upgrade, 네 컬럼 타입/nullable/default, current/head | | 기존 ledger rows | row count/business data 보존, source broker backfill | | runtime-precreated columns | 중복 DDL 부재, constraints/default 정합, current/head | | broker write | 기존 `/ledger/trades` 회귀 없음 | | manual API | source/manual metadata 및 REQ-056 핵심 regression | | runbook | preflight 조건, 실패 중단, forward-only recovery 문서 정합 | ## D-5. Operational gate 이번 batch는 local/non-production verification만 수행한다. 운영 DB backup/upgrade, service restart, 신규 API activation, deploy/push/merge는 M5 Release의 별도 결재 없이는 실행하지 않는다. runbook은 실행 가능한 명령 템플릿과 중단 조건을 제공하되 실제 운영 결과를 가장하지 않는다. ## Design decisions / open findings - 실제 revision ID는 구현 preflight 결과로 결정한다. - 실제 DB driver availability에 따라 migration integration test harness는 repository 표준 fixture 또는 isolated PostgreSQL 경로를 사용하되, 사용하지 못한 환경은 QC evidence에 명시한다. - stamp 필요성은 schema inspection과 version table evidence 이후에만 판단하며 자동 조치하지 않는다.