POST /api/v1/ai/analyze/{rceptNo}/reveal
의도
분석 결과를 열람한다. 처음 reveal 시 quota를 차감하고 결과를 반환한다. 이미 reveal한 공시는 재차감 없이 반환 (재진입 무료).
인증
- Bearer JWT 필수
- X-Firebase-AppCheck 헤더 —
APP_CHECK_ENFORCEMENT=strict(prod 기본) 시 필수, 없으면 403.soft(기본값) 시 없어도 통과(로그만).
strict 모드에서는 직접 curl 호출 불가 — App Check 토큰은 실제 앱/디바이스에서만 발급됨. soft 모드(로컬
.env.local기본)에서는 헤더 없이 curl 테스트 가능.
입력
- Path:
rceptNo— 14자리 공시 접수번호 - Body: 없음
응답
200 OK — reveal 성공
json
{
"status": "OK",
"newly_revealed": true,
"is_short": false,
"result": {
"summary": "...",
"key_points": ["...", "..."],
"sentiment": "positive",
"model": "RedHatAI/Qwen3.6-35B-A3B-NVFP4"
}
}newly_revealed: false면 이미 reveal한 공시 — quota 차감 없이 반환.
409 Conflict — 분석 미완료 / 본문 인덱싱 대기
json
{ "status": "NOT_READY", "message": "분석이 아직 완료되지 않았어요. 잠시 후 다시 시도해주세요." }
{ "status": "BODY_PENDING", "message": "DART 본문 등록을 기다리는 중이에요. 보통 몇 시간 내 분석 가능해요." }NOT_READY— 일반 PENDING/PROCESSING (분석 중).BODY_PENDING— DART OpenAPIstatus=014(본문 미존재) 응답 + 24h 이내. BodyRecoveryWorker (5분 주기) 가 회수 시도 중. FE 는 "DART 본문 등록 대기 중" 메시지 + 시계 아이콘으로 일반 NOT_READY 와 시각적 분기 (PR #82, 2026-05-13).
422 Unprocessable Entity — 분석 불가 (본문 영구 부재)
json
{ "status": "UNAVAILABLE", "message": "이 공시는 DART 가 본문을 제공하지 않아 분석할 수 없어요." }analysis_cache.status='FAILED' AND retry_count >= UnavailableRetryThreshold (=90). BODY_PENDING 24h 경과 또는 viewer fallback 도 본문 미회수 시 MarkFailedPermanent 마킹. FE 는 quota 차감 없이 "본문 없어 분석 불가" 메시지 표시. backend internal/ai/handler.go 의 Reveal 핸들러 Unavailable 분기.
429 Too Many Requests — quota 소진
json
{
"status": "QUOTA_EXHAUSTED",
"can_watch_ad": true,
"message": "이번 달 무료 AI 분석을 모두 사용했어요. 광고를 시청하면 분석을 더 볼 수 있어요."
}can_watch_ad: false이면 광고 월 cap도 초과 — 다음 달까지 불가.
401 Unauthorized — JWT 없음
403 Forbidden — App Check 토큰 없음/유효하지 않음
비즈니스 메모
- 짧은 공시(is_short=true)는 quota 차감 없이 반환
user_revealed_disclosures테이블에 (user_id, rcept_no) 기록 → 재진입 판단- quota 차감 + reveal 기록은 단일 트랜잭션
- App Check 미들웨어:
POST /api/v1/ai/analyze/{rceptNo}/reveal에만 적용 (다른 엔드포인트 제외)