로컬 export API (v2)
로컬 export API는 현재(active) cycle 의 건강 데이터를 선택한 포맷(pdf | xml)으로 생성해 GCS(EU, europe-west3)에 업로드하고, 1분 만료 signed URL 을 반환하는 v2 endpoint입니다. ePA로 전송하지 않고 사용자가 직접 내려받도록 하는 LOCAL 채널이며, xml 은 ePA 정본과 동일한 FHIR/MIO Bundle 직렬화 결과입니다.
핵심
- 채널 = LOCAL: ePA 전송 없이 signed URL 로 다운로드만 제공합니다. ePA로 실제 전송하려면 ePA 전송(
POST /epa)을 사용합니다. - 기본 포맷 =
pdf:format미지정 시pdf. (ePA 전송용POST /epa는 기본xml.) xml= ePA MIO Bundle:xml선택 시 ePA로 넘기는 것과 동일한 FHIR/MIO Bundle 이 생성됩니다.- PII 보호: 응답 바디의
downloadUrl은 로그에서 제외됩니다(bodyExcludedPaths('*health-data/export*')).
인증 정책 (v2 공통)
- 인증 채널은
Authorization: Bearer <accessToken>한 줄(JwtAuthGuard). - 신원은 access token payload(
userId)로 확정하므로 요청 본문에 사용자 식별자를 넣지 않습니다.
POST /v2/health-data/export/local ⭐
현재(active) cycle 데이터를 선택한 포맷으로 생성해 다운로드용 signed URL 을 반환합니다.
- Path:
POST /v2/health-data/export/local - 인증: User Access Token (
JwtAuthGuard) - Rate Limit: 60/분 (전역 default)
- 🔗 라이브 명세 (Swagger UI): dev
Request
| Header | Value |
|---|---|
Authorization | Bearer <accessToken> (필수) |
Request Body — LocalExportRequestDto
| 필드 | 타입 | 필수 | 제약 | 설명 |
|---|---|---|---|---|
format | string | No | pdf | xml | export 포맷. 미지정 시 pdf. xml 은 ePA 용 FHIR/MIO Bundle |
{
"format": "pdf"
}
동작
JwtAuthGuard로 access token을 검증하고 payload에서userId를 확정합니다.- 사용자의 현재(active) cycle 데이터를 조회해 export 도메인 모델을 생성합니다 — active cycle 없으면 404(
EXPORT_USER_INFO_NOT_FOUND), 내보낼 데이터 없으면 404(EXPORT_NO_DATA). - 선택 포맷(
pdf|xml)으로 산출물을 렌더링합니다. - GCS(EU, europe-west3)에 업로드하고 1분 만료 v4 signed URL 을 발급합니다.
downloadUrl·fileName·expiresAt을 반환합니다. 렌더/업로드 실패 시 FAILED export 로그가 먼저 기록됩니다.
Response 200 OK — LocalExportResponseDto
{
"downloadUrl": "https://storage.googleapis.com/dta-cloud-de-dev-health-data-export/health-export/...&X-Goog-Signature=...",
"fileName": "health-export-20260601.pdf",
"expiresAt": 1748768460000
}
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
downloadUrl | string | Yes | v4 signed URL (1분 만료) |
fileName | string | Yes | 다운로드 파일명 |
expiresAt | number | Yes | signed URL 만료 시각 unix timestamp(ms, 13자리) |
Errors
| HTTP | code | message | 발생 조건 |
|---|---|---|---|
| 400 | 1001 | Bad Request | format 이 pdf/xml 외 값 (ValidationPipe) |
| 401 | 1000 | Authentication token not found | Bearer access token 미제공 (JwtAuthGuard) |
| 401 | 1000 | Invalid or expired token | access token 만료/서명·검증 실패 (JwtAuthGuard) |
| 401 | 1000 | Invalid token: missing subject (user ID) | payload에 userId(sub) 없음 |
| 401 | 1000 | User ID not found in request | guard 통과했으나 req.user.userId 부재 (컨트롤러) |
| 404 | 21100 | EXPORT_USER_INFO_NOT_FOUND | 요청 사용자의 활성(active) cycle 없음 |
| 404 | 21102 | EXPORT_NO_DATA | 내보낼 임상 데이터 없음 (model.isEmpty()) |
| 500 | 21200 | EXPORT_SERIALIZATION_FAILED | 산출물 생성 실패 — 도메인 모델 생성 또는 PDF/XML 렌더 |
| 500 | 21201 | EXPORT_UPLOAD_FAILED | GCS 업로드 / signed URL 발급 실패 |
| 500 | 1000 | An unexpected error occurred | 그 외 미처리 서버 오류 (global exception filter fallback) |
실패(500) 시 FAILED export 로그가 먼저 기록됩니다.
EXPORT_NO_DATA(21102)는 무로그입니다.
다음 단계
- ePA로 실제 전송: ePA 전송 (
POST /epa). - 최근 export 결과 확인: 최신 export 기록 조회 (
GET .../local/latest). - 자동 주기 전송 설정: ePA 주기 export 스케줄.