# QuantEngine 수집 파이프라인 (KIS API) ## 1. 수집 실행 상태 전이도 (State Diagram) KIS 데이터 수집 실행(kis_collection_runs)의 상태 흐름. 상태값은 KisDataCollectionOrchestrator 에서 정의: - `RUNNING`: 수집 진행 중 - `COMPLETED`: 모든 스냅샷 수집 완료 (에러 없음, `total_errors == 0`) - `COMPLETED_WITH_ERRORS`: 부분 수집 완료 (에러 발생, `total_errors > 0`이지만 일부 성공) - `FAILED`: 전체 실패 (예외 발생, 데이터 미적재) ```mermaid stateDiagram-v2 [*] --> RUNNING: 수집 시작
(RunCollectionAsync) RUNNING --> COMPLETED: 완료 & error_count==0 RUNNING --> COMPLETED_WITH_ERRORS: 완료 & error_count>0 RUNNING --> FAILED: 예외 발생 COMPLETED --> [*] COMPLETED_WITH_ERRORS --> [*] FAILED --> [*] ``` **상태 전이 조건** (KisDataCollectionOrchestrator.cs 라인 104-105): - `error_count == 0` → `COMPLETED` - `error_count > 0` → `COMPLETED_WITH_ERRORS` - 예외(Exception) → `FAILED` **성공 기준** (CLAUDE.md "Collection Run Success Criteria"): - Success: `status == "COMPLETED"` (NOT failed) - Partial Success: `status == "COMPLETED"` + `total_snapshots > 0` + `total_errors > 0` - Failure: `status == "FAILED"` OR `total_snapshots == 0` --- ## 2. 수집 파이프라인 흐름도 (Flowchart) KIS API 데이터 수집의 전체 흐름. 두 개의 트리거: 1. **Hangfire 정기 작업**: 매일 09:00 에 자동 실행 2. **API 수동 트리거**: POST /api/collection/run (쿠키 기반 인증) ```mermaid flowchart TD A["Hangfire daily-collection
(09:00 KST)"] B["POST /api/collection/run
(Cookie Auth)"] A --> C["IServiceScopeFactory.CreateScope
(resolve ICollectionOrchestrator)"] B --> C C --> D["KisDataCollectionOrchestrator.RunCollectionAsync
(tickers: [005930, 000660, ...])"] D --> E["Per-ticker 루프"] E --> F["KisApiPriceSource.GetPriceDataAsync
(ticker, account)"] F --> G["PriceDataNormalizer.NormalizeCollectionRow
(seedRow, kisResult)"] G --> H["CollectionRepository.SaveSnapshot
(kis_collection_snapshots)"] G --> I["CollectionRepository.SaveError
(kis_collection_errors, on exception)"] H --> J{루프 끝?} I --> J J -->|Yes| K["CollectionRepository.SaveRun
(kis_collection_runs)"] J -->|No| E K --> L["파일 출력:
Temp/kis_dotnet_collection_v1.json"] L --> M["Serilog 로그:
src/dotnet/.../logs/"] M --> N["Admin UI: /Admin/Collection
(CollectionRepository 읽기)"] N --> O["대시보드 표시:
상태, 스냅샷 수, 에러"] ``` **데이터 흐름**: 1. **입력**: Hangfire 스케줄 or API 수동 요청 2. **오케스트레이션**: ICollectionOrchestrator 스코프 생성 3. **수집**: KIS Open API 호출 → PriceDataNormalizer → DB 저장 4. **출력**: - kis_collection_runs: 실행 메타데이터 (run_id, status, total_snapshots, total_errors) - kis_collection_snapshots: 종목별 가격 데이터 (JSON payload) - kis_collection_errors: 에러 기록 - Temp/kis_dotnet_collection_v1.json: 수집 결과 요약 (formula_id, gate, run_id, summary) - Serilog 로그: 런타임 로그 (src/dotnet/QuantEngine.Web/logs/) 5. **표시**: Admin UI에서 CollectionRepository API 호출 → kis_collection_* 읽기 → Dashboard 렌더링 --- ## 3. WBS 증거 검증 시퀀스도 (Sequence Diagram) 작업 완료 증거를 자동 검증하는 파이프라인. 도구: `verify_wbs_task_v1.py` (증거 수집) + `validate_quant_engine_wbs_v1.py` (CI에서 재검증). ```mermaid sequenceDiagram Developer->>verify_wbs_task_v1.py: python verify_wbs_task_v1.py --task QE-M1-01
(또는 --run-commands) verify_wbs_task_v1.py->>+spec/60_quant_engine_wbs.yaml: load spec spec/60_quant_engine_wbs.yaml-->>-verify_wbs_task_v1.py: meta + tasks[QE-M1-01] Note over verify_wbs_task_v1.py: evidence_checks 선언형 해석 alt pg_query 체크 verify_wbs_task_v1.py->>+PostgreSQL: SELECT ... (WHERE 절) PostgreSQL-->>-verify_wbs_task_v1.py: 스칼라 결과 또는 행 verify_wbs_task_v1.py->>verify_wbs_task_v1.py: expect{min,max,equals} 비교 end alt log_pattern 체크 verify_wbs_task_v1.py->>+src/dotnet/.../logs/: file_glob 매칭 src/dotnet/.../logs/-->>-verify_wbs_task_v1.py: 로그 라인 verify_wbs_task_v1.py->>verify_wbs_task_v1.py: 정규식 패턴 검사
(min_matches, max_age_hours) end alt json_gate 체크 verify_wbs_task_v1.py->>+Temp/kis_dotnet_collection_v1.json: read JSON Temp/kis_dotnet_collection_v1.json-->>-verify_wbs_task_v1.py: payload verify_wbs_task_v1.py->>verify_wbs_task_v1.py: 점 표기 경로(dot notation)
+ 값 비교 (>=N 지원) end alt file_exists 체크 verify_wbs_task_v1.py->>verify_wbs_task_v1.py: paths[] 존재 확인
(min_bytes 검증) end alt playwright_report 체크 verify_wbs_task_v1.py->>+tests/e2e/playwright-report.json: read report tests/e2e/playwright-report.json-->>-verify_wbs_task_v1.py: suites[].specs[] verify_wbs_task_v1.py->>verify_wbs_task_v1.py: spec_file 매칭
(passed_min, failed) end verify_wbs_task_v1.py->>verify_wbs_task_v1.py: 모든 체크 결과 종합
(gate = ALL PASS? → PASS : FAIL) verify_wbs_task_v1.py->>+Temp/evidence/QE-M1-01/: mkdir verify_wbs_task_v1.py->>Temp/evidence/QE-M1-01/verdict.json: write verdict
(task_id, gate, checks[]) verify_wbs_task_v1.py->>Temp/evidence/QE-M1-01/: save raw evidence
(pg_query_n.json, log_excerpt.txt, ...) verify_wbs_task_v1.py->>+runtime/lineage_events.jsonl: append event
(node_id, gate, timestamp) Developer<<--verify_wbs_task_v1.py: exit 0 (gate=PASS)
or exit 1 (gate=FAIL) Note over Developer: 선택: --run-commands 플래그
verification_commands[] 실행 Developer->>+validate_quant_engine_wbs_v1.py: (CI) python validate_quant_engine_wbs_v1.py validate_quant_engine_wbs_v1.py->>validate_quant_engine_wbs_v1.py: spec load validate_quant_engine_wbs_v1.py->>validate_quant_engine_wbs_v1.py: tasks[status==DONE] 필터 validate_quant_engine_wbs_v1.py->>+Temp/evidence/*/verdict.json: load all verdicts Temp/evidence/*/verdict.json-->>-validate_quant_engine_wbs_v1.py: gate 값 validate_quant_engine_wbs_v1.py->>validate_quant_engine_wbs_v1.py: gate=FAIL? → CI FAIL validate_quant_engine_wbs_v1.py->>+Temp/quant_engine_wbs_v1.json: write summary Developer<<--validate_quant_engine_wbs_v1.py: exit 0 (모두 PASS)
or exit 1 (일부 FAIL) ``` **검증 프로세스 상세**: | 단계 | 역할 | 산출물 | |------|------|--------| | **1. 스펙 로드** | verify_wbs_task_v1.py | spec/60_quant_engine_wbs.yaml | | **2. 증거 체크 실행** | 선언형 evidence_checks[] | pg_query / log_pattern / json_gate / file_exists / playwright_report | | **3. 게이트 결정** | 모든 체크 PASS? | gate = PASS or FAIL | | **4. 증거 저장** | Temp/evidence// | verdict.json + 원시 증거 | | **5. 계보 로깅** | runtime/lineage_events.jsonl | node_id, gate, timestamp | | **6. CI 재검증** | validate_quant_engine_wbs_v1.py | status=DONE 작업만 재검증 | **주요 특징**: - **선언형 검증**: 체크 로직을 YAML에 기술 (하드코딩 최소화) - **원시 증거 보존**: 각 체크의 상세 결과를 JSON/텍스트로 저장 - **완료 주장 차단**: "완료했다"는 수동 선언 불가 → verdict.json gate=PASS만 인정 - **CI 편입**: validate_quant_engine_wbs_v1.py가 release DAG의 노드로 동작 - **멀티 트리거**: 단일 작업 검증 (--task) 또는 전체 검증 (CI) **검증 체크 타입 참고** (spec/60_quant_engine_wbs.yaml "evidence_check_types"): - **pg_query**: PostgreSQL 스칼라 결과 비교 (min/max/equals) - **log_pattern**: 로그 파일 정규식 매칭 (min_matches, max_age_hours) - **json_gate**: JSON 아티팩트 키-값 검사 (점 표기 경로, >=N 비교) - **file_exists**: 파일 존재 + 크기 검증 (min_bytes) - **playwright_report**: Playwright 리포트 테스트 결과 (passed_min, failed)