{"openapi":"3.0.3","info":{"title":"chart-api","description":"진료 차트 PDF·건강검진·케이스 이미지 vet-report 호환 API. 대부분 Bearer CHART_APP_API_KEY. PDF export는 인프로세스 playwright-core + @sparticuz/chromium; PLAYWRIGHT_PDF_SERVICE_URL 이 있으면 원격 우선. 로컬은 PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH 권장. 건강검진 run 인쇄 …/runs/{runId}/report/print, 공유 …/review/health-checkup/{token}/print — SHARE 템플릿· env 참고. Storage: pdf-uploads·hospital-assets. PDF 업로드 경로 extract-uploads/YYYY-MM-DD/{uuid}-{파일}.pdf.","version":"1.0.0"},"servers":[{"url":"/","description":"배포 호스트 루트(예: Vercel 프로젝트 URL)"}],"tags":[{"name":"A. PDF · 텍스트 버킷팅"},{"name":"B. 런 · 추출 · 평가 · 케이스 이미지"},{"name":"C. 리포트 · 건강검진 PDF"},{"name":"D. 생성 콘텐츠 · 공유 리뷰"},{"name":"E. 건강상식 · OCR · 참고문헌"},{"name":"F. 히스토리"},{"name":"G. 관리자 · 크론"}],"paths":{"/api/text-bucketing/upload-url":{"post":{"tags":["A. PDF · 텍스트 버킷팅"],"summary":"PDF 업로드용 서명 URL 발급 — signedUrl 은 가능 시 절대 URL · extract-uploads/… · pdf-uploads","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/text-bucketing":{"post":{"tags":["A. PDF · 텍스트 버킷팅"],"summary":"텍스트 버킷팅 전체 파이프라인 — multipart 권장 · 필수 chartType · 병원 UUID는 hospitalId 또는 hospital_id · file 또는 storageBucket+storagePath(pdf-uploads, extract-uploads/) · 선택 chartPasteText·efriendsChartBlocksJson · LLM 미설정 400 · 30MB · runId·friendlyId · 스캔 PDF 422","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/runs/{runId}/extraction":{"patch":{"tags":["B. 런 · 추출 · 평가 · 케이스 이미지"],"summary":"추출 결과 섹션별 PATCH","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/runs/{runId}/assessment":{"get":{"tags":["B. 런 · 추출 · 평가 · 케이스 이미지"],"summary":"AI 소견 조회 · 생성 — POST는 GEMINI_API_KEY 필요, 없으면 503","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]},"post":{"tags":["B. 런 · 추출 · 평가 · 케이스 이미지"],"summary":"AI 소견 조회 · 생성 — POST는 GEMINI_API_KEY 필요, 없으면 503","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/image-case":{"get":{"tags":["B. 런 · 추출 · 평가 · 케이스 이미지"],"summary":"케이스 이미지 목록 + 서명 URL — 쿼리 runId 필수. 미리보기 서명 TTL 7일. 버킷 SUPABASE_IMAGE_CASE_BUCKET(선택, 기본 case-image)","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]},"delete":{"tags":["B. 런 · 추출 · 평가 · 케이스 이미지"],"summary":"이미지 삭제 — 쿼리 runId, imageId","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/ocr":{"post":{"tags":["E. 건강상식 · OCR · 참고문헌"],"summary":"범용 OCR — Vision 미연동 시 503","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/report/generate":{"post":{"tags":["C. 리포트 · 건강검진 PDF"],"summary":"리포트 템플릿 생성(Gemini)","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/report/export":{"post":{"tags":["C. 리포트 · 건강검진 PDF"],"summary":"리포트 PDF 바이너리 — POST { printUrl } · 인프로세스 Playwright (원격 URL 있으면 우선)","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/report/health-checkup/preview":{"post":{"tags":["C. 리포트 · 건강검진 PDF"],"summary":"건강검진 미리보기(Gemini)","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/report/health-checkup/export":{"get":{"tags":["C. 리포트 · 건강검진 PDF"],"summary":"건강검진 PDF — GET ?runId=&exportRequestId= · POST JSON 또는 form(runId, exportRequestId) · 상관 ID: 헤더 X-Chart-Export-Request-Id 우선 · Playwright · export-debug","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]},"post":{"tags":["C. 리포트 · 건강검진 PDF"],"summary":"건강검진 PDF — GET ?runId=&exportRequestId= · POST JSON 또는 form(runId, exportRequestId) · 상관 ID: 헤더 X-Chart-Export-Request-Id 우선 · Playwright · export-debug","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/report/health-checkup/export-debug":{"post":{"tags":["C. 리포트 · 건강검진 PDF"],"summary":"건강검진 PDF export 진단(JSON) — Bearer 필수 · { runId, probePrintUrl? } · 환경 플래그·인쇄 URL fetch·비밀값 미포함 · Failed to fetch 원인 좁히기","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/report/health-checkup/export-by-share":{"post":{"tags":["C. 리포트 · 건강검진 PDF"],"summary":"공유 토큰으로 PDF — 토큰 경로 인쇄 URL · SHARE 템플릿 또는 VET_REPORT_PUBLIC_ORIGIN","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[]}},"/api/content/generate":{"post":{"tags":["D. 생성 콘텐츠 · 공유 리뷰"],"summary":"health_checkup | blog_post 생성","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/content":{"get":{"tags":["D. 생성 콘텐츠 · 공유 리뷰"],"summary":"generated_run_content 목록 — 쿼리 runId","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]},"patch":{"tags":["D. 생성 콘텐츠 · 공유 리뷰"],"summary":"콘텐츠 upsert","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]},"delete":{"tags":["D. 생성 콘텐츠 · 공유 리뷰"],"summary":"단건 삭제","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/content/health-checkup/review-share":{"post":{"tags":["D. 생성 콘텐츠 · 공유 리뷰"],"summary":"외부 리뷰용 공유 링크 발급","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]},"get":{"tags":["D. 생성 콘텐츠 · 공유 리뷰"],"summary":"토큰으로 페이로드 조회 — 공개 — 쿼리 token","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[]},"patch":{"tags":["D. 생성 콘텐츠 · 공유 리뷰"],"summary":"토큰으로 검토 반영 — 공개 — 바디에 token","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[]}},"/api/content/reference-extract":{"post":{"tags":["D. 생성 콘텐츠 · 공유 리뷰"],"summary":"참고문헌 추출 — multipart file= 또는 JSON · fileName·mimeType·fullText·rows","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/health-knowledge/generate":{"post":{"tags":["E. 건강상식 · OCR · 참고문헌"],"summary":"건강상식 HTML(Gemini)","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/history":{"get":{"tags":["F. 히스토리"],"summary":"최근 런 목록 · ?runId= 상세","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/history/{runId}":{"delete":{"tags":["F. 히스토리"],"summary":"런 + 연관 데이터 삭제","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/admin/hospitals":{"get":{"tags":["G. 관리자 · 크론"],"summary":"병원 목록","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]},"post":{"tags":["G. 관리자 · 크론"],"summary":"병원 생성","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/admin/hospitals/{id}":{"patch":{"tags":["G. 관리자 · 크론"],"summary":"병원 수정","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]},"delete":{"tags":["G. 관리자 · 크론"],"summary":"병원 삭제","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/admin/hospitals/{id}/assets":{"post":{"tags":["G. 관리자 · 크론"],"summary":"logo | seal 업로드","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/admin/basic-info-normalization":{"get":{"tags":["G. 관리자 · 크론"],"summary":"종·품종 빈도(정규화 통계)","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerChartKey":[]}]}},"/api/cron/recompute-basic-info-ages":{"get":{"tags":["G. 관리자 · 크론"],"summary":"나이 재계산 크론 — CRON_SECRET 설정 시 Bearer 필요","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerCronSecret":[]}]},"post":{"tags":["G. 관리자 · 크론"],"summary":"나이 재계산 크론 — CRON_SECRET 설정 시 Bearer 필요","responses":{"200":{"description":"성공 (일부 엔드포인트는 JSON 본문 형식 상이)"},"400":{"description":"잘못된 요청"},"401":{"description":"인증 실패"},"403":{"description":"권한 없음"},"503":{"description":"미구현·키 미설정 등 — 서버 안내 JSON"}},"security":[{"BearerCronSecret":[]}]}}},"components":{"securitySchemes":{"BearerChartKey":{"type":"http","scheme":"bearer","description":"환경 변수 CHART_APP_API_KEY 와 동일한 값"},"BearerCronSecret":{"type":"http","scheme":"bearer","description":"환경 변수 CRON_SECRET 과 동일한 값"}}}}