flowchart LR
subgraph Presentation["Presentation"]
StockController["StockApiController"]
Scheduler["StockPriceScheduler"]
end
subgraph Application["Application"]
ListUC["ListStocksUseCase"]
SyncUC["SyncStocksUseCase"]
SseReg["SseEmitterRegistry"]
end
subgraph Domain["Domain (stock)"]
StockDS["StockDomainService"]
end
subgraph WatchlistDomain["Domain (watchlist)"]
WatchlistDS["WatchlistDomainService"]
end
StockController --> ListUC
ListUC --> StockDS
ListUC --> WatchlistDS
Scheduler --> SyncUC
Scheduler --> SseReg
SyncUC --> StockDS
Sequence Diagram — SSE 가격 전송
sequenceDiagram
participant Sch as StockPriceScheduler
participant UC as SyncStocksUseCase
participant DS as StockDomainService
participant Cache as StockPriceCacheRepo
participant Sse as SseEmitterRegistry
participant FE as FE(SSE Client)
Sch->>UC: executeAndReturn()
UC->>DS: syncPrices()
DS->>Cache: upsertAll(prices)
DS-->>UC: prices: List<StockPriceCache>
UC-->>Sch: prices
Sch->>Sse: broadcast(prices)
Sse->>FE: SSE event(price-updated, JSON[])
Sequence Diagram — 테마 연관 추천 (ML)
sequenceDiagram
participant C as FE/Client
participant ML as ML Service
participant TH as theme_chain.py
participant Map as THEME_MAPPING
C->>ML: GET /theme-recommendations
ML->>TH: extract_theme(recent_headlines)
TH-->>ML: theme = "AI_SERVER"
ML->>Map: get_related_stocks("AI_SERVER")
Map-->>ML: [{symbol, name, relation}, ...]
ML-->>C: [{theme, reason, stocks}]
ERD
변경 없음 — DB 스키마 변경 없다. watchlist·stock 테이블 재사용.
Testing Plan
ML: get_curated_symbols(category) — large/mid/small/all 각 카테고리별 심볼 수 검증
ML: extract_theme(headlines) — AI_SERVER 키워드 감지·빈 헤드라인 graceful 처리 검증
ML: GET /theme-recommendations — 200 응답, [{theme, reason, stocks}] 형식 준수 검증
BE: ListStocksUseCase — 관심종목 교차 조회 후 isInWatchlist 정확성 + 예외 시 graceful 검증
BE: SseEmitterRegistry.broadcast(prices) — JSON 배열 event 전송·실패 emitter 제거·빈 목록 처리 검증
Release Scenario
ML 서비스 배포: CURATED_SYMBOLS 확장 + theme_chain.py 추가
BE 배포: ListStocksUseCase, SseEmitterRegistry, StockPriceScheduler 변경
FE 변경: SSE data 파싱 로직 (JSON 배열 처리), 관심종목 버튼 로직 확인
롤백: ML 서비스는 구버전 재배포 (category 파라미터 없으면 all 기본값 유지). BE는 broadcastRefresh() 메서드 복구.