# Phase 2 Source Adapter 상세 명세

이 문서는 Phase 2에서 구현할 핵심 source adapter의 상세 규격을 정의합니다.
모든 adapter는 다음 공통 인터페이스를 따라야 합니다.

## 1. 공통 인터페이스

### 1.1 입력

- `run_id: str`
- `mode: Literal["poll", "backfill", "replay"]`
- `start_date: date | None`
- `end_date: date | None`
- `symbols: list[str] | None`
- `force: bool = False`
- `dry_run: bool = False`

### 1.2 출력

표준 실행 요약 객체:

```json
{
  "run_id": "...",
  "job_name": "...",
  "source": "...",
  "status": "completed",
  "raw_objects_written": 0,
  "staging_records_written": 0,
  "structured_records_written": 0,
  "warnings": [],
  "errors": []
}
```

### 1.3 예외 분류

- `RetriableSourceError`
- `TerminalSourceError`
- `SchemaValidationError`
- `CheckpointCorruptionError`
- `RawWriteError`
- `StructuredWriteError`

## 2. SEC Adapter

### 2.1 책임

- 회사 submissions JSON 수집
- filing index / filing text / exhibit 문서 다운로드
- accession / form_type / filing_date / acceptance_datetime 추출
- XBRL facts 추출 대상 식별

### 2.2 세부 job

#### A. `sec_submissions_poll`

입력:
- CIK 목록 또는 symbol master 기반 CIK 맵

raw 출력:
- submissions JSON

staging 출력:
- filing header row 목록
- 신규 accession 후보 목록

structured 출력:
- `documents`
- `document_versions`

#### B. `sec_filing_fetch`

입력:
- accession 목록

raw 출력:
- filing text/html
- filing index
- exhibit 문서

staging 출력:
- exhibit inventory
- 99.1 / xbrl 관련 링크

structured 출력:
- `raw_objects`
- `document_artifacts`

#### C. `sec_xbrl_extract`

입력:
- XBRL 가능 accession

staging 출력:
- canonical fact rows

structured 출력:
- `xbrl_facts`

### 2.3 체크포인트

- 마지막 submissions fetch 시각
- accession별 fetch 완료 상태
- accession별 xbrl extract 완료 상태

### 2.4 idempotency key

- submissions: `(source, cik, fetched_at_date, checksum)`
- filing fetch: `(source, accession, artifact_name, checksum)`
- xbrl facts: `(accession, concept, period_end, unit, segment_hash)`

### 2.5 구현 주의사항

- accession formatting을 내부 표준으로 통일
- 동일 accession의 문서/artifact는 checksum이 다를 때만 새 버전 생성
- raw write 전에 checksum 계산
- 99.1, 8-K, 10-Q, 10-K, 6-K, 20-F 우선

### 2.6 실패 조건

retriable:
- 일시적 네트워크 오류
- 응답 타임아웃
- 일시적 source unavailable

terminal:
- accession 식별 불가
- 필수 filing metadata 누락
- artifact MIME/type 해석 불가

## 3. Alpaca Adapter

### 3.1 책임

- 일봉 수집
- 분봉 수집(Phase 2에서는 1분/5분 중 하나만 선택)
- 심볼별 거래일 범위 backfill

### 3.2 세부 job

#### A. `alpaca_daily_bars_backfill`

입력:
- symbol list
- date range

raw 출력:
- 원본 bars payload

staging 출력:
- canonical daily bars

structured 출력:
- `market_bars_daily`
- Parquet partition `bars_daily/trading_date=YYYY-MM-DD/`

#### B. `alpaca_intraday_bars_poll`

입력:
- symbol list
- trading day

raw 출력:
- intraday bars payload

staging 출력:
- canonical intraday bars

structured 출력:
- `market_bars_intraday`
- Parquet partition `bars_intraday/trading_date=YYYY-MM-DD/`

### 3.3 체크포인트

- symbol / timeframe / date 단위 완료 플래그
- intraday는 마지막 timestamp

### 3.4 idempotency key

- `(symbol, timeframe, timestamp)`

### 3.5 구현 주의사항

- timezone normalization을 내부 표준으로 강제
- 반일장 / 휴장일 처리
- 동일 바 중복 수신 시 마지막 checksum만 허용

### 3.6 실패 조건

retriable:
- 네트워크 오류
- 일시적 rate-limit

terminal:
- symbol invalid
- timestamp parse 실패
- 필수 OHLCV 필드 누락

## 4. FRED Adapter

### 4.1 책임

- 지정 series_id 목록 sync
- daily/weekly/monthly frequency series 공통 적재

### 4.2 세부 job

#### A. `fred_series_sync`

입력:
- series_id 목록
- optional date range

raw 출력:
- series observations payload

staging 출력:
- canonical series rows

structured 출력:
- `macro_series_observations`

### 4.3 체크포인트

- series_id별 마지막 observation date

### 4.4 idempotency key

- `(series_id, observation_date)`

### 4.5 구현 주의사항

- 숫자/결측 문자열 처리 규칙 고정
- revision이 가능한 시계열은 overwrite 가능한 upsert 허용
- source metadata(series title, units, frequency)도 별도 저장

## 5. FINRA Adapter

### 5.1 책임

- daily short sale volume 파일 다운로드
- 파일 파싱 및 종목별 행 생성

### 5.2 세부 job

#### A. `finra_short_volume_fetch`

입력:
- trading date range

raw 출력:
- 원본 txt/csv 파일

staging 출력:
- parsed rows

structured 출력:
- `short_sale_volume_daily`

### 5.3 체크포인트

- trading_date 파일 존재 여부
- checksum

### 5.4 idempotency key

- `(trade_date, symbol)`

### 5.5 구현 주의사항

- header drift 대응
- symbol 정규화
- total_volume == 0 또는 short_volume > total_volume 같은 비정상 레코드 검출

## 6. 공통 구현 요구사항

### 6.1 로그

모든 adapter는 최소 아래 필드를 구조화 로그로 남겨야 합니다.

- `run_id`
- `job_name`
- `source`
- `mode`
- `status`
- `object_count`
- `duration_ms`
- `warning_count`
- `error_count`

### 6.2 메트릭

최소 메트릭:
- fetch success rate
- fetch latency
- raw write latency
- staging rows written
- structured rows written
- checkpoint lag

### 6.3 Dry Run

모든 adapter는 `dry_run` 모드를 지원해야 합니다.

`dry_run=True`일 때:
- 원격 요청은 수행 가능
- raw/structured write는 하지 않음
- validation과 실행 계획만 출력

### 6.4 Replay

모든 adapter는 특정 raw object를 replay input으로 받을 수 있어야 합니다.

예:
- `--raw-path data/raw/sec/.../filing.txt`
- `--raw-path data/raw/finra/.../file.txt`

### 6.5 Source Freeze

특정 source가 이상 동작할 때 운영자가 source별 수집을 중단할 수 있어야 합니다.

예:
- `configs/source_freeze.yaml`
- source/job 단위 on/off

## 7. 완료 기준

- 각 adapter는 poll/backfill/replay를 모두 지원해야 합니다.
- 동일 input에서 동일 output을 만들어야 합니다.
- raw sidecar, structured rows, checkpoint, job_runs가 모두 연결되어야 합니다.
