buildrisk-radar

ADR-027 근거 계보 · 내려받기 · 공개 API 안내

배경 경보마다 근거(evidence: 조건 · 파라미터 · 관측값 · 원천 접수번호)가 붙어 있지만(NFR-05), 그 숫자가 원천 재무제표의 어느 줄에서, 어떤 매핑 규칙으로 왔는지는 DB 를 직접 봐야 알 수 있었다. 분석가 · 감사인이 “이 420%는 어디서 왔나”를 화면과 API 로 끝까지 확인하고, 같은 숫자를 자기 도구(엑셀 등)로 가져갈 수 있어야 한다.

결정

  1. 근거 계보 API GET /alerts/{id}/lineage — 경보 → 규칙 버전(파라미터 · 변경 메모) → 지표 행 → 표준계정(fs_std) → 원천 재무제표 줄(fs_raw)과 그 줄을 고른 매핑 규칙 · 통계 행(region_stat) · 공시(구조화 값 · 파서 버전) → 수집 · 계산 실행(calc_run · collect_run · Spring Batch 실행).
    • 원천 줄은 같은 보고서를 지금의 매핑 규칙으로 다시 표준화해 고른다(AccountStandardizer.explain — standardize 와 같은 경로, 값이 같음을 실제 DART 응답 6건 골든 테스트로 고정). 이름으로 거꾸로 찾지 않는 이유: 합산 계정(단기차입금 + 유동성장기부채)과 같은 이름의 두 줄(순액 · 액면)을 이름만으로는 구별할 수 없음.
    • 다시 계산한 값이 저장된 값과 다르면 reproduced = false — 매핑 규칙을 바꾼 뒤 아직 재표준화하지 않은 경우를 숨기지 않는다.
    • 분기값(QTR)은 두 누적값(이번 · 직전)을 derivedFrom 으로 함께 — 누적 차분까지 손으로 검산할 수 있게.
    • 규칙마다 근거에 쓰는 지표를 RuleEvaluator.evidenceMetrics() 로 선언하고, seed 파라미터로 평가할 때 실제로 읽는 지표인지 계약 테스트로 확인(오타 · 낡은 선언 방지).
    • 지표의 분자 · 분모에 표준계정의 기준(basis: POINT · CUM · QTR)을 기록 — 계보가 금액으로 기준을 추측하지 않도록(1분기는 누적 = 분기라 금액만으로 구별 불가).
  2. CSV 내려받기 /api/v1/export/… — 경보 · 기업 지표 · 노출 · PF 사업장.
    • 열 이름 = JSON 필드 이름(API 와 같은 계약), UTF-8 BOM(엑셀 한글), RFC 4180(CRLF · 큰따옴표).
    • 수식 주입 방어 — OWASP CSV Injection 문서 확인: 글자 칸의 첫 글자가 = + - @ · 탭 · CR · LF · 전각 =+-@ 이면 ' 를 붙이고, 모든 글자 칸을 큰따옴표로 감싸 큰따옴표는 두 번 씀. 숫자 칸은 DB 숫자 열에서만 오므로 그대로(음수가 글자로 바뀌지 않게).
    • 경보는 행이 많아 DB 커서(fetchSize 1,000, 읽기 전용 트랜잭션)로 흘려 쓰고 50,000행 상한(X-Total-Count · X-Truncated). 나머지는 화면 서비스의 결과를 그대로 써서 화면과 같은 숫자.
    • IP 당 분당 30회 별도 한도(EXPORT_LIMIT_PER_MINUTE, 일반 API 1,200 과 따로).
  3. API 안내 화면 /developers — 엔드포인트 · curl 예시 · 근거 · 계보 필드 사전 · CSV 규칙 · v1 호환 정책: v1 안에서는 필드를 더하기만 하고(받는 쪽은 모르는 필드 무시), 이름 바꾸기 · 지우기 · 의미 변경은 /api/v2 로만. 열거 값은 늘어날 수 있음. 값이 없으면 0 대신 null + 사유 코드.

실데이터 확인 (2026-10-08, 규칙 10종 경보 하나씩)

규칙 계보
R-C01 · R-C02 · R-C03 지표 → 표준계정 3~4개 → 원천 줄 4~8줄, 모두 reproduced (예: R-C02 분기 영업이익 −151,733,878 = 반기 누적 183,873,810 − 1분기 누적 335,607,688)
R-C06 PF 지표 3개 → 자본총계 원천 줄 + PF 종합요약표(파서 v13 · 본문 서술 합계 대조)
R-R01 · R-R02 · R-R03 지역 지표 → 미분양 · 가격지수 · 실거래 · 가구 통계 행 → 통계 수집 실행
R-C04 · R-C05 · R-X01 공시 원문 · 구조화 값(보증 잔액 · 계약 지역) · 수주 지역의 미분양 지표

이 과정에서 공시 행의 수집 실행 ID 가 비어 있던 문제를 찾았다(VERIFICATION 100).

성능

계보 API 는 캐시가 없을 때 15~45 ms(재시작 직후 첫 호출 347 ms — 매핑 규칙 적재 · JIT), 캐시(10분, Job 이 끝나면 세대 무효화) 뒤 약 10 ms. 경보 CSV 595행 24~70 ms, 기업 지표 CSV 29~75 ms (edge 경유, 같은 기계).

한계

덧붙임 (2026-10-11, VERIFICATION 184 · 187) — v1 안에서 바꾼 두 가지 (결정 D1 · D2)