BAT-016's initial implementation passed only against mocked repositories and broke on a real database. Two defects fixed: 1. insert_ledger_trade used `ON CONFLICT (portfolio_id, order_id, execution_id) WHERE order_id IS NOT NULL` but portfolio_ledger is a TimescaleDB hypertable, which cannot have that partial unique index (must include the partitioning column recorded_at). The statement errored against Postgres. Replaced with application-level idempotency: SELECT-before-insert inside the existing `SELECT ... FOR UPDATE` portfolio row lock, which serializes concurrent same-portfolio writes (race-safe). Duplicate returns current authoritative portfolio state (dcy-006 OQ-4 b). 2. `with self._connect() as conn:` closes the shared psycopg3 connection on exit, leaving the reused repository connection unusable. Switched to `with conn.transaction():` (commits without closing). Added tests/test_ledger_consolidation_integration.py — real-Postgres integration tests (new / duplicate / negative-balance) that close the mock-only verification gap. Full suite: 376 passed. SDLC: REQ-036/037 CHG-20260605-03 reconcile OQ-7 (ii) (DB partial unique → application-level idempotency) since the hypertable makes the DB constraint infeasible. REQ-036/037/038 → Implemented; BAT-016 → release-candidate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5.1 KiB
5.1 KiB
REQ-038: 레거시 buy/sell endpoint deprecated 표기
- Status: Implemented
- Type: Interface
- Priority: Low
- Owner: Justin Ko
Intent
- 신 path(
POST /v1/portfolios/{id}/ledger/trades)가 portfolio 회계의 단일 권위 endpoint로 단일화됨에 따라(REQ-037), 레거시 거래 endpointPOST /portfolios/{id}/buy·/sell을 deprecated로 표기해 클라이언트에 폐지 예정을 통지한다(dcy-006 OQ-5). - 본 REQ는 표기만 다루며 실제 endpoint 제거 + CLI 호출자 전환은 후속 정리 batch/Discovery에서 처리한다.
Requirement
POST /portfolios/{id}/buy,POST /portfolios/{id}/sell라우트(app/api/portfolios.py:158,176)에 deprecated 표기를 추가한다:- FastAPI route에
deprecated=True를 지정해 OpenAPI 문서//docs에 deprecated로 노출. - 응답 헤더
Deprecation: true추가(가능하면Sunset또는 안내 link 헤더 동반은 선택).
- FastAPI route에
- endpoint 동작 자체는 변경하지 않는다(회계 거부 정책 + portfolio_ledger 기록 유지). REQ-036 portfolio_ledger 스키마 변경 하에서도 레거시 흐름이 정상 동작하는지 회귀로 확인한다(레거시 write는 order_id/execution_id NULL append-only).
- CLI(
pfhub portfolio buy/sell) 동작은 변경하지 않는다(호출자 전환은 후속).
Acceptance Criteria
- Given
/docs(OpenAPI), WhenPOST /portfolios/{id}/buy·/sell스펙 확인, Then deprecated=true로 표시된다. - Given
POST /portfolios/{id}/buy정상 호출, When 응답 확인, Then HTTP 200(기존 동작 보존) + 응답 헤더에Deprecation: true포함. - Given REQ-036 portfolio_ledger 신 스키마 적용 후, When 레거시 buy/sell 호출, Then portfolio_ledger에 order_id/execution_id NULL + side 매핑된 row가 정상 append되고 회계 거부 정책(잔고 부족 시 거부)이 유지된다.
- Given codebase grep
grep -n "deprecated=True" app/api/portfolios.py, When 본 REQ 구현 후, Then buy/sell 라우트에 매치된다.
Impacted Area
- Docs:
docs/interface-contract.md—POST /portfolios/{id}/buy·/selldeprecated 표기 + 신 path로의 이전 안내
- Modules:
app/api/portfolios.py:158,176— 라우트deprecated=True+ 응답 헤더Deprecation: true
- Tests:
- 갱신/신규
tests/test_portfolios.py또는 해당 — AC-1~3 검증(deprecated 표기 + 동작 보존 + 레거시 append)
- 갱신/신규
Notes
- 본 REQ는 dcy-006 FR-8 산출물.
- 실제 endpoint 제거는 본 REQ 범위 밖(dcy-006 Out of Scope). 후속 정리 batch 또는 별도 Discovery.
- REQ-036(portfolio_ledger 스키마 변경) 선행 — 레거시 흐름이 신 스키마에서 동작 보존되는지 AC-3로 확인.
- 별도 REL(REL-003 등)로 분리 배포(dcy-006 A-4).
- Source: dcy-006 FR-8, OQ-5.
Change Log
CHG-20260605-03
- Date: 2026-06-05
- Author: Justin Ko
Change Summary
- Status: Approved → Implemented
Intent
- BAT-016 confirm-batch-verification 완료. 레거시 buy/sell
deprecated=True+Deprecation: true헤더 구현, 동작 보존. AC-1~4 검증(tests/test_auth.py::test_legacy_buy_sell_routes_emit_deprecation_header포함). 전체 376 passed.
Acceptance Criteria Delta
- No change
Impacted Area Delta
- No change
Delivery Trace Delta
- Batches:
- BAT-016 (release-candidate)
- Releases:
- REL-003 (예정)
Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: implemented
- Follow-up Action: 실제 endpoint 제거는 후속 정리 트랙
CHG-20260605-02
- Date: 2026-06-05
- Author: Justin Ko
Change Summary
- Status: Proposed → Approved
Intent
- 승인 게이트 통과: 필수 필드 모두 충족, AC-1~4 구체성(OpenAPI deprecated + 헤더 + 레거시 append 보존) 확인 완료, blocker 없음.
Acceptance Criteria Delta
- No change
Impacted Area Delta
- No change
Delivery Trace Delta
- Batches: none (미정)
- Releases: none (미정 — REL-003 등 분리 예정)
Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: promote-to-approved
- Follow-up Action: batch 계획 편입; 실제 endpoint 제거는 후속 트랙
CHG-20260605-01
- Date: 2026-06-05
- Author: Justin Ko
Change Summary
- 최초 생성 — dcy-006 confirm-discovery 후 draft-req 실행. dcy-006 FR-8 산출물.
Intent
- 레거시 buy/sell endpoint deprecated 표기로 신 path 단일화 통지.
Acceptance Criteria Delta
- Added:
- AC-1~4 최초 작성
Impacted Area Delta
- Docs: docs/interface-contract.md — 최초 지정
- Modules: app/api/portfolios.py — 최초 지정
- Tests: tests/test_portfolios.py — 최초 지정
Delivery Trace Delta
- Batches: none (미정)
- Releases: none (미정 — REL-003 등 분리 예정)
Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 후 batch 계획 편입; 실제 endpoint 제거는 후속 트랙
Validation Plan
- pytest로 AC-1~4 검증(OpenAPI deprecated + 헤더 + 레거시 append 보존)