[STK5-05] 보유종목 조회 + 거래내역 조회 API
작업 내용 (설계 의도)
변경 사항
holding 도메인을 외부로 노출하는 UseCase·Controller를 구성한다. STK5-02(account 패키지)·STK5-03(holding 패키지) 완료 후 착수한다. STK5-04·STK5-06과 독립적인 파일(별도 컨트롤러 또는 AccountApiController 내 별도 메서드)이므로 병렬 진행 가능하다.
구성 범위:
- application UseCase:
GetHoldingsUseCase,GetTradeHistoryUseCase - presentation:
AccountApiController에 엔드포인트 2개 추가 (STK5-04와 같은 컨트롤러 파일 — Wave 3에서 STK5-04·STK5-05가 같은 파일을 수정하므로 STK5-04 완료 후 착수하거나 역할 분담 필요)
파일 충돌 주의:
AccountApiController.kt는 STK5-04도 수정한다. STK5-04를 먼저 머지하고 STK5-05를 후행 착수하거나, STK5-05 전용HoldingApiController.kt를 신설한다. 후자를 권장.
구성 범위 (조정):
- presentation:
HoldingApiController신설 (AccountApiController와 파일 분리)
API 엔드포인트:
GET /api/v1/accounts/{accountNumber}/holdings— 보유종목 조회 (Toss fetch → upsert → 응답)GET /api/v1/accounts/{accountNumber}/trade-history?from=&to=— 거래내역 조회 (Toss fetch → upsert → 응답, 기본 최근 30일)
다이어그램
처리 흐름 (보유종목 조회)
sequenceDiagram participant C as HoldingApiController participant U as GetHoldingsUseCase participant D as HoldingDomainService participant G as HoldingGateway participant R as HoldingRepository C->>U: execute(accountNumber) U->>D: getHoldings(accountNumber) D->>G: fetchHoldings(accountNumber) G-->>D: List<HoldingData> D->>R: upsertAll(holdings) R-->>D: List<Holding> D-->>U: List<Holding> U-->>C: List<HoldingResponse> alt Toss API 오류 G-->>D: 예외 D-->>U: 예외 전파 U-->>C: 500 end
처리 흐름 (거래내역 조회)
sequenceDiagram participant C as HoldingApiController participant U as GetTradeHistoryUseCase participant D as HoldingDomainService participant G as HoldingGateway participant R as TradeHistoryRepository C->>U: execute(accountNumber, from, to) U->>D: getTradeHistory(accountNumber, from, to) D->>G: fetchTradeHistory(accountNumber, from, to) G-->>D: List<TradeHistoryData> D->>R: upsertAll(tradeHistories) R-->>D: List<TradeHistory> D-->>U: List<TradeHistory> U-->>C: List<TradeHistoryResponse>
클래스 의존
flowchart LR subgraph Presentation["presentation"] HC[HoldingApiController] end subgraph Application["application"] GHU[GetHoldingsUseCase] GTU[GetTradeHistoryUseCase] end subgraph Domain["domain"] HDS[HoldingDomainService] HGW[HoldingGateway] HR[HoldingRepository] THR[TradeHistoryRepository] end subgraph Infra["infrastructure"] THG[TossHoldingGateway] HRI[HoldingRepositoryImpl] THRI[TradeHistoryRepositoryImpl] end HC --> GHU HC --> GTU GHU --> HDS GTU --> HDS HDS --> HGW HDS --> HR HDS --> THR THG -.->|implements| HGW HRI -.->|implements| HR THRI -.->|implements| THR
테스트 케이스
- 동일 계좌·종목으로
GET /api/v1/accounts/{accountNumber}/holdings를 2회 조회하면 MySQL에 중복 없이 1건만 존재하고refreshed_at이 최신값으로 갱신된다. - 보유종목이 없는 계좌를 조회하면 빈 배열을 반환하고 200을 응답한다.
GET /api/v1/accounts/{accountNumber}/trade-history호출 시from·to를 생략하면 기본 최근 30일 범위로 조회된다.- 동일
toss_transaction_id를 가진 거래내역이 2회 upsert되더라도 MySQL에 1건만 존재한다. - Toss API 호출이 실패하면 MySQL upsert를 실행하지 않고 500을 반환한다.