Confirm REQ-057 for BAT-025 while preserving REQ-056/BAT-024 implementation status. Operational DB execution remains separately approved.
18 KiB
REQ-056: owner-scoped 수동 장부 입력 HTTP API
- Status: Implemented
- Type: Interface
- Priority: High
- Owner: Justin Ko
Intent
- trex-web이 user/session token으로 자기 소유 portfolio에 수동 장부 entry를 append할 수 있는 portfolio-hub v1 API 계약을 신설한다.
- 기존
POST /v1/portfolios/{portfolio_id}/ledger/trades는 trex-core/daemon/service-token broker 체결 보고 전용 계약으로 유지하고, 사용자 수동 입력은 신규POST /v1/portfolios/{portfolio_id}/ledger/manual로 분리한다. - manual write는 portfolio snapshot(
cash_balance,asset_quantity,profit_buffer)과portfolio_ledgerappend를 단일 트랜잭션으로 처리하고, trex-web이 장부 이력/후속 상태/수익 실현액을 표시할 수 있는 응답 shape을 제공한다.
Requirement
-
신규 라우트
POST /v1/portfolios/{portfolio_id}/ledger/manual을 제공한다.- Bearer user/session token을 요구한다.
- 요청자는 대상 portfolio의
owner_user_id와 일치해야 한다. owner mismatch는 HTTP 403 fail-closed로 거부한다. - service-token/daemon-token은 본 endpoint에서 HTTP 403 fail-closed로 거부한다. service-token broker trade write는 기존
/ledger/trades만 사용한다. status='disabled'portfolio write는 HTTP 409로 거부한다.
-
request body는 단일 action-dispatch shape을 사용하며
actionenum을 포함한다.action 필수 입력 선택 입력 snapshot effect INVESTamountnoteprofit_buffer += amountBUFFER_OUTamountnoteprofit_buffer -= amount,cash_balance += amountBUFFER_INamountnotecash_balance -= amount,profit_buffer += amountBUYquantity,pricefee,tax,notecash_balance -= quantity * price + fee + tax,asset_quantity += quantitySELLquantity,pricefee,tax,noteasset_quantity -= quantity,cash_balance += quantity * price - fee - taxWITHDRAWamountnoteprofit_buffer -= amount; 순입금액 계산에서sum(INVEST) - sum(WITHDRAW)의 차감 항목PROFITamountnoteprofit_buffer -= amount; 순수 수익 실현 인출이며 순입금액 계산에는 미포함REVERSALtarget_ledger_entry_idnotetarget entry의 반대 effect를 서버가 계산해 append -
QUANTITY_ADJUSTMENT는 1차 범위에서 제외한다. manual endpoint enum/schema/test는 해당 action을 허용하지 않아야 한다. -
입력 값 검증:
amount,quantity,price는 0보다 커야 한다.fee,tax는 생략 시 0으로 취급하며 음수를 허용하지 않는다.- action에 필요하지 않은 핵심 수치 필드가 포함되면 422로 거부하거나 schema에서 명시적으로 무시하지 말고 계약상 실패로 처리한다.
-
manual write는 새 음수 상태를 만드는 operation을 1차 범위에서 거부한다.
BUY:quantity * price + fee + tax > cash_balance이면 HTTP 409.SELL:quantity > asset_quantity이면 HTTP 409.BUFFER_IN:amount > cash_balance이면 HTTP 409.BUFFER_OUT,WITHDRAW,PROFIT:amount > profit_buffer이면 HTTP 409.INVEST:amount > 0이면 잔고 부족 검증 없이 허용한다.
-
daemon-managed portfolio(
managed_by_daemon_id IS NOT NULL)에는 API-level explicit confirmation을 강제한다.- confirmation 없는 manual write는 HTTP 409 + error code
MANUAL_WRITE_REQUIRES_CONFIRMATION으로 거부한다. - 사용자가 경고를 확인한 뒤 request body에 confirmation flag/evidence를 포함하면 write를 허용한다.
- 허용된 write는 actor user,
managed_by_daemon_id, confirmation evidence를 ledger/audit metadata 또는 동등한 추적 가능한 저장 위치에 남긴다.
- confirmation 없는 manual write는 HTTP 409 + error code
-
REVERSAL정책:target_ledger_entry_id는 필수이며 같은 portfolio 소속 ledger entry여야 한다.- target entry를 직접 수정/삭제하지 않고 반대 effect의 신규
REVERSALentry를 append한다. - target을 찾을 수 없거나 owner scope를 벗어나면 fail-closed(404 또는 403)한다.
- 동일 target entry의 중복 reversal은 HTTP 409로 거부한다.
-
manual write 성공 응답은 HTTP 201을 기본으로 하며 다음 필드를 포함한다.
ledger_entry_id,portfolio_id,action, 입력 수치(amount또는quantity/price/fee/tax),note,recorded_atcash_balance_after,asset_quantity_after,profit_buffer_after,total_value_aftertarget_ledger_entry_id(REVERSAL인 경우),source="manual"또는 동등한 source 구분 필드- daemon-managed confirmation이 적용된 경우 confirmation metadata 또는 audit reference
-
manual ledger history/read 계약은 trex-web 표시를 위해 portfolio별 최근 ledger entries를 반환해야 한다.
- 기존 history endpoint를 확장하거나 신규
GET /v1/portfolios/{portfolio_id}/ledger/manual/동등 endpoint를 설계할 수 있으나, 응답 item에는action,amount,quantity,price,fee,tax,note,recorded_at,cash_balance_after,asset_quantity_after,profit_buffer_after,total_value_after가 포함되어야 한다. total_value_after는 ledger entry 기록 시점의 portfolio-hub snapshot 값이며 실시간 mark-to-market 값으로 해석하지 않는다.
- 기존 history endpoint를 확장하거나 신규
-
수익률/요약 응답은
cumulative_profit_withdrawn을 별도 지표로 노출해야 한다.- 값은
PROFITaction 누적액이다. - 순입금액은
sum(INVEST) - sum(WITHDRAW)로 계산하며PROFIT은 이 계산에 포함하지 않는다.
- 값은
-
ledger append와 portfolio snapshot update는 같은 DB 트랜잭션에서 수행하고, 같은 portfolio의 동시 manual write는 row lock 또는 동등한 concurrency control로 lost update 없이 직렬화한다.
-
기존
/ledger/tradesservice-token broker write,GET /v1/portfolios, CLI portfolio invest/transfer/buy/sell 흐름은 본 endpoint 추가로 회귀하지 않아야 한다.
Acceptance Criteria
- Given owner user/session token + active portfolio, When
POST /v1/portfolios/{id}/ledger/manualwithaction="INVEST",amount=100000, Then HTTP 201 +profit_buffer_after가 100000 증가하고cash_balance_after/asset_quantity_after는 기존 값이며portfolio_ledgerrow가 append된다. - Given owner token + active portfolio(
profit_buffer=100000,cash_balance=0), WhenBUFFER_OUT amount=40000, Then HTTP 201 +profit_buffer_after=60000,cash_balance_after=40000. - Given owner token + active portfolio(
cash_balance=40000,profit_buffer=60000), WhenBUFFER_IN amount=10000, Then HTTP 201 +cash_balance_after=30000,profit_buffer_after=70000. - Given owner token + active portfolio(
cash_balance=1000000,asset_quantity=0), WhenBUY quantity=10 price=80000 fee=100 tax=0, Then HTTP 201 +cash_balance_after=199900,asset_quantity_after=10. - Given owner token + active portfolio(
cash_balance=199900,asset_quantity=10), WhenSELL quantity=3 price=90000 fee=100 tax=0, Then HTTP 201 +asset_quantity_after=7,cash_balance_after=469800. - Given owner token + active portfolio(
profit_buffer=70000), WhenWITHDRAW amount=20000, Then HTTP 201 +profit_buffer_after=50000and the portfolio return/net-contribution calculation treats the amount assum(INVEST) - sum(WITHDRAW)reduction. - Given owner token + active portfolio(
profit_buffer=50000), WhenPROFIT amount=10000, Then HTTP 201 +profit_buffer_after=40000,cumulative_profit_withdrawnincreases by 10000, and net contributed capital is unchanged. - Given owner token + existing ledger entry in the same portfolio, When
REVERSAL target_ledger_entry_id=<target>is posted, Then HTTP 201 + a newREVERSALrow is appended with the target's opposite snapshot effect and the original target row remains unchanged. - Given a target ledger entry was already reversed, When the same
target_ledger_entry_idis reversed again, Then HTTP 409 and no additional ledger row/snapshot update occurs. - Given non-owner user/session token, When manual write or manual history/read is requested for another user's portfolio, Then HTTP 403 fail-closed and no ledger/snapshot mutation occurs.
- Given service-token/daemon-token, When
POST /v1/portfolios/{id}/ledger/manualis called, Then HTTP 403 fail-closed; When existingPOST /v1/portfolios/{id}/ledger/tradesis called with valid daemon assignment, Then existing broker trade contract remains unchanged. - Given disabled portfolio, When owner token posts any manual action, Then HTTP 409 and no ledger/snapshot mutation occurs.
- Given daemon-managed portfolio and no confirmation flag/evidence, When owner token posts any manual action, Then HTTP 409 with error code
MANUAL_WRITE_REQUIRES_CONFIRMATION; Given confirmation evidence is included, Then the write succeeds and actor/daemon/confirmation audit metadata is stored. - Given insufficient balances, When
BUYexceeds cash,SELLexceeds quantity,BUFFER_INexceeds cash, orBUFFER_OUT/WITHDRAW/PROFITexceedsprofit_buffer, Then HTTP 409 and ledger/snapshot remain unchanged for each case. - Given invalid action
QUANTITY_ADJUSTMENTor missing/zero/negative required numeric fields, When manual write is posted, Then HTTP 422 and no ledger/snapshot mutation occurs. - Given successful manual writes, When manual ledger history/read is requested, Then each returned entry includes
action, numeric inputs,note,recorded_at,cash_balance_after,asset_quantity_after,profit_buffer_after,total_value_after. - Given
PROFITentries exist, When return/summary response is requested, Thencumulative_profit_withdrawnis returned separately and net contribution usesINVEST - WITHDRAWwithoutPROFIT. - Given two concurrent manual writes for the same portfolio, When both complete, Then row lock or equivalent control serializes updates without lost update; final snapshot equals sequential application of both accepted entries.
- Given existing regression tests for
/ledger/trades,GET /v1/portfolios, and CLI portfolio invest/transfer/buy/sell, When this REQ is implemented, Then those contracts still pass without semantic regression.
Impacted Area
- Docs:
docs/interface-contract.md— 신규 manual ledger write/read endpoint, request/response schema, error codes,cumulative_profit_withdrawn지표 명세.docs/runtime-flows.md— owner-scoped manual write flow, daemon-managed confirmation, transaction/row lock, reversal flow 추가.docs/data-model.md—portfolio_ledgermanual source/action metadata, reversal target reference, after-snapshot/cumulative profit semantics 보강.
- Modules:
app/api/v1_portfolios.py또는 신규 v1 router —POST /v1/portfolios/{portfolio_id}/ledger/manual및 manual ledger history/read endpoint.app/schemas/v1.py— manual request/response schemas, action enum, error response shape.app/domain/services.py— manual action/effect helper, negative-state validation, reversal calculation,PROFITvsWITHDRAWclassification.app/repositories/portfolio_repository.py,app/repositories/postgres.py— transaction/row lock, ledger append, reversal target lookup/dedup, history/read,cumulative_profit_withdrawnaggregate.- auth dependencies — user/session owner-scope write guard and service-token fail-closed guard.
- Tests:
- 신규/갱신 API tests for AC-1~17.
- repository/concurrency tests for AC-18.
- regression tests for existing
/ledger/trades, portfolio list, CLI/domain flow compatibility (AC-19).
Notes
- Source:
docs/discovery/dcy-012_20260714_manual-ledger-write-api-owner-scoped.mdconfirmed by Justin Ko, Ready for REQ Drafting true. - Project #7 item:
PVTI_lADOBCBKFM4BbUVHzgyvA9A— Status Requirements. - 본 REQ는 Interface 중심이다. Data 변경(예: reversal target reference 저장 위치, confirmation metadata 저장 위치)이 필요할 수 있으나, 현재는 API 계약과 수락 기준에서 추적하고 batch design에서 기존
portfolio_ledgermetadata로 충분한지 또는 migration REQ 분리가 필요한지 판정한다. - 기존
/ledger/trades는 daemon/service-token broker write 전용으로 보존한다. user/session token manual BUY/SELL은/ledger/trades로 우회 허용하지 않는다. PROFIT과WITHDRAW는 snapshot effect가 모두profit_buffer감소일 수 있으나 성과 계산 의미가 다르다.WITHDRAW는 원금/입금액 회수로 순입금액을 감소시키고,PROFIT은 순수 수익 실현 인출로cumulative_profit_withdrawn에만 누적한다.total_value_after는 ledger 기록 시점의 snapshot 값이며, 실시간 가격 재평가 결과가 아니다.QUANTITY_ADJUSTMENT는 후속 Discovery/REQ 후보이며 본 REQ 구현 범위가 아니다.
Change Log
CHG-20260714-01
- Date: 2026-07-14
- Author: portfolio-hub-dev (Hermes)
Change Summary
- 신규 생성 (Proposed) — dcy-012 confirmed Discovery 근거로 draft-req 실행. owner-scoped manual ledger write/read API 계약을 정의하고 기존 daemon/service-token
/ledger/trades계약 보존을 명시한다.
Intent
- trex-web manual ledger UI가 소비할 portfolio-hub API surface를
POST /v1/portfolios/{portfolio_id}/ledger/manual+ action enum으로 고정하고, action/effect/권한/409 validation/daemon-managed confirmation/history response/PROFIT 계산 의미를 수락 가능 요구사항으로 정규화한다.
Acceptance Criteria Delta
- Added:
- AC-1~19 최초 작성
- Updated: 없음
- Removed: 없음
Impacted Area Delta
- Docs:
docs/interface-contract.md,docs/runtime-flows.md,docs/data-model.md갱신 예고 - Modules: v1 portfolio router, v1 schemas, domain services, portfolio repository/postgres repository, auth dependency 확장
- Tests: manual action/effect, owner/non-owner/service-token/disabled/daemon-confirmation, insufficient balance, reversal, history/read, cumulative profit, concurrency, existing ledger trade/CLI regression
Delivery Trace Delta
- Batches: 미정 (confirm-req 이후 suggest-batch-reqs)
- Releases: 미정
Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req(팀장 승인) → suggest-batch-reqs. Design 단계에서 reversal/confirmation metadata 저장 위치가 migration 필요 여부를 확정한다.
Validation Plan
- pytest TestClient/API tests로 AC-1~17 검증. repository/integration 또는 concurrency harness로 AC-18 검증. 기존
/ledger/trades,GET /v1/portfolios, CLI/domain 흐름 regression으로 AC-19 검증.
CHG-20260714-02
- Date: 2026-07-14
- Author: TREX lead (Hermes)
Change Summary
- Status: Proposed → Approved (confirm-req). dcy-012 confirmed Discovery와 AC-1~19가 test 가능한 구현 기준으로 충분하다고 판정한다.
Intent
- owner-scoped manual ledger API를 batch delivery 기준으로 확정한다.
Acceptance Criteria Delta
- Added: 없음
- Updated: 없음
- Removed: 없음
Impacted Area Delta
- 변경 없음. 구현 단계에서 docs/interface-contract.md, docs/runtime-flows.md, docs/data-model.md, API/schema/domain/repository/auth/tests를 갱신한다.
Delivery Trace Delta
- Batches: BAT-024 후보로 제안
- Releases: 미정
Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: proceed-to-batch
- Follow-up Action: suggest-batch-reqs → draft-batch/planning/design/implementation/verification.
Validation Plan
- AC-1~19를 batch verification에서 API/repository/concurrency/regression evidence로 검증한다.
CHG-20260715-03
- Date: 2026-07-15
- Author: TREX lead (Hermes)
Change Summary
- 운영 적용 방식 보완을 REQ-057로 분리 추적한다. REQ-056의 기존 API 계약, AC-1~19,
Implementedstatus 및 BAT-024release-candidate상태는 변경하거나 되돌리지 않는다.
Intent
- REQ-056 구현에서 사용된 additive
portfolio_ledger컬럼의 운영 DB 적용을 runtimeensure_schema()자동 DDL에만 의존하지 않도록 명시 Alembic migration과 운영 runbook 요구사항으로 후속 관리한다.
Acceptance Criteria Delta
- Added: 없음 (REQ-056 AC 변경 없음)
- Updated: 없음
- Removed: 없음
- Follow-on: REQ-057 AC-1~11이 migration, schema/Alembic revision 정합, 운영 preflight/runbook, forward-only recovery, release 결재 게이트를 별도로 정의한다.
Impacted Area Delta
- REQ-056 구현 영향 범위는 변경 없음.
- 후속 REQ-057 영향:
migrations/versions/, runtimeensure_schema()호환성, migration/runbook 및 persistence baseline 문서. 실제 변경은 BAT-025 standard에서 수행한다.
Delivery Trace Delta
- Batches: BAT-024는 REQ-056 구현/검증 release-candidate 상태로 유지. BAT-025 standard가 REQ-057 migration implementation/test/QC/runbook을 담당한다.
- Releases: 운영 DB upgrade, 서비스 재시작 및 신규 manual ledger API 활성화는 별도 명시 release 결재 전 실행하지 않는다.
Revalidation Impact
- Reverification Needed: no — REQ-056의 기존 implementation/QC evidence는 무효화하지 않는다.
- Existing Implementation Invalidated: no
- Status Recommendation: keep-Implemented
- Follow-up Action: REQ-057 Proposed 검토·승인 후 BAT-025에서 migration compatibility/data preservation/runbook evidence를 확보한다.
Validation Plan
- BAT-025에서 fresh DB와 runtime-precreated-schema 환경의 Alembic upgrade, 기존 row/source 보존,
alembic current정합, broker/manual ledger regression, runbook preflight 및 service smoke를 검증한다. 운영 DB 실행은 별도 release 결재 범위다.
Implementation Confirmation
- Confirmed: 2026-07-14 KST
- Implementing Batch: BAT-024 —
docs/batches/bat-024_20260714_manual-ledger-api/ - Implementation commit:
b3447f6 feat(api): add owner-scoped manual ledger endpoint - Developer verification:
594 passed, 12 warnings in 37.24s - Independent QC: PASS (
deleg_f2337a39) —594 passed, 12 warnings in 37.29s; focused remediation tests4 passed. - Lead gate:
confirm-req-implementedaccepted. - Release caveat: production DB rollout needs release-gate handling for additive
portfolio_ledgercolumns (source,target_ledger_entry_id,confirmation_evidence,actor_user_id), preferably Alembic migration/runbook instead of relying only onensure_schema().