Skip to content

Screen: DisclosureDetail (공시 상세)

특정 공시 한 건의 상세 화면. AI 분석 카드 (lazy reveal) + 메타 + 이전 공시 list (App).

💡 시각 미리보기:

진입 경로

  • App: dashboard 의 DisclosureItem 탭 / push 알림 / company detail 의 PreviousDisclosuresList 탭
  • Web: dashboard (/) 의 DisclosureItem 링크 / 공시 SNS 공유 링크 / 검색 엔진

URL: /disclosures/[rceptNo]

플랫폼별 차이

항목App (Flutter)Web (Next.js)
인증로그인 시 풀기능, 비로그인은 requireAuth 게이트비로그인 한정 (로그인 UI 없음)
AnalysisCard풀버전 — reveal / 광고 / 피드백 mechanicsmeta only — 요약만 (일부 마스킹)
Quota 표시QuotaIndicator (HP bar) 하위없음
AuthGaterequireAuth 흐름 (reveal / feedback 트리거 시)없음
보상형 광고광고 시청 시 quota 1회 회복없음
이전 공시 listPreviousDisclosuresList (같은 종목 N건)없음
AppCTA없음"앱에서 더 자세히 보기" 인라인
DART 원문in-app browser sheettarget=_blank 외부 링크
Renderingclient-side (Riverpod)SSR + ISR (revalidate=300)

App — 화면 구성

영역컴포넌트조건
AppBar← back + "공시 상세"항상
HeaderCardcorp 칩 + report name + meta list + DART 원문 보기 CTA항상
AnalysisCardAI 분석 (M1~M9 / W1~W5 상태 분기)항상
QuotaIndicatorHP bar항상
PreviousDisclosuresList같은 종목 이전 공시 list데이터 있을 때

App — 상태 분기 (전체 화면)

  • D1. 로딩 — spinner + "공시 정보를 불러오는 중..."
  • D2. 에러 — 메시지 (error ?? '공시를 찾을 수 없습니다.')
  • D3. 정상 — Header + AnalysisCard + Quota + PreviousList

App — AnalysisCard 상태 (M1~M9 / W1~W5)

AnalysisCard 컴포넌트 자체 spec: components/analysis-card.html. 화면 단위에서는 다음 흐름:

  • M1. 분석 준비/진행 중 (PENDING · PROCESSING) — shimmer 스켈레톤 + "분석 중" 배지. PENDING 과 PROCESSING 은 UI 를 구분하지 않고 동일한 shimmer 로 처리 (폴링으로 자동 갱신).
  • M2. 본문 등록 대기 (BODY_PENDING) — "DART 본문 등록을 기다리는 중이에요." + "정기보고서·정정 공시는 DART 인덱싱이 늦어질 수 있어요. 보통 몇 시간 내 분석이 가능해져요." (_BodyPendingBadge). status=014 + 24h 이내 → domain-disclosure 참조
  • M3. 분석 완료, 미 reveal — Summary 줄 (이미 동봉) + "AI 분석 보기 (1회 차감)" CTA → reveal flow
  • M4. Reveal 완료 — 본문 분석 풀 노출 + feedback 인라인
  • M5. Quota 소진 — Summary + "이번 주 무료 AI 분석을 모두 사용했어요." + 광고 시청 CTA ("광고 보고 분석 보기"). 광고 보상까지 소진 시 "이번 주 광고 보상 한도까지 모두 사용했어요. 다음 주에 다시 만나요."
  • M6. Reveal 사용 — quota 1회 차감 → POST /api/v1/ai/analyze/{rceptNo}/reveal
  • M7. 광고 시청 (보상형)RewardedAdController.showAd() → quota 1회 회복
  • M8. 짧은 공시 (isShort) — reveal 안 함, summary 자체가 본문 역할
  • M9. 분석 불가 (UNAVAILABLE) — "아직 본문을 가져오지 못했어요." + "공시 본문이 확인되는 대로 AI가 분석해드릴게요. 급하시면 DART 원문에서 먼저 확인할 수 있어요." (BODY_PENDING 24h 경과 / 4xx·5xx · 알 수 없는 예외 fallback)
  • W1~W5: AuthGate / 네트워크 에러 / 재시도 등 — flow-auth-gate spec 참조

App — 진입 시 API 호출

GET /api/v1/disclosures/{rceptNo}        → DisclosureDetail (corp / report_name / meta / previous)
GET /api/v1/ai/analyze/{rceptNo}         → AnalyzeMeta (status / isShort / alreadyRevealed)
GET /api/v1/quota                        → QuotaStatus (HP bar)

App — 액션

Reveal (AI 분석 보기)

  1. AnalysisCard CTA 탭 → requireAuth 통과 시
  2. POST /api/v1/ai/analyze/{rceptNo}/reveal
  3. 성공: analysis 본문 노출 + alreadyRevealed=true + quota 1 차감
  4. 실패 (quota 소진): M5 상태로 → 광고 시청 옵션
  5. 실패 (인증 만료): flow-auth-gate → 재시도

광고 시청 (Rewarded Ad)

  1. M5 상태 CTA 탭 → RewardedAdController.showAd()
  2. 시청 완료 → quota +1 (음수 weeklyUsed 가능, M5 → M3 회복)
  3. 시청 중간 종료 → 회복 없음, M5 유지
  4. 자동으로 retryAfterAd() 호출 → analyze meta refetch

