[STK8-01] Backend: ManualHolding 도메인 + DB 스키마 + CRUD API
작업 내용 (설계 의도)
변경 사항
portfolio 패키지를 새로 만들고 수동 포트폴리오(ManualHolding) 도메인을 구현한다. 사용자가 “삼성전자, 50,000원, 100주”처럼 수동으로 입력한 내용을 DB에 저장하고, 현재가(TossAPI)와 함께 손익을 계산하는 것이 이 티켓의 핵심이다.
기존 holding 도메인(토스 실계좌 보유 스냅샷)과는 완전히 분리된 신규 도메인이다.
DB 마이그레이션: V202606201700__create_manual_holdings.sql
다이어그램
처리 흐름
sequenceDiagram participant C as ManualHoldingApiController participant UC as AddManualHoldingUseCase participant DS as ManualHoldingDomainService participant R as ManualHoldingRepository C->>UC: execute(command) UC->>DS: addHolding(command) DS->>R: findBy(symbol) — 중복 체크 DS->>R: save(entity) DS-->>UC: ManualHolding UC-->>C: ManualHoldingResponse
클래스 의존
flowchart LR Controller --> AddManualHoldingUseCase Controller --> UpdateManualHoldingUseCase Controller --> DeleteManualHoldingUseCase Controller --> ListManualHoldingsUseCase AddManualHoldingUseCase --> ManualHoldingDomainService UpdateManualHoldingUseCase --> ManualHoldingDomainService DeleteManualHoldingUseCase --> ManualHoldingDomainService ListManualHoldingsUseCase --> ManualHoldingDomainService ManualHoldingDomainService --> ManualHoldingRepository ManualHoldingDomainService --> TossStockGateway
테스트 케이스
- 정상 종목을 추가하면 ManualHolding이 DB에 저장된다
- 동일 symbol을 중복 추가하면 예외가 발생한다
- 매수가·수량 수정 시 기존 항목이 갱신된다
- 존재하지 않는 symbol 삭제 시 예외가 발생한다
- 목록 조회 시 현재가가 포함된 손익이 계산되어 반환된다
- 현재가 > 매수가이면 손익이 양수로 반환된다
- 현재가 < 매수가이면 손익이 음수로 반환된다
- 매수가 0 이하 입력 시 예외가 발생한다
- 수량 0 이하 입력 시 예외가 발생한다
DDL 참고
CREATE TABLE manual_holdings (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '기본키',
symbol VARCHAR(20) NOT NULL UNIQUE COMMENT '종목 코드',
name VARCHAR(100) NOT NULL COMMENT '종목명',
avg_price DECIMAL(20, 4) NOT NULL COMMENT '평균 매수가',
quantity INT NOT NULL COMMENT '보유 수량',
created_at DATETIME(6) NOT NULL COMMENT '생성일시',
updated_at DATETIME(6) NOT NULL COMMENT '수정일시'
) COMMENT = '수동 입력 포트폴리오';