# BAT-016 Implementation - Status: implemented - Batch: BAT-016 ## Plan Summary - 순서: REQ-036(마이그레이션 + ensure_schema) → REQ-037(repository/도메인/응답/회계) → REQ-038(deprecated) - 각 REQ 후 부분 회귀, batch 마지막 통합 회귀를 수행했다. ## Changed Files - `migrations/versions/20260605_0025_ledger_consolidation.py` - `app/repositories/postgres.py` - `app/repositories/portfolio_repository.py` - `app/domain/models.py` - `app/domain/services.py` call-site compatible model usage retained through `LedgerEntry.action` compatibility - `app/schemas/v1.py` - `app/api/v1_portfolios.py` - `app/api/portfolios.py` - `tests/test_v1_portfolios_ledger.py` - `tests/test_v1.py` - `tests/test_daemon_assignment.py` - `tests/test_auth.py` ## Execution Log 1. `portfolio_ledger` schema was consolidated to carry trade-write identifiers/state directly: `ledger_entry_id`, `order_id`, `execution_id`, `side`, `executed_at`, `cash_balance_after`, and `asset_quantity_after`. 2. Legacy `ledger_trades` references were removed from application code; `ensure_schema()` now migrates old `action` data into `side`, drops `action`, and drops `ledger_trades` when present. 3. `LedgerEntry` became the canonical domain object for recent trades and authoritative ledger-trade writes. 4. `POST /v1/portfolios/{portfolio_id}/ledger/trades` now writes to `portfolio_ledger`, supports idempotent lookup by broker identifiers, computes cash/security balances, and returns accounting state. 5. Legacy `/portfolios/{portfolio_id}/buy` and `/portfolios/{portfolio_id}/sell` routes were marked `deprecated=True` and emit `Deprecation: true` on legacy responses/errors. 6. Regression tests were updated to assert the consolidated model and deprecation header behavior. ## Validation - Targeted regression: - `.venv/bin/python -m pytest -q tests/test_domain_services.py tests/test_v1_portfolios_ledger.py tests/test_daemon_assignment.py tests/test_v1.py` - Result: `47 passed in 3.66s` - Full suite: - `.venv/bin/python -m pytest -q` - Result: `373 passed, 3 warnings in 14.78s` ## Remaining Risks - Timescale hypertable constraints can require time-column-aware unique/primary indexes. The runtime consolidation avoids unsupported primary/unique constraints on `portfolio_ledger`; idempotency is enforced in repository logic by looking up `(portfolio_id, order_id, execution_id)` before insert.