피드백 (Reveal 후)

  1. 👍 / 👎 (binary) 선택 → requireAuth 통과 시. 👎 선택 시 사유 태그 선택 시트(FeedbackTagSheet) 오픈
  2. PUT /api/v1/ai/analyze/{rceptNo}/feedback {rating, tags} (upsert) — rating1(👍) 또는 -1(👎)
  3. UI 인라인 토스트 ("피드백 감사합니다"). 재탭 시 토글 해제 → DELETE /api/v1/ai/analyze/{rceptNo}/feedback

피드백 삭제

  1. 본인이 남긴 피드백 영역의 X 탭
  2. DELETE /api/v1/ai/analyze/{rceptNo}/feedback

DART 원문 보기

App 내 in-app browser sheet (InAppBrowserSheet) 로 DART 공식 URL 오픈.

이전 공시 탭

PreviousDisclosuresList 의 item 탭 → context.push('/disclosures/{otherRceptNo}') (라우터 재진입).


Web — 화면 구성

영역컴포넌트조건
AppBar← back to / + "공시 상세"항상
HeaderCardcorp Link (/?corp={corpCode} — 대시보드 종목 필터) + report name + meta list + DART 원문 외부 링크항상
AnalysisCardmeta 기반 (요약만, 본문 마스킹)항상
AppCTA인라인 "앱에서 더 자세히 보기" + App Store / Play disabled 버튼 (준비 중) — 모달 X항상

Web — 상태 분기

비로그인 한정 단일 상태:

  • D0. 로딩 — 카드 진입(/disclosures/[rceptNo] SSR fetch) 동안 loading.tsx 스켈레톤(AppBar + HeaderCard/AnalysisCard 자리) 즉시 표시 → "멈춘 듯" 체감 제거
  • D1. 404fetchDisclosure null → Next.js notFound() → 404 페이지
  • D2. 정상 — Header + AnalysisCard (요약만) + AppCTA

Web — AnalysisCard 상태 (Web 전용 subset)

  • W-M1. 분석 안 됨 — "AI가 곧 분석할 예정이에요" (App 과 동일 카피)
  • W-M2. 분석 중 — spinner + 카피
  • W-M3. 분석 완료 — Summary 줄만 노출, "전체 분석은 앱에서" 안내 박스 (reveal 없음)
  • W-M8. 짧은 공시 — summary 풀 노출 (App 과 동일)
  • W-M9. 분석 불가 — 카피만

Web — 진입 시 API 호출

SSR + ISR (revalidate=300):

GET /api/v1/disclosures/{rceptNo}        → Disclosure
GET /api/v1/ai/analyze/{rceptNo}         → AnalyzeMeta (요약만 사용)

Web — 액션

DART 원문 보기

<a target=_blank> 외부 링크 (https://dart.fss.or.kr/dsaf001/main.do?rcpNo={rceptNo}).

AppCTA (인라인)

<AppCTA /> 가 본문 하단에 인라인 렌더 — "앱에서 더 자세히 보기" + App Store / Play disabled 버튼 (준비 중). 모달/핸들러 없음, 단순 표시.

공시 카드 SNS 공유

generateMetadata 가 OpenGraph 채움 → {corp_name} - {report_name} | 공시한입 으로 카카오톡 / 트위터 미리보기.


액션 카탈로그 (전체)

액션endpointmethodrequestresponseAppWeb
공시 메타 조회/api/v1/disclosures/{rceptNo}GETDisclosureDetail
분석 메타 조회/api/v1/ai/analyze/{rceptNo}GETAnalyzeMeta✅ (요약만)
Reveal 본문 분석/api/v1/ai/analyze/{rceptNo}/revealPOSTAnalysis
피드백 제출 (upsert)/api/v1/ai/analyze/{rceptNo}/feedbackPUT{rating: 1|-1, tags}204
피드백 삭제/api/v1/ai/analyze/{rceptNo}/feedbackDELETE204
광고 보상/api/v1/quota/ad-rewardPOSTQuotaStatus
Quota 조회/api/v1/quotaGETQuotaStatus

Edge cases

App

  • 인증 만료 (401) — reveal/feedback 시점: requireAuth 가 AuthGate 모달 띄움 (자세히 flow-auth-gate.md)
  • 광고 SDK 미로드: Rewarded button disabled, 자동 재시도
  • 광고 중간 종료: quota 회복 X, M5 유지
  • race — reveal 중 quota 소진 통보 (다른 디바이스): BE 가 reveal 실패 응답 → M5 로 전환
  • PreviousDisclosuresList 빈 결과: 섹션 자체 hide (헤더 X)

Web

  • 공시 not found (rceptNo 잘못됨): notFound() → Next.js 404
  • 백엔드 403 (CF Worker secret 없음): getJSONSoft null 삼킴, AnalysisCard 빈 상태
  • OpenGraph metadata 빈 응답: title 만 "공시 상세 | 공시한입" 으로 fallback
  • ISR cache stale: 5분(300s) 후 revalidate, 그 사이는 stale-while-revalidate

관련 docs

Status

  • ✅ App — 모든 상태 / API / 액션 구현 일치
  • ✅ Web — meta only 모드 + AppCTA 구현 일치
  • 📋 광고 보상 시 quota 회복 UI 깜빡임 — 별도 backlog