feat: consolidate ledger trade writes into portfolio_ledger
- add ledger consolidation migration and remove ledger_trades usage - return portfolio state after v1 ledger trade writes - deprecate legacy buy/sell endpoints with deprecation headers - add BAT-016, DCY-006, and REQ-036~038 documentation - update repository models and tests for unified ledger entries
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
# REQ-037: 신 path 회계 책임 단일화 + 응답에 portfolio 상태 포함
|
||||
|
||||
- Status: Approved
|
||||
- Type: Interface
|
||||
- Priority: High
|
||||
- Owner: Justin Ko
|
||||
|
||||
## Intent
|
||||
- `POST /v1/portfolios/{portfolio_id}/ledger/trades`를 portfolio 회계의 단일 권위 endpoint로 단일화한다. ledger 기록 시 portfolio `cash_balance`/`asset_quantity`를 트랜잭션 갱신하고, 응답에 거래 반영 후 권위 상태를 포함해 trex-core daemon의 drift를 원천 차단한다(issue #8).
|
||||
- 현재 audit-only 흐름(`insert_ledger_trade`가 `ledger_trades` INSERT만 수행)을 portfolio_ledger 단일 원장 기록 + portfolio 갱신 + 응답 확장으로 재정의한다.
|
||||
|
||||
## Requirement
|
||||
- 신 path handler([app/api/v1_portfolios.py:514-588](../../app/api/v1_portfolios.py#L514-L588) `record_ledger_trade_v1`)가 다음을 단일 DB 트랜잭션으로 수행한다(dcy-006 FR-6):
|
||||
- portfolios row를 `SELECT ... FOR UPDATE`로 잠근다(FR-7, lost update 방지).
|
||||
- 회계 공식 적용: side="buy" → `cash_balance -= qty*price + fee + tax`, `asset_quantity += qty`; side="sell" → `cash_balance += qty*price - fee - tax`, `asset_quantity -= qty`.
|
||||
- **잔고/수량 부족 거부 검증을 적용하지 않는다 — 음수 `cash_balance`/`asset_quantity` 모두 허용**(dcy-006 OQ-3). 음수 검증을 제거한 회계 헬퍼를 ledger 흐름 전용으로 추출하거나 inline 구현(기존 `apply_buy`/`apply_sell`은 레거시 전용으로 보존, R-8).
|
||||
- `portfolio_ledger`에 INSERT(REQ-036 신 스키마 사용). broker 식별자 `order_id`/`execution_id`/`side`/`executed_at` + 갱신 후 잔고 snapshot(`cash_balance_after`, `asset_quantity_after`, `total_value_after`) 기록.
|
||||
- portfolios 테이블 UPDATE(`cash_balance`, `asset_quantity`, `last_trade_at`, `updated_at`).
|
||||
- duplicate 감지(dcy-006 FR-15): `ON CONFLICT (portfolio_id, order_id, execution_id) WHERE order_id IS NOT NULL DO NOTHING`로 전환(기존 `ON CONFLICT ON CONSTRAINT uq_ledger_trades_idempotency` 대체). PostgreSQL partial index inference 사용.
|
||||
- `status="new"`(신규 row): 거래 반영 후 권위 상태를 응답한다(FR-2).
|
||||
- `status="duplicate"`(재호출): ledger row 재생성 없이 duplicate 호출 시점의 portfolios 테이블 현재 권위 상태를 SELECT로 조회해 응답한다(FR-3, dcy-006 OQ-4 (b)).
|
||||
- `LedgerTradeResponse`([app/schemas/v1.py](../../app/schemas/v1.py))에 `cash_balance_after: float`, `asset_quantity_after: float` 두 필드를 응답 root에 flat으로 비파괴 추가한다(FR-1, dcy-006 OQ-2 (b)). 기존 응답 필드는 모두 보존.
|
||||
- 기존 인가(daemon 3단계: token daemon_id == portfolio.managed_by_daemon_id), idempotency, status 의미를 보존한다(FR-4).
|
||||
- 도메인 모델 통합(FR-13): `LedgerEntry`와 `LedgerTrade` dataclass를 `LedgerEntry` 단일로 통합. `LedgerTrade` 삭제. broker 필드(`ledger_entry_id`, `order_id`, `execution_id`, `side`, `executed_at`)를 `LedgerEntry`에 흡수.
|
||||
- repository 통합(FR-14): `insert_ledger_trade`를 portfolio_ledger insert + portfolios UPDATE 단일 트랜잭션 함수로 재정의(또는 통합). `_row_to_ledger_trade`는 `_row_to_ledger_entry`와 통합.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given service token + daemon 배정 active portfolio(cash=1,000,000, qty=0) + buy 10@80,000 fee 100, When `POST /v1/portfolios/{id}/ledger/trades`, Then HTTP 201 + `status="new"` + 응답 `cash_balance_after=199900`(1,000,000 - 800,000 - 100) + `asset_quantity_after=10`. DB portfolios도 동일 값으로 갱신.
|
||||
2. Given AC-1 직후 같은 (portfolio_id, order_id, execution_id)로 재호출, When 동일 payload, Then HTTP 200 + `status="duplicate"` + 응답 `cash_balance_after`/`asset_quantity_after`는 현재 portfolios 권위 값. portfolio_ledger row는 1건 유지(재생성 없음).
|
||||
3. Given sell로 보유 수량보다 큰 수량 또는 cash를 초과하는 buy, When 호출, Then **HTTP 201**(거부하지 않음) + 음수 `cash_balance_after` 또는 음수 `asset_quantity_after` 반환(음수 허용, OQ-3).
|
||||
4. Given 기존 응답 필드(ledger_entry_id, portfolio_id, order_id, execution_id, side, quantity, price, fee_amount, tax_amount, executed_at, recorded_at, status), When AC-1 응답 확인, Then 모두 보존되고 `cash_balance_after`/`asset_quantity_after`만 추가된다.
|
||||
5. Given service token `daemon_id IS NULL` 또는 daemon mismatch, When 호출, Then 기존 인가 동작(HTTP 403 fail-closed) 보존.
|
||||
6. Given codebase grep `grep -rn "ledger_trades\|insert_ledger_trade\|class LedgerTrade\b" app/`, When 본 REQ + REQ-036 구현 후, Then `ledger_trades` 테이블 INSERT 코드 및 `LedgerTrade` dataclass 참조가 0건(LedgerEntry 단일).
|
||||
7. Given 동시 ledger write 2건(같은 portfolio), When 트랜잭션 실행, Then `SELECT FOR UPDATE` row lock으로 lost update 없이 두 거래가 순차 반영된다(회귀 테스트).
|
||||
|
||||
## Impacted Area
|
||||
- Docs:
|
||||
- `docs/interface-contract.md` — `POST /v1/portfolios/{id}/ledger/trades` 회계 동작 + 응답 schema(`cash_balance_after`/`asset_quantity_after`) + status별 동작 명문화
|
||||
- `docs/runtime-flows.md` — ledger write flow에 회계 적용 + portfolio 갱신 + 트랜잭션 lock 단계 + portfolio_ledger 단일 원장 명문화
|
||||
- Modules:
|
||||
- `app/api/v1_portfolios.py:record_ledger_trade_v1` — 통합 함수 호출 + 응답 확장
|
||||
- `app/repositories/postgres.py` — `insert_ledger_trade` 재정의(portfolio_ledger insert + portfolios UPDATE 단일 트랜잭션 + FOR UPDATE + ON CONFLICT partial), `_row_to_ledger_*` 통합
|
||||
- `app/repositories/portfolio_repository.py` — interface 시그니처 갱신
|
||||
- `app/domain/models.py` — `LedgerEntry` 단일화, `LedgerTrade` 삭제
|
||||
- `app/domain/services.py` 또는 신규 — 음수 검증 제거한 ledger 전용 회계 헬퍼 추출
|
||||
- `app/schemas/v1.py` — `LedgerTradeResponse`에 `cash_balance_after`/`asset_quantity_after` 추가
|
||||
- Tests:
|
||||
- 갱신 `tests/test_v1_portfolios_ledger.py` — AC-1~7 (응답 신규 필드 + 회계 + duplicate + 음수 + 인가 보존 + 동시성)
|
||||
- 갱신 `tests/test_v1.py`, `tests/test_daemon_assignment.py` — LedgerEntry 통합 + 응답 schema 반영
|
||||
|
||||
## Notes
|
||||
- 본 REQ는 dcy-006 FR-1/2/3/4/6/7/13/14/15 산출물 + FR-5(interface-contract/runtime-flows) 일부 흡수.
|
||||
- REQ-036(마이그레이션) 선행 필요 — portfolio_ledger 신 스키마 위에서 동작.
|
||||
- 음수 허용은 신 path 한정. 레거시 buy/sell은 기존 거부 정책 유지(REQ-038 deprecated 대상).
|
||||
- 별도 REL(REL-003 등)로 분리 배포(dcy-006 A-4).
|
||||
- Source: dcy-006 FR-1/2/3/4/6/7/13/14/15, OQ-1~4/6/7.
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260605-02
|
||||
- Date: 2026-06-05
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
- Status: Proposed → Approved
|
||||
|
||||
#### Intent
|
||||
- 승인 게이트 통과: 필수 필드 모두 충족, AC-1~7 구체성(수치 회계 예시 + 음수 허용 + duplicate + 동시성) 확인 완료, 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 계획 편입; REQ-036 선행 의존성 확인
|
||||
|
||||
### CHG-20260605-01
|
||||
- Date: 2026-06-05
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
- 최초 생성 — dcy-006 confirm-discovery 후 draft-req 실행. dcy-006 회계 책임 단일화 + 응답 확장 산출물.
|
||||
|
||||
#### Intent
|
||||
- 신 path를 portfolio 회계 단일 권위 endpoint로 재정의하고 응답에 거래 후 권위 상태를 포함해 trex-core drift 차단.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~7 최초 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs: docs/interface-contract.md, docs/runtime-flows.md — 최초 지정
|
||||
- Modules: app/api/v1_portfolios.py, app/repositories/postgres.py, app/repositories/portfolio_repository.py, app/domain/models.py, app/domain/services.py, app/schemas/v1.py — 최초 지정
|
||||
- Tests: tests/test_v1_portfolios_ledger.py, tests/test_v1.py, tests/test_daemon_assignment.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 계획 편입; REQ-036 선행 의존성 확인
|
||||
|
||||
#### Validation Plan
|
||||
- pytest TestClient로 AC-1~7 검증; 동시성은 회귀 또는 staging concurrent test
|
||||
@@ -0,0 +1,98 @@
|
||||
# REQ-038: 레거시 buy/sell endpoint deprecated 표기
|
||||
|
||||
- Status: Approved
|
||||
- Type: Interface
|
||||
- Priority: Low
|
||||
- Owner: Justin Ko
|
||||
|
||||
## Intent
|
||||
- 신 path(`POST /v1/portfolios/{id}/ledger/trades`)가 portfolio 회계의 단일 권위 endpoint로 단일화됨에 따라(REQ-037), 레거시 거래 endpoint `POST /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](../../app/api/portfolios.py#L158))에 deprecated 표기를 추가한다:
|
||||
- FastAPI route에 `deprecated=True`를 지정해 OpenAPI 문서/`/docs`에 deprecated로 노출.
|
||||
- 응답 헤더 `Deprecation: true` 추가(가능하면 `Sunset` 또는 안내 link 헤더 동반은 선택).
|
||||
- endpoint 동작 자체는 변경하지 않는다(회계 거부 정책 + portfolio_ledger 기록 유지). REQ-036 portfolio_ledger 스키마 변경 하에서도 레거시 흐름이 정상 동작하는지 회귀로 확인한다(레거시 write는 order_id/execution_id NULL append-only).
|
||||
- CLI(`pfhub portfolio buy/sell`) 동작은 변경하지 않는다(호출자 전환은 후속).
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given `/docs`(OpenAPI), When `POST /portfolios/{id}/buy`·`/sell` 스펙 확인, Then deprecated=true로 표시된다.
|
||||
2. Given `POST /portfolios/{id}/buy` 정상 호출, When 응답 확인, Then HTTP 200(기존 동작 보존) + 응답 헤더에 `Deprecation: true` 포함.
|
||||
3. Given REQ-036 portfolio_ledger 신 스키마 적용 후, When 레거시 buy/sell 호출, Then portfolio_ledger에 order_id/execution_id NULL + side 매핑된 row가 정상 append되고 회계 거부 정책(잔고 부족 시 거부)이 유지된다.
|
||||
4. 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`·`/sell` deprecated 표기 + 신 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-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 보존)
|
||||
@@ -0,0 +1,112 @@
|
||||
# REQ-036: portfolio_ledger 회계 원장 통합 마이그레이션 (ledger_trades 흡수/DROP)
|
||||
|
||||
- Status: Approved
|
||||
- Type: Migration
|
||||
- Priority: High
|
||||
- Owner: Justin Ko
|
||||
|
||||
## Intent
|
||||
- 두 ledger 테이블(`portfolio_ledger` 회계 원장 + `ledger_trades` broker audit)이 공존하는 구조를 `portfolio_ledger` 단일 회계 원장으로 통합한다(dcy-006 OQ-6 (iv)).
|
||||
- `ledger_trades`의 broker idempotency/식별 필드를 `portfolio_ledger`에 흡수하고 `ledger_trades` 테이블을 삭제해, 신 path(`POST /v1/portfolios/{id}/ledger/trades`)가 단일 회계 원장에 기록할 수 있는 스키마 기반을 마련한다.
|
||||
|
||||
## Requirement
|
||||
- Alembic 신규 revision을 작성한다. (head는 dcy-005 `20260601_0024` 다음)
|
||||
- `portfolio_ledger`에 컬럼을 추가한다:
|
||||
- `ledger_entry_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY`
|
||||
- `order_id TEXT NULL`, `execution_id TEXT NULL` (dcy-006 OQ-7 (ii): NULL 허용)
|
||||
- `side TEXT NOT NULL`
|
||||
- `executed_at TIMESTAMPTZ NOT NULL`
|
||||
- partial UNIQUE index `(portfolio_id, order_id, execution_id) WHERE order_id IS NOT NULL`를 추가한다. broker write(신 path)만 idempotency를 적용하고 레거시/수동 write(order_id NULL)는 append-only 유지. (REQ-017 partial unique index 패턴 재사용)
|
||||
- 수치 컬럼 타입을 DOUBLE PRECISION → NUMERIC(20,8)로 변경한다: `price`, `quantity`, `fee_amount`, `tax_amount`, `cash_balance_after`, `asset_quantity_after`, `total_value_after`, `profit_buffer_after`.
|
||||
- 기존 `action` 컬럼을 제거하고 `side`로 통일한다. backfill 매핑: `action='BUY'` → `side='buy'`, `action='SELL'` → `side='sell'`. 그 외 자유형식 action 값의 처리(R-6)는 마이그레이션 본문에서 분포 확인 후 결정(개발 워크스페이스는 분포 단순).
|
||||
- 기존 데이터 backfill: `recorded_at` → `executed_at` 복사, `order_id`/`execution_id`는 NULL(synthetic 생성 불요).
|
||||
- 추가 인덱스 `idx_portfolio_ledger_portfolio_executed (portfolio_id, executed_at)` 신설. 기존 `idx_portfolio_ledger_portfolio_time (portfolio_id, recorded_at DESC)`은 유지.
|
||||
- `ledger_trades` 테이블을 DROP한다. (본 워크스페이스 미생성이라 `DROP TABLE IF EXISTS`로 안전 처리. prod 데이터 보존 필요 시 backfill은 release 단계 별도 검토.)
|
||||
- `app/repositories/postgres.py`의 `ensure_schema()` 내 `portfolio_ledger` 정의도 신 스키마와 동일하게 갱신한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
1. Given 신규 Alembic revision 적용 후, When `\d portfolio_ledger` 확인, Then `ledger_entry_id`(PK), `order_id`(NULL 허용), `execution_id`(NULL 허용), `side`(NOT NULL), `executed_at`(NOT NULL) 컬럼이 존재한다.
|
||||
2. Given AC-1 환경, When `information_schema`로 수치 컬럼 타입 확인, Then `price`/`quantity`/`fee_amount`/`tax_amount`/`cash_balance_after`/`asset_quantity_after`/`total_value_after`/`profit_buffer_after`가 모두 NUMERIC(20,8)이다.
|
||||
3. Given AC-1 환경, When partial UNIQUE index 확인, Then `(portfolio_id, order_id, execution_id) WHERE order_id IS NOT NULL` 조건의 unique index가 존재한다.
|
||||
4. Given AC-1 환경, When `action` 컬럼 존재 확인, Then `action` 컬럼은 존재하지 않고 `side` 컬럼으로 대체되어 있다.
|
||||
5. Given AC-1 환경, When `\d ledger_trades` 또는 테이블 목록 조회, Then `ledger_trades` 테이블이 존재하지 않는다.
|
||||
6. Given 기존 portfolio_ledger 데이터(있는 경우), When 마이그레이션 적용, Then `executed_at`은 `recorded_at` 값으로 채워지고 `order_id`/`execution_id`는 NULL이며 `side`는 기존 action에서 매핑된다.
|
||||
7. Given `ensure_schema()` 단독 실행, When portfolio_ledger 스키마 확인, Then 마이그레이션과 동일한 컬럼/제약/타입이 반영된다.
|
||||
|
||||
## Impacted Area
|
||||
- Docs:
|
||||
- `docs/data-model.md` — `portfolio_ledger` entity에 신규 컬럼(ledger_entry_id PK, order_id/execution_id NULL, side, executed_at) + 정밀도 NUMERIC(20,8) + partial UNIQUE index 명세 추가. `ledger_trades` entity 섹션 제거. 두 ledger 테이블 → 단일 원장 통합 명시.
|
||||
- Modules:
|
||||
- `migrations/versions/` — 신규 revision (예: `20260605_NNNN_portfolio_ledger_consolidation.py`). down_revision = `20260601_0024`.
|
||||
- `app/repositories/postgres.py:263-282` — `ensure_schema()` portfolio_ledger 정의 갱신
|
||||
- Tests:
|
||||
- 신규/갱신 마이그레이션 회귀 (alembic upgrade head 후 schema 검증)
|
||||
- 기존 `tests/test_v1_portfolios_ledger.py` 등 ledger 의존 테스트가 신 스키마와 정합하도록 갱신 (REQ-037과 연동)
|
||||
|
||||
## Notes
|
||||
- 본 REQ는 dcy-006 FR-9/FR-10/FR-11/FR-12 산출물 + FR-5(data-model.md) 일부 흡수.
|
||||
- REQ-037(신 path 회계 책임 + 응답)의 선행 — 본 마이그레이션이 스키마 기반을 제공한다.
|
||||
- partial UNIQUE는 broker write만 dedup, 레거시 write(order_id NULL)는 append-only. dcy-006 OQ-7 (ii) 결정.
|
||||
- R-5(DOUBLE→NUMERIC 정밀도)/R-6(action→side 매핑 누락)/R-7(DROP 트랜잭션)는 prod 마이그레이션 시 별도 검토. 본 워크스페이스는 개발용이라 영향 미미(workspace_purpose 메모리).
|
||||
- 별도 REL(REL-003 등)로 분리 배포(dcy-006 A-4).
|
||||
- Source: dcy-006 FR-9~12, OQ-6 (iv), OQ-7 (ii).
|
||||
|
||||
## Change Log
|
||||
|
||||
### CHG-20260605-02
|
||||
- Date: 2026-06-05
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
- Status: Proposed → Approved
|
||||
|
||||
#### Intent
|
||||
- 승인 게이트 통과: 필수 필드(Status/Type/Priority/Owner/Intent/Requirement/AC/Impacted Area/Change Log) 모두 충족, AC-1~7 구체성(DB schema 검증) 확인 완료, 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 계획 편입 (BAT-016 후보, REQ-037/038 선행)
|
||||
|
||||
### CHG-20260605-01
|
||||
- Date: 2026-06-05
|
||||
- Author: Justin Ko
|
||||
|
||||
#### Change Summary
|
||||
- 최초 생성 — dcy-006 confirm-discovery 후 draft-req 실행. dcy-006 FR-9~12 산출물.
|
||||
|
||||
#### Intent
|
||||
- portfolio_ledger/ledger_trades 두 ledger 테이블을 portfolio_ledger 단일 회계 원장으로 통합하는 스키마 마이그레이션 정의.
|
||||
|
||||
#### Acceptance Criteria Delta
|
||||
- Added:
|
||||
- AC-1~7 최초 작성
|
||||
|
||||
#### Impacted Area Delta
|
||||
- Docs: docs/data-model.md — 최초 지정
|
||||
- Modules: migrations/versions/, app/repositories/postgres.py — 최초 지정
|
||||
- Tests: 마이그레이션 회귀, tests/test_v1_portfolios_ledger.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 계획 편입; staging에서 DOUBLE→NUMERIC + action→side backfill dry-run
|
||||
|
||||
#### Validation Plan
|
||||
- alembic upgrade head 후 schema 검증(AC-1~7); 개발 DB에서 ensure_schema 정합 확인
|
||||
+6
-3
@@ -74,7 +74,7 @@
|
||||
|
||||
## Next Requirement ID
|
||||
|
||||
- Current: `REQ-036`
|
||||
- Current: `REQ-039`
|
||||
- Rule: `Requirement Register`에 있는 가장 큰 REQ 번호보다 정확히 1 커야 한다.
|
||||
|
||||
## Requirement Register
|
||||
@@ -116,11 +116,14 @@
|
||||
| REQ-033 | ledger_trades.asset_id → portfolio_id 컬럼명 정합화 | Migration | Implemented | Medium | Justin Ko | [req-033](./Migration/req-033_ledger-trades-asset-id-to-portfolio-id-rename.md) |
|
||||
| REQ-034 | LoginRequest 추가 필드 거부 enforcement | Interface | Implemented | Medium | Justin Ko | [req-034](./Interface/req-034_login-request-extra-forbid-enforcement.md) |
|
||||
| REQ-035 | GET /health 응답에 db_enabled 필드 추가 | Interface | Implemented | Medium | Justin Ko | [req-035](./Interface/req-035_health-response-db-enabled-field.md) |
|
||||
| REQ-036 | portfolio_ledger 회계 원장 통합 마이그레이션 (ledger_trades 흡수/DROP) | Migration | Approved | High | Justin Ko | [req-036](./Migration/req-036_portfolio-ledger-consolidation-migration.md) |
|
||||
| REQ-037 | 신 path 회계 책임 단일화 + 응답에 portfolio 상태 포함 | Interface | Approved | High | Justin Ko | [req-037](./Interface/req-037_ledger-trade-write-accounting-and-state-response.md) |
|
||||
| REQ-038 | 레거시 buy/sell endpoint deprecated 표기 | Interface | Approved | Low | Justin Ko | [req-038](./Interface/req-038_legacy-buy-sell-endpoint-deprecation.md) |
|
||||
|
||||
## Recent Change Log Summary
|
||||
|
||||
- 2026-06-05: REQ-036/037/038 Proposed → Approved (CHG-20260605-02 각각) — confirm-req 무인자 일괄 모드 실행, 승인 게이트(필수 필드/AC 구체성/Change Log) 모두 충족, blocker 없음. dcy-006 산출물 3건 모두 Approved. REQ-036(마이그레이션) 선행 의존성 명시.
|
||||
- 2026-06-05: REQ-036/037/038 신규 (Proposed) — dcy-006(ledger trade write 회계 책임 단일화) draft-req 산출물. REQ-036 portfolio_ledger/ledger_trades 통합 마이그레이션(Migration), REQ-037 신 path 회계 책임 단일화 + 응답에 cash_balance_after/asset_quantity_after 포함(Interface), REQ-038 레거시 buy/sell deprecated 표기(Interface). 3건 모두 별도 REL(REL-003 등) 분리 배포 예정(dcy-006 A-4).
|
||||
- 2026-06-05: REQ-033/034/035 Approved → Implemented (CHG-20260601-03 각각) — BAT-015 confirm-batch-verification 완료(2026-06-05). 전체 372 passed + 로컬 smoke 5건 통과. REQ-033 AC-1/AC-4 실 DB evidence는 REL-002 staging 이연(blocker 아님). BAT-015 status: release-candidate.
|
||||
- 2026-06-01: REQ-033/034/035 Proposed → Approved (CHG-20260601-02 각각) — confirm-req 무인자 일괄 모드 실행, 승인 게이트(필수 필드/AC 구체성/Change Log) 모두 충족, blocker 없음. dcy-005 산출물 3건 모두 Approved.
|
||||
- 2026-06-01: REQ-033/034/035 신규 (Proposed) — dcy-005(rel-001-feedback-cleanup) draft-req 산출물. REQ-033 ledger_trades.asset_id → portfolio_id 컬럼명 정합화 (Migration), REQ-034 LoginRequest extra="forbid" enforcement (Interface, REQ-021 follow-up), REQ-035 HealthResponse db_enabled 필드 추가 + docs/runtime-flows.md baseline 갱신 (Interface). 3건 모두 REL-002 분리 배포 예정(dcy-005 OQ-3).
|
||||
- 2026-06-01: REQ-028 Approved → Implemented (CHG-20260601-02) — CHG-20260601-01 augmentation에 대한 verification evidence 확보. pytest 368 PASSED + 로컬 smoke로 GET /v1/portfolios 응답에 `display_name` 노출 확인. BAT-009 verification.md AC-13 매핑 누적. REL-001 실 배포 환경 smoke는 배포 시 최종 확인.
|
||||
- 2026-06-01: REQ-028 Implemented → Approved (CHG-20260601-01) — GET /v1/portfolios 응답 schema에 `display_name` 필드 추가 augmentation. portfolio가 참조하는 asset의 display_name을 join하여 UI/CLI 단일 호출 표시 가능. AC-13 신설, Portfolio domain model + PortfolioItem schema + repo join 보강. BAT-009/BAT-014 verification 재실행 필요.
|
||||
|
||||
Reference in New Issue
Block a user