Questionnaire API 엔드포인트
목차
- 관련 문서
- 접근 권한 매트릭스
- 설문 관리 API
- 설문 문항 관리 API
- 설문 회차 관리 API
- 설문 응답 제출 API
- 사용자 다음 설문 조회 API
- 7. 설문 결과 관리 API
- 8. 모바일 캐싱 API
- 9. 데이터 관리 및 개인정보 보호 API (GDPR 준수)
- 오류 코드
- 변경 이력
관련 문서
- Questionnaire 도메인 요구사항
- Questionnaire 도메인 비즈니스 규칙
- Questionnaire 도메인 모델
- Questionnaire 도메인 이벤트 스토밍
- 설문 조회 및 응답 흐름
접근 권한 매트릭스
| 엔드포인트 | 시스템 관리자 | 일반 사용자 | 서비스 계정 | 비고 |
|---|---|---|---|---|
| POST /v1/questionnaires | ✓ | ✘ | ✘ | 관리자만 설문 생성 가능 |
| GET /v1/questionnaires | ✓ | ✓ | ✓ | 모든 설문 목록 조회 |
GET /v1/questionnaires/{id} | ✓ | ✓ | ✓ | 설문 정보 조회 |
PATCH /v1/questionnaires/{id} | ✓ | ✘ | ✘ | 관리자만 설문 수정 가능 |
DELETE /v1/questionnaires/{id} | ✓ | ✘ | ✘ | 관리자만 설문 삭제 가능 |
POST /v1/questionnaires/{id}/versions | ✓ | ✘ | ✘ | 관리자만 새 버전 생성 가능 |
PATCH /v1/questionnaires/{id}/versions/{version}/activate | ✓ | ✘ | ✘ | 관리자만 버전 활성화 가능 |
PATCH /v1/questionnaires/{id}/versions/{version}/deactivate | ✓ | ✘ | ✘ | 관리자만 버전 비활성화 가능 |
GET /v1/questionnaires/{id}/versions | ✓ | ✘ | ✓ | 버전 목록 조회 |
POST /v1/questionnaires/{id}/questions | ✓ | ✘ | ✘ | 관리자만 문항 생성 가능 |
GET /v1/questionnaires/{id}/questions | ✓ | ✓ | ✓ | 설문 문항 목록 조회 |
GET /v1/questions/{id} | ✓ | ✓ | ✓ | 문항 정보 조회 |
PATCH /v1/questions/{id} | ✓ | ✘ | ✘ | 관리자만 문항 수정 가능 |
DELETE /v1/questions/{id} | ✓ | ✘ | ✘ | 관리자만 문항 삭제 가능 |
POST /v1/questionnaires/{id}/rounds | ✓ | ✘ | ✘ | 관리자만 회차 생성 가능 |
GET /v1/questionnaires/{id}/rounds | ✓ | ✓ | ✓ | 회차 목록 조회 |
GET /v1/questionnaires/{id}/rounds/{roundId} | ✓ | ✓ | ✓ | 회차 정보 조회 |
PATCH /v1/questionnaires/{id}/rounds/{roundId} | ✓ | ✘ | ✘ | 관리자만 회차 수정 가능 |
PATCH /v1/questionnaires/{id}/rounds/{roundId}/status | ✓ | ✘ | ✘ | 관리자만 회차 상태 변경 가능 |
POST /v1/questionnaires/rounds/{roundId}/complete | ✓ | 자신만 | ✘ | 회차 완료 및 결과 요약 조회 |
GET /v1/questionnaires/rounds/{roundId}/cumulative-results | ✓ | 자신만 | ✓ | 회차 누적 결과 조회 |
POST /v1/questionnaires/{questionnaireId}/rounds/{roundId}/responses | ✓ | 자신의 응답만 | ✘ | 설문 전체 응답 제출 |
GET /v1/users/{userId}/questionnaire-results/{questionnaireId} | ✓ | 자신만 | ✓ | 설문 결과 조회 |
GET /v1/users/{userId}/questionnaire-history/{questionnaireId} | ✓ | 자신만 | ✓ | 결과 이력 조회 |
GET /v1/users/{userId}/questionnaire-charts/{questionnaireId} | ✓ | 자신만 | ✓ | 차트 데이터 조회 |
POST /v1/users/{userId}/questionnaire-reports | ✓ | 자신만 | ✘ | 종합 보고서 생성 요청 |
GET /v1/users/{userId}/questionnaire-reports/{reportId} | ✓ | 자신만 | ✓ | 보고서 상태 및 URL 조회 |
GET /v1/questionnaires/bundles/{bundleId} | ✓ | ✓ | ✓ | 특정 번들 버전 조회 (캐싱용) |
POST /v1/questionnaires/admin/users/{userId}/archive | ✓ | ✘ | ✘ | 사용자 설문 데이터 아카이빙 |
POST /v1/questionnaires/admin/users/{userId}/restore | ✓ | ✘ | ✘ | 사용자 설문 데이터 복원 |
DELETE /v1/questionnaires/admin/users/{userId}/data | ✓ | ✘ | ✘ | 사용자 설문 데이터 영구 삭제 |
POST /v1/questionnaires/admin/users/{userId}/anonymize | ✓ | ✘ | ✘ | 사용자 설문 데이터 익명화 |
| GET /v1/questionnaires/users/me/data-export | ✘ | ✓ | ✘ | 내 설문 데이터 추출 요청 |
GET /v1/questionnaires/admin/users/{userId}/data-export | ✓ | ✘ | ✘ | 특정 사용자 설문 데이터 추출 요청 |
GET /v1/questionnaires/bundles/{bundleId}/users/me/schedule/next-pending | ✘ | 자신만 | ✘ | 다음 진행할 설문 스케줄 조회 |
| GET /v1/questionnaires/users/me/results/all-rounds | ✘ | 자신만 | ✘ | 내 전체 회차 결과 조회 |
GET /v1/questionnaires/users/{userId}/results/all-rounds | ✓ | ✘ | ✓ | 사용자 전체 회차 결과 조회 (관리자용) |
참고:
- ✓: 접근 가능
- ✘: 접근 불가
- 자신만: 자신의 데이터에만 접근 가능
- 자신의 응답만: 자신이 참여한 응답에만 접근 가능
설문 관리 API
2.1 설문 생성
- HTTP 메서드: POST
- 경로: /v1/questionnaires
- Headers:
- Content-Type: application/json
- Authorization: Bearer
{adminToken}
요청 (Request)
{
"questionnaireType": "ISI",
"scoreCalculationType": "SUM",
"maxScore": 28,
"metadata": {
"estimatedTimeMinutes": 5,
"purpose": "불면증 증상의 심각도를 평가하기 위한 설문",
"recommendations": "조용한 환경에서 진행하세요",
"notes": "지난 2주간의 경험을 기준으로 응답하세요"
},
"translations": [
{
"language": "ko",
"title": "불면증 심각도 지수",
"description": "불면증 증상의 심각도를 평가하는 설문입니다."
},
{
"language": "en",
"title": "Insomnia Severity Index",
"description": "This questionnaire assesses the severity of insomnia symptoms."
},
{
"language": "de",
"title": "Schweregrad der Schlaflosigkeit",
"description": "Dieser Fragebogen bewertet den Schweregrad der Schlaflosigkeitssymptome."
}
]
}
응답 (Response)
- 성공 응답 (201 Created)
{
"id": "q_isi123",
"questionnaireType": "ISI",
"scoreCalculationType": "SUM",
"maxScore": 28,
"metadata": {
"estimatedTimeMinutes": 5,
"purpose": "불면증 증상의 심각도를 평가하기 위한 설문",
"recommendations": "조용한 환경에서 진행하세요",
"notes": "지난 2주간의 경험을 기준으로 응답하세요"
},
"translations": [
{
"id": "qt_ko123",
"language": "ko",
"title": "불면증 심각도 지수",
"description": "불면증 증상의 심각도를 평가하는 설문입니다."
},
{
"id": "qt_en123",
"language": "en",
"title": "Insomnia Severity Index",
"description": "This questionnaire assesses the severity of insomnia symptoms."
},
{
"id": "qt_de123",
"language": "de",
"title": "Schweregrad der Schlaflosigkeit",
"description": "Dieser Fragebogen bewertet den Schweregrad der Schlaflosigkeitssymptome."
}
],
"createdAt": 1715600400000,
"updatedAt": 1715600400000
}
- 오류 응답 (400 Bad Request)
{
"code": 9001,
"message": "INVALID_INPUT_DATA",
"detail": "요청 데이터가 유효하지 않습니다. (필수 필드 누락 또는 잘못된 형식)"
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "설문을 생성할 권한이 없습니다."
}
2.2 설문 정보 조회
- HTTP 메서드: GET
- 경로: /v1/questionnaires/
{id} - Headers:
- Authorization: Bearer
{accessToken} - Accept-Language: de-DE (기본값), en-US, ko-KR
- Authorization: Bearer
- Query Parameters:
- language: 응답 언어 (선택, 기본값: 사용자 선호 언어)
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "q_isi123",
"questionnaireType": "ISI",
"scoreCalculationType": "SUM",
"maxScore": 28,
"metadata": {
"estimatedTimeMinutes": 5,
"purpose": "불면증 증상의 심각도를 평가하기 위한 설문",
"recommendations": "조용한 환경에서 진행하세요",
"notes": "지난 2주간의 경험을 기준으로 응답하세요"
},
"translation": {
"language": "ko",
"title": "불면증 심각도 지수",
"description": "불면증 증상의 심각도를 평가하는 설문입니다."
},
"scoreLevels": [
{
"id": "sl_isi1",
"minScore": 0,
"maxScore": 7,
"translation": {
"language": "ko",
"label": "불면 증상이 거의 없음",
"chartLabel": "수면 상태 좋음",
"description": "해당 범위는 불면의 증상이 거의 없거나 매우 적은 경우를 나타냅니다.",
"feedback": "수면에 거의 문제가 없는 편입니다. 그러나 일상적인 수면 습관을 유지하고 스트레스를 관리하는 것이 중요합니다."
}
}
// ... 다른 점수 구간들
],
"createdAt": 1715600400000,
"updatedAt": 1715600400000
}
- 오류 응답 (404 Not Found)
{
"code": 9010,
"message": "QUESTIONNAIRE_NOT_FOUND",
"detail": "요청한 설문을 찾을 수 없습니다."
}
2.3 설문 목록 조회
- HTTP 메서드: GET
- 경로: /v1/questionnaires
- Headers:
- Authorization: Bearer
{accessToken} - Accept-Language: de-DE (기본값), en-US, ko-KR
- Authorization: Bearer
- Query Parameters:
- type: 설문 유형 필터 (선택)
- language: 응답 언어 (선택, 기본값: 사용자 선호 언어)
- page: 페이지 번호 (선택, 기본값: 1)
- pageSize: 페이지 크기 (선택, 기본값: 10)
응답 (Response)
- 성공 응답 (200 OK)
{
"items": [
{
"id": "q_isi123",
"questionnaireType": "ISI",
"translation": {
"language": "ko",
"title": "불면증 심각도 지수"
},
"maxScore": 28,
"metadata": {
"estimatedTimeMinutes": 5
},
"createdAt": 1715600400000
},
{
"id": "q_dbas123",
"questionnaireType": "DBAS16",
"translation": {
"language": "ko",
"title": "수면에 대한 비합리적 신념"
},
"maxScore": 10,
"metadata": {
"estimatedTimeMinutes": 8
},
"createdAt": 1715600400000
}
// ... 다른 설문들
],
"metadata": {
"totalCount": 6,
"currentPage": 1,
"pageSize": 10,
"totalPages": 1
}
}
2.4 설문 정보 수정
- HTTP 메서드: PATCH
- 경로: /v1/questionnaires/
{id} - Headers:
- Content-Type: application/json
- Authorization: Bearer
{adminToken}
요청 (Request) - 메타데이터 및 최대 점수 수정
{
"maxScore": 28,
"metadata": {
"estimatedTimeMinutes": 7,
"notes": "지난 2주간의 수면 경험을 바탕으로 응답해주세요."
}
}
요청 (Request) - 번역 정보 수정
{
"translations": [
{
"language": "ko",
"title": "불면증 심각도 지수 (ISI)",
"description": "불면증 증상의 심각도를 평가하는 설문입니다. 모든 질문에 답변해주세요."
}
]
}
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "q_isi123",
"questionnaireType": "ISI",
"scoreCalculationType": "SUM",
"maxScore": 28,
"metadata": {
"estimatedTimeMinutes": 7,
"purpose": "불면증 증상의 심각도를 평가하기 위한 설문",
"recommendations": "조용한 환경에서 진행하세요",
"notes": "지난 2주간의 수면 경험을 바탕으로 응답해주세요."
},
"translations": [
{
"id": "qt_ko123",
"language": "ko",
"title": "불면증 심각도 지수 (ISI)",
"description": "불면증 증상의 심각도를 평가하는 설문입니다. 모든 질문에 답변해주세요."
}
// ... 다른 언어 번역
],
"updatedAt": 1715600400000
}
- 오류 응답 (400 Bad Request)
{
"code": 9001,
"message": "INVALID_INPUT_DATA",
"detail": "요청 데이터가 유효하지 않습니다."
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "설문을 수정할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 9010,
"message": "QUESTIONNAIRE_NOT_FOUND",
"detail": "요청한 설문을 찾을 수 없습니다."
}
2.5 설문 삭제
- HTTP 메서드: DELETE
- 경로: /v1/questionnaires/
{id} - Headers:
- Authorization: Bearer
{adminToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"message": "설문이 성공적으로 삭제되었습니다.",
"id": "q_isi123",
"deletedAt": 1716034200000
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "설문을 삭제할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 9010,
"message": "QUESTIONNAIRE_NOT_FOUND",
"detail": "요청한 설문을 찾을 수 없습니다."
}
- 오류 응답 (409 Conflict)
{
"code": 9031,
"message": "QUESTIONNAIRE_CANNOT_BE_DELETED",
"detail": "해당 설문은 사용자 응답이 존재하여 삭제할 수 없습니다."
}
2.6 설문 새 버전 생성
- HTTP 메서드: POST
- 경로: /v1/questionnaires/
{id}/versions - Headers:
- Content-Type: application/json
- Authorization: Bearer
{adminToken}
요청 (Request)
{
"versionInfo": {
"versionNumber": "1.1.0",
"changelog": "문항 순서 변경 및 선택지 텍스트 개선",
"releaseNotes": "사용자 피드백을 반영하여 설문 문항을 더 명확하게 개선했습니다."
}
}
응답 (Response)
- 성공 응답 (201 Created)
{
"id": "q_isi124",
"questionnaireType": "ISI",
"version": "1.1.0",
"isActive": false,
"metadata": {
"estimatedTimeMinutes": 5,
"purpose": "불면증 증상의 심각도를 평가하기 위한 설문",
"versionInfo": {
"versionNumber": "1.1.0",
"releaseDate": 1715690500000,
"changelog": "문항 순서 변경 및 선택지 텍스트 개선"
}
},
"createdAt": 1715690500000,
"updatedAt": 1715690500000
}
- 오류 응답 (400 Bad Request)
{
"code": 9001,
"message": "INVALID_INPUT_DATA",
"detail": "요청 데이터가 유효하지 않습니다."
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "설문 버전을 생성할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 9010,
"message": "QUESTIONNAIRE_NOT_FOUND",
"detail": "요청한 설문을 찾을 수 없습니다."
}
- 오류 응답 (409 Conflict)
{
"code": 9021,
"message": "VERSION_ALREADY_EXISTS",
"detail": "해당 버전 번호가 이미 존재합니다."
}
2.7 설문 버전 활성화
- HTTP 메서드: PATCH
- 경로: /v1/questionnaires/
{id}/versions/{version}/activate - Headers:
- Authorization: Bearer
{adminToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "q_isi124",
"questionnaireType": "ISI",
"version": "1.1.0",
"isActive": true,
"activatedAt": 1715690600000,
"updatedAt": 1715690600000
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "설문 버전을 활성화할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 9020,
"message": "VERSION_NOT_FOUND",
"detail": "요청한 설문 버전을 찾을 수 없습니다."
}
- 오류 응답 (409 Conflict)
{
"code": 9023,
"message": "ANOTHER_VERSION_ACTIVE",
"detail": "다른 버전이 이미 활성화되어 있습니다. 먼저 해당 버전을 비활성화해야 합니다."
}
2.8 설문 버전 비활성화
- HTTP 메서드: PATCH
- 경로: /v1/questionnaires/
{id}/versions/{version}/deactivate - Headers:
- Authorization: Bearer
{adminToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "q_isi124",
"questionnaireType": "ISI",
"version": "1.1.0",
"isActive": false,
"deactivatedAt": 1715690700000,
"updatedAt": 1715690700000
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "설문 버전을 비활성화할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 9020,
"message": "VERSION_NOT_FOUND",
"detail": "요청한 설문 버전을 찾을 수 없습니다."
}
- 오류 응답 (409 Conflict)
{
"code": 9024,
"message": "NO_ACTIVE_VERSION",
"detail": "활성화된 버전이 없어 비활성화할 수 없습니다."
}
2.9 설문 버전 목록 조회
- HTTP 메서드: GET
- 경로: /v1/questionnaires/
{id}/versions - Headers:
- Authorization: Bearer
{accessToken} - Accept-Language: de-DE (기본값), en-US, ko-KR
- Authorization: Bearer
- Query Parameters:
- includeInactive: 비활성 버전 포함 여부 (선택, 기본값: false)
- page: 페이지 번호 (선택, 기본값: 1)
- pageSize: 페이지 크기 (선택, 기본값: 10)
응답 (Response)
- 성공 응답 (200 OK)
{
"questionnaireId": "q_isi123",
"questionnaireType": "ISI",
"versions": [
{
"id": "q_isi124",
"version": "1.1.0",
"isActive": true,
"metadata": {
"versionInfo": {
"versionNumber": "1.1.0",
"releaseDate": 1715690500000,
"changelog": "문항 순서 변경 및 선택지 텍스트 개선"
}
},
"createdAt": 1715690500000,
"activatedAt": 1715690600000
},
{
"id": "q_isi123",
"version": "1.0.0",
"isActive": false,
"metadata": {
"versionInfo": {
"versionNumber": "1.0.0",
"releaseDate": 1715600400000
}
},
"createdAt": 1715600400000,
"deactivatedAt": 1715690600000
}
],
"metadata": {
"totalCount": 2,
"currentPage": 1,
"pageSize": 10,
"totalPages": 1
}
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "설문 버전 목록을 조회할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 9010,
"message": "QUESTIONNAIRE_NOT_FOUND",
"detail": "요청한 설문을 찾을 수 없습니다."
}
설문 문항 관리 API
3.1 문항 생성
- HTTP 메서드: POST
- 경로: /v1/questionnaires/
{id}/questions - Headers:
- Content-Type: application/json
- Authorization: Bearer
{adminToken}
요청 (Request)
{
"orderIndex": 1,
"questionType": "LINEAR_SCALE",
"isRequired": true,
"metadata": {
"defaultValue": 5,
"minValue": 0,
"maxValue": 10,
"step": 1
},
"translations": [
{
"language": "ko",
"text": "최근 불면 증상으로 인한 어려움의 정도를 표시해주세요.",
"description": "0(전혀 어려움 없음)부터 10(매우 심각한 어려움)까지 선택하세요."
},
{
"language": "en",
"text": "Please rate the severity of your recent insomnia problem(s).",
"description": "Select from 0 (no difficulty) to 10 (very severe difficulty)."
},
{
"language": "de",
"text": "Bitte bewerten Sie den Schweregrad Ihrer jüngsten Schlaflosigkeitsprobleme.",
"description": "Wählen Sie von 0 (keine Schwierigkeiten) bis 10 (sehr schwere Schwierigkeiten)."
}
],
"options": [
{
"value": "0",
"orderIndex": 0,
"score": 0,
"translations": [
{
"language": "ko",
"text": "전혀 어려움 없음"
},
{
"language": "en",
"text": "No difficulty"
},
{
"language": "de",
"text": "Keine Schwierigkeiten"
}
]
},
// ... 다른 옵션들 (1-9)
{
"value": "10",
"orderIndex": 10,
"score": 10,
"translations": [
{
"language": "ko",
"text": "매우 심각한 어려움"
},
{
"language": "en",
"text": "Very severe difficulty"
},
{
"language": "de",
"text": "Sehr schwere Schwierigkeiten"
}
]
}
]
}
응답 (Response)
- 성공 응답 (201 Created)
{
"id": "q_123",
"questionnaireId": "q_isi123",
"orderIndex": 1,
"questionType": "LINEAR_SCALE",
"isRequired": true,
"metadata": {
"defaultValue": 5,
"minValue": 0,
"maxValue": 10,
"step": 1
},
"translations": [
{
"id": "qt_ko123",
"language": "ko",
"text": "최근 불면 증상으로 인한 어려움의 정도를 표시해주세요.",
"description": "0(전혀 어려움 없음)부터 10(매우 심각한 어려움)까지 선택하세요."
}
// ... 다른 언어 번역
],
"options": [
{
"id": "opt_0",
"value": "0",
"orderIndex": 0,
"score": 0,
"translations": [
{
"id": "optt_ko0",
"language": "ko",
"text": "전혀 어려움 없음"
}
// ... 다른 언어 번역
]
}
// ... 다른 옵션들
],
"createdAt": 1715600400000,
"updatedAt": 1715600400000
}
- 오류 응답 (400 Bad Request)
{
"code": 9001,
"message": "INVALID_INPUT_DATA",
"detail": "요청 데이터가 유효하지 않습니다."
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "문항을 생성할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 9010,
"message": "QUESTIONNAIRE_NOT_FOUND",
"detail": "요청한 설문을 찾을 수 없습니다."
}
3.2 문항 정보 조회
- HTTP 메서드: GET
- 경로: /v1/questions/
{id} - Headers:
- Authorization: Bearer
{accessToken} - Accept-Language: de-DE (기본값), en-US, ko-KR
- Authorization: Bearer
- Query Parameters:
- language: 응답 언어 (선택, 기본값: 사용자 선호 언어)
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "q_123",
"questionnaireId": "q_isi123",
"orderIndex": 1,
"questionType": "LINEAR_SCALE",
"isRequired": true,
"metadata": {
"defaultValue": 5,
"minValue": 0,
"maxValue": 10,
"step": 1
},
"translation": {
"language": "ko",
"text": "최근 불면 증상으로 인한 어려움의 정도를 표시해주세요.",
"description": "0(전혀 어려움 없음)부터 10(매우 심각한 어려움)까지 선택하세요."
},
"options": [
{
"id": "opt_0",
"value": "0",
"orderIndex": 0,
"score": 0,
"translation": {
"language": "ko",
"text": "전혀 어려움 없음"
}
}
// ... 다른 옵션들
],
"createdAt": 1715600400000,
"updatedAt": 1715600400000
}
- 오류 응답 (404 Not Found)
{
"code": 9004,
"message": "QUESTION_NOT_FOUND",
"detail": "요청한 문항을 찾을 수 없습니다."
}
3.3 문항 목록 조회
- HTTP 메서드: GET
- 경로: /v1/questionnaires/
{id}/questions - Headers:
- Authorization: Bearer
{accessToken} - Accept-Language: de-DE (기본값), en-US, ko-KR
- Authorization: Bearer
- Query Parameters:
- language: 응답 언어 (선택, 기본값: 사용자 선호 언어)
응답 (Response)
- 성공 응답 (200 OK)
{
"items": [
{
"id": "q_123",
"orderIndex": 1,
"questionType": "LINEAR_SCALE",
"isRequired": true,
"translation": {
"language": "ko",
"text": "최근 불면 증상으로 인한 어려움의 정도를 표시해주세요."
},
"metadata": {
"defaultValue": 5,
"minValue": 0,
"maxValue": 10
}
},
{
"id": "q_124",
"orderIndex": 2,
"questionType": "CHOICE",
"isRequired": true,
"translation": {
"language": "ko",
"text": "수면 문제가 당신의 일상 기능에 얼마나 방해가 되고 있습니까?"
},
"metadata": {}
}
// ... 다른 문항들
],
"metadata": {
"totalCount": 7,
"questionnaireId": "q_isi123"
}
}
- 오류 응답 (404 Not Found)
{
"code": 9010,
"message": "QUESTIONNAIRE_NOT_FOUND",
"detail": "요청한 설문을 찾을 수 없습니다."
}
3.4 문항 정보 수정
- HTTP 메서드: PATCH
- 경로: /v1/questions/
{id} - Headers:
- Content-Type: application/json
- Authorization: Bearer
{adminToken}
요청 (Request) - 문항 기본 정보 수정
{
"orderIndex": 2,
"isRequired": true,
"metadata": {
"defaultValue": 3,
"minValue": 0,
"maxValue": 10
}
}
요청 (Request) - 번역 정보 수정
{
"translations": [
{
"language": "ko",
"text": "최근 2주간 불면 증상으로 인한 어려움의 정도를 표시해주세요.",
"description": "0(전혀 어려움 없음)부터 10(매우 심각한 어려움)까지 선택하세요."
}
]
}
요청 (Request) - 옵션 정보 수정
{
"options": [
{
"id": "opt_0",
"value": "0",
"score": 0,
"translations": [
{
"language": "ko",
"text": "전혀 어려움이 없음"
}
]
}
]
}
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "q_123",
"questionnaireId": "q_isi123",
"orderIndex": 2,
"questionType": "LINEAR_SCALE",
"isRequired": true,
"metadata": {
"defaultValue": 3,
"minValue": 0,
"maxValue": 10,
"step": 1
},
"translations": [
{
"id": "qt_ko123",
"language": "ko",
"text": "최근 2주간 불면 증상으로 인한 어려움의 정도를 표시해주세요.",
"description": "0(전혀 어려움 없음)부터 10(매우 심각한 어려움)까지 선택하세요."
}
// ... 다른 언어 번역
],
"options": [
{
"id": "opt_0",
"value": "0",
"orderIndex": 0,
"score": 0,
"translations": [
{
"id": "optt_ko0",
"language": "ko",
"text": "전혀 어려움이 없음"
}
// ... 다른 언어 번역
]
}
// ... 다른 옵션들
],
"updatedAt": 1715600400000
}
- 오류 응답 (400 Bad Request)
{
"code": 9001,
"message": "INVALID_INPUT_DATA",
"detail": "요청 데이터가 유효하지 않습니다."
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "문항을 수정할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 9004,
"message": "QUESTION_NOT_FOUND",
"detail": "요청한 문항을 찾을 수 없습니다."
}
3.5 문항 삭제
- HTTP 메서드: DELETE
- 경로: /v1/questions/
{id} - Headers:
- Authorization: Bearer
{adminToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"message": "문항이 성공적으로 삭제되었습니다.",
"id": "q_123",
"questionnaireId": "q_isi123",
"deletedAt": "2025-05-15T15:00:00.000Z"
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "문항을 삭제할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 9004,
"message": "QUESTION_NOT_FOUND",
"detail": "요청한 문항을 찾을 수 없습니다."
}
- 오류 응답 (409 Conflict)
{
"code": 9041,
"message": "QUESTION_CANNOT_BE_DELETED",
"detail": "해당 문항은 사용자 응답이 존재하여 삭제할 수 없습니다."
}
설문 회차 관리 API
설문 결과 및 피드백 관리 규칙
4.1 회차 생성
- HTTP 메서드: POST
- 경로: /v1/questionnaires/
{questionnaireId}/rounds - Headers:
- Content-Type: application/json
- Authorization: Bearer
{accessToken}
요청 (Request)
{
"title": "2025년 7월 건강 설문",
"startDate": 1719792000000,
"endDate": 1722470399000,
"status": "DRAFT",
"properties": {
"isRequired": true,
"allowAnonymous": false,
"maxAttempts": 1
}
}
응답 (Response)
- 성공 응답 (201 Created)
{
"id": "round_789",
"questionnaireId": "quest_123",
"title": "2025년 7월 건강 설문",
"startDate": 1719792000000,
"endDate": 1722470399000,
"status": "DRAFT",
"properties": {
"isRequired": true,
"allowAnonymous": false,
"maxAttempts": 1
},
"createdAt": 1714538000000,
"updatedAt": 1714538000000
}
- 오류 응답 (400 Bad Request)
{
"code": 9001,
"message": "INVALID_INPUT_DATA",
"detail": "요청 데이터가 유효하지 않습니다."
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "회차를 생성할 권한이 없습니다."
}
4.2 회차 조회
- HTTP 메서드: GET
- 경로: /v1/questionnaires/
{questionnaireId}/rounds/{roundId} - Headers:
- Authorization: Bearer
{accessToken} - Accept-Language: de-DE (기본값), en-US, ko-KR
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "round_789",
"questionnaireId": "quest_123",
"title": "2025년 7월 건강 설문",
"startDate": 1719792000000,
"endDate": 1722470399000,
"status": "ACTIVE",
"properties": {
"isRequired": true,
"allowAnonymous": false,
"maxAttempts": 1
},
"createdAt": 1714538000000,
"updatedAt": 1714539000000,
"responseCount": 42
}
- 오류 응답 (404 Not Found)
{
"code": 9005,
"message": "ROUND_NOT_FOUND",
"detail": "요청한 회차를 찾을 수 없습니다."
}
4.3 회차 목록 조회
- HTTP 메서드: GET
- 경로: /v1/questionnaires/
{questionnaireId}/rounds - Query Parameters:
- page: 페이지 번호 (기본값: 1)
- pageSize: 페이지 크기 (기본값: 10)
- status: 상태 필터 (예: DRAFT, ACTIVE, ENDED)
- Headers:
- Authorization: Bearer
{accessToken} - Accept-Language: de-DE (기본값), en-US, ko-KR
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"items": [
{
"id": "round_789",
"questionnaireId": "quest_123",
"title": "2025년 7월 건강 설문",
"startDate": 1719792000000,
"endDate": 1722470399000,
"status": "ACTIVE",
"responseCount": 42,
"createdAt": 1714538000000,
"updatedAt": 1714539000000
},
{
"id": "round_456",
"questionnaireId": "quest_123",
"title": "2025년 6월 건강 설문",
"startDate": 1717200000000,
"endDate": 1719791999000,
"status": "ENDED",
"responseCount": 87,
"createdAt": 1712000000000,
"updatedAt": 1714000000000
}
],
"metadata": {
"totalCount": 2,
"currentPage": 1,
"pageSize": 10,
"totalPages": 1
}
}
- 오류 응답 (404 Not Found)
{
"code": 9010,
"message": "QUESTIONNAIRE_NOT_FOUND",
"detail": "요청한 설문을 찾을 수 없습니다."
}
4.4 회차 수정
- HTTP 메서드: PATCH
- 경로: /v1/questionnaires/
{questionnaireId}/rounds/{roundId} - Headers:
- Content-Type: application/json
- Authorization: Bearer
{accessToken}
요청 (Request)
{
"title": "2025년 7월 건강 및 생활습관 설문",
"endDate": 1723075199000,
"properties": {
"maxAttempts": 2
}
}
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "round_789",
"questionnaireId": "quest_123",
"title": "2025년 7월 건강 및 생활습관 설문",
"startDate": 1719792000000,
"endDate": 1723075199000,
"status": "ACTIVE",
"properties": {
"isRequired": true,
"allowAnonymous": false,
"maxAttempts": 2
},
"createdAt": 1714538000000,
"updatedAt": 1714540000000
}
- 오류 응답 (400 Bad Request)
{
"code": 9001,
"message": "INVALID_INPUT_DATA",
"detail": "요청 데이터가 유효하지 않습니다."
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "회차를 수정할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 9005,
"message": "ROUND_NOT_FOUND",
"detail": "요청한 회차를 찾을 수 없습니다."
}
4.5 회차 상태 변경
- HTTP 메서드: PATCH
- 경로: /v1/questionnaires/
{questionnaireId}/rounds/{roundId}/status - Headers:
- Content-Type: application/json
- Authorization: Bearer
{accessToken}
요청 (Request)
{
"status": "ACTIVE"
}
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "round_789",
"questionnaireId": "quest_123",
"status": "ACTIVE",
"updatedAt": 1714541000000
}
- 오류 응답 (400 Bad Request)
{
"code": 9001,
"message": "INVALID_INPUT_DATA",
"detail": "요청 데이터가 유효하지 않습니다."
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "회차 상태를 변경할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 9005,
"message": "ROUND_NOT_FOUND",
"detail": "요청한 회차를 찾을 수 없습니다."
}
- 오류 응답 (409 Conflict)
{
"code": 9051,
"message": "INVALID_STATUS_TRANSITION",
"detail": "현재 상태에서 요청한 상태로 변경할 수 없습니다."
}
4.6 회차 완료
사용자가 특정 설문 회차의 모든 설문을 완료했을 때, 해당 회차를 완료 상태로 변경합니다.
- HTTP 메서드: POST
- 경로: /v1/questionnaires/rounds/
{roundId}/complete - Headers:
- Content-Type: application/json
- Authorization: Bearer
{accessToken} - Accept-Language: de-DE (기본), en-US, ko-KR (선택)
- Path Parameters:
roundId(string, 필수): 완료할 회차 ID
요청 (Request)
회차 완료 요청에는 별도의 request body가 필요하지 않습니다. 사용자 정보는 Authorization header의 access token에서 추출됩니다.
#### 응답 (Response)
- 성공 응답 (200 OK)
```json
{
"success": true
}
- 오류 응답 (400 Bad Request) - 회차 미완료
{
"code": 9050,
"message": "ROUND_INCOMPLETE",
"detail": "회차의 모든 설문이 완료되지 않았습니다"
}
- 오류 응답 (400 Bad Request) - 번들과 회차 불일치
{
"code": 9012,
"message": "ROUND_BUNDLE_MISMATCH",
"detail": "요청한 회차가 사용자의 설문 번들에 포함되지 않습니다"
}
- 오류 응답 (401 Unauthorized)
{
"code": 2051,
"message": "INVALID_TOKEN",
"detail": "토큰이 유효하지 않습니다"
}
- 오류 응답 (404 Not Found) - 회차를 찾을 수 없음
{
"code": 7008,
"message": "USER_STATE_NOT_FOUND",
"detail": "사용자의 활성 주기를 찾을 수 없습니다"
}
{
"code": 9031,
"message": "QUESTIONNAIRE_ROUND_NOT_FOUND",
"detail": "설문지 회차를 찾을 수 없습니다"
}
- 오류 응답 (404 Not Found) - 설문 번들을 찾을 수 없음
{
"code": 9010,
"message": "QUESTIONNAIRE_BUNDLE_NOT_FOUND",
"detail": "설문지 번들을 찾을 수 없습니다"
}
- 오류 응답 (410 Gone) - 회차 진행 기간 만료
{
"code": 9055,
"message": "ROUND_EXPIRED",
"detail": "해당 회차 진행 기간이 만료되었습니다"
}
- 오류 응답 (412 Precondition Failed) - 회차 시작 전
{
"code": 9054,
"message": "ROUND_NOT_STARTED",
"detail": "아직 해당 회차 진행 기간이 시작되지 않았습니다"
}
- 오류 응답 (500 Internal Server Error)
{
"code": 9000,
"message": "SERVER_ERROR",
"detail": "서버 내부 오류"
}
주요 처리 단계:
- 번들 검증: 사용자의 모바일 설정에서 bundleId를 조회하고, 요청된 회차가 해당 번들에 포함되는지 검증
- 사용자 상태 조회: 사용자의 활성 사이클 ID 조회
- 회차 기간 검증: 사용자의 currentDayIndex를 기반으로 회차 진행 가능 기간 검증 (시작일과 마감일 체크)
- 회차 완료 처리: CompleteQuestionnaireRoundCommand를 통한 회차 완료 처리 및 이벤트 발행
보안 검증: 사용자가 자신에게 할당된 설문 번들의 회차만 완료할 수 있도록 번들-회차 일치성을 검증합니다.
4.7 회차 누적 결과 조회
사용자가 특정 회차까지 완료된 모든 설문 결과를 누적으로 조회합니다. 3차를 요청하면 1,2,3차의 완료된 설문 결과를 모두 반환합니다.
-
HTTP 메서드: GET
-
경로: /v1/questionnaires/rounds/cumulative-results
-
Headers:
- Authorization: Bearer
{accessToken} - Accept-Language: de-DE, en-US, ko-KR (필수)
- Authorization: Bearer
-
Query Parameters:
- roundNumber: 조회할 회차 번호 (해당 회차까지의 누적 결과 반환, null이면 가장 최신까지)
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_abc_123",
"requestedRoundNumber": 3,
"allRounds": [
{
"id": "round_456",
"roundNumber": 1,
"questionnaireResponses": [
{
"id": "q_isi123",
"type": "ISI",
"title": "불면증 심각도 지수",
"score": {
"calculationType": "SUM",
"range": {
"min": { "value": 0 },
"max": { "value": 28 }
},
"userScore": 18,
"level": {
"id": "sl_isi3",
"range": {
"min": { "value": 15 },
"max": { "value": 21 }
},
"label": "중간 정도의 불면증",
"chartLabel": "수면 불량",
"description": "중등도의 불면 증상이 나타날 수 있습니다.",
"feedback": "중등도의 불면 증상이 나타날 수 있습니다. 의료 전문가의 도움이 필요한 상황입니다."
}
},
"completedAt": 1711929600000,
"completedDayIndex": 12
},
{
"id": "q_dbas16_123",
"type": "DBAS16",
"title": "수면에 대한 비합리적 신념",
"score": {
"calculationType": "AVERAGE",
"range": {
"min": { "value": 0 },
"max": { "value": 10 }
},
"userScore": 4.2,
"level": {
"id": "sl_dbas16_2",
"range": {
"min": { "value": 3.8 },
"max": { "value": 10 }
},
"label": "수면 부족에 대해 불편함을 느낌",
"chartLabel": "수면 부족에 대해 불편함을 느낌",
"description": "수면 부족으로 생긴 불편함이나 불안을 많이 느끼고 있는 경우를 나타냅니다.",
"feedback": "수면 부족으로 생긴 불편함이나 불안을 크게 느끼고 있습니다. 의료 전문가와 상담하여 적절한 치료 방안을 모색해 보세요."
}
},
"completedAt": 1711929600000,
"completedDayIndex": 12
},
{
"id": "q_phq9_123",
"type": "PHQ9",
"title": "우울증 선별 도구",
"score": {
"calculationType": "SUM",
"range": {
"min": { "value": 0 },
"max": { "value": 27 }
},
"userScore": 12,
"level": {
"id": "sl_phq9_3",
"range": {
"min": { "value": 10 },
"max": { "value": 14 }
},
"label": "중등도 우울증",
"chartLabel": "중등도 우울",
"description": "중등도의 우울 증상이 나타날 수 있습니다.",
"feedback": "의료 전문가와 상담하여 적절한 치료 방안을 모색해 보세요."
}
},
"completedAt": 1711929600000,
"completedDayIndex": 12
}
]
},
{
"id": "round_567",
"roundNumber": 2,
"questionnaireResponses": [
{
"id": "q_isi123",
"type": "ISI",
"title": "불면증 심각도 지수",
"score": {
"calculationType": "SUM",
"range": {
"min": { "value": 0 },
"max": { "value": 28 }
},
"userScore": 16,
"level": {
"id": "sl_isi3",
"range": {
"min": { "value": 15 },
"max": { "value": 21 }
},
"label": "중간 정도의 불면증",
"chartLabel": "수면 불량",
"description": "중등도의 불면 증상이 나타날 수 있습니다.",
"feedback": "중등도의 불면 증상이 나타날 수 있습니다. 의료 전문가의 도움이 필요한 상황입니다."
}
},
"completedAt": 1711929600000,
"completedDayIndex": 12
}
]
},
{
"id": "round_789",
"roundNumber": 3,
"questionnaireResponses": [
{
"id": "q_isi123",
"type": "ISI",
"title": "불면증 심각도 지수",
"score": {
"calculationType": "SUM",
"range": {
"min": { "value": 0 },
"max": { "value": 28 }
},
"userScore": 15,
"level": {
"id": "sl_isi2",
"range": {
"min": { "value": 8 },
"max": { "value": 14 }
},
"label": "약간의 불면증",
"chartLabel": "수면 다소 불량",
"description": "수면의 질이 다소 저하되어 있으며 가벼운 불면 증상이 있습니다.",
"feedback": "수면 습관 개선을 위한 몇 가지 조치가 필요합니다. 취침 전 루틴을 점검하고 수면 환경을 최적화하세요."
}
},
"completedAt": 1711929600000,
"completedDayIndex": 12
}
]
}
]
}
- 오류 응답 (401 Unauthorized)
{
"code": 2051,
"message": "INVALID_TOKEN",
"detail": "토큰이 유효하지 않습니다"
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "해당 회차를 완료할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 7008,
"message": "USER_STATE_NOT_FOUND",
"detail": "사용자의 활성 주기를 찾을 수 없습니다"
}
{
"code": 9031,
"message": "QUESTIONNAIRE_ROUND_NOT_FOUND",
"detail": "설문지 회차를 찾을 수 없습니다"
}
{
"code": 9010,
"message": "QUESTIONNAIRE_BUNDLE_NOT_FOUND",
"detail": "설문지 번들을 찾을 수 없습니다"
}
설문 응답 제출 API
5.1 설문 개별 응답 제출
사용자가 특정 설문의 모든 질문의 답변을 완료한 후, 해당 설문의 응답을 제출합니다.
- HTTP 메서드: POST
- 경로: /v1/questionnaires/
{questionnaireId}/rounds/{roundId}/responses - Headers:
- Content-Type: application/json
- Authorization: Bearer
{accessToken}(사용자 토큰)
- Path Parameters:
questionnaireId(string, 필수): 응답을 제출할 설문의 ID.roundId(string, 필수): 응답을 제출할 설문 회차의 ID.
요청 (Request)
{
"userId": "ksjekljtwkj6-623j456l23jk6kjk-ksjfja",
"questionResponses": [
{
"id": "question_abc_001",
"type": "MULTI_CHOICE",
"responses": [
// QuestionOption.id 와 QuestionOption.value를 함께 전송
{ "optionId": "q_opt_001a", "value": "option_value_1", "textValue": "Text for option 1" }
],
"textValue": "Text answer for question_abc_001",
"decisionTimeMs": 180000 // (optional) 답변 완료까지 총 소요 시간 (ms)
},
{
"id": "question_abc_001b",
"type": "SINGLE_CHOICE",
"responses": [{ "optionId": "q_opt_001c", "value": "option_value_single" }],
"decisionTimeMs": 180000 // 답변 완료까지 총 소요 시간 (ms)
},
{
"id": "question_abc_002", // LINEAR_SCALE (옵션 기반)
"type": "LINEAR_SCALE",
// LINEAR_SCALE도 내부적으로 QuestionOption을 사용할 경우 optionId와 value를 전송
"responses": [{ "optionId": "q_opt_ls_003", "value": "3" }],
"decisionTimeMs": 180000 // 답변 완료까지 총 소요 시간 (ms)
},
{
"id": "question_abc_003", // TIME (옵션 기반이 아님)
"type": "TIME",
// 이 경우 optionId는 null이며, value만 중요
"responses": [{ "optionId": null, "value": "22:30" }],
"decisionTimeMs": 180000 // 답변 완료까지 총 소요 시간 (ms)
},
{
"id": "question_abc_005", //
"type": "DURATION_MINUTES",
// 이 경우 optionId는 null이며, value만 중요
"responses": [{ "optionId": null, "value": "430" }], // minutes
"decisionTimeMs": 180000 // 답변 완료까지 총 소요 시간 (ms)
},
{
"id": "question_abc_004", // LINE_TEXT (옵션 기반이 아님)
"type": "LINE_TEXT",
// 이 경우 optionId는 null이며, value만 중요
"responses": [{ "optionId": null, "value": "한 줄 텍스트 답변" }],
"decisionTimeMs": 180000 // 답변 완료까지 총 소요 시간 (ms)
}
// ... questionnaireId에 해당하는 설문의 모든 문항에 대한 응답
],
"metadata": {
// 선택적 필드: 전체 설문 응답에 대한 메타데이터
"startedAt": 1747823247000 // 설문 시작 시각
}
}
응답 (Response)
- 성공 응답 (201 Created)
{
"id": "resp_new_123", // 새로 생성된 QuestionnaireResponse의 ID
"userId": "user_abc_789", // 토큰에서 식별된 사용자 ID
"questionnaireId": "q_isi123",
"roundId": "round_xyz_456",
"score": 18,
"maxPossible": 28,
"minPossible": 0,
"scoreLevel": {
"id": "sl_isi3",
"minScore": 0,
"maxScore": 7,
"label": "불면 증상이 거의 없음",
"feedback": "수면에 거의 문제가 없는 편입니다. 그러나 일상적인 수면 습관을 유지하고 스트레스를 관리하는 것이 중요합니다. 다만 이 점검 결과가 절대적인 것은 아니며 자세한 사항은 의료진과 상의하세요."
},
"createdAt": 1716800000000,
"updatedAt": 1716800000000
}
- 오류 응답 (400 Bad Request) - 필수 문항 누락, 유효하지 않은 답변 등
{
"code": 9001, // 또는 좀 더 구체적인 오류 코드 (예: REQUIRED_ANSWERS_MISSING)
"message": "INVALID_INPUT_DATA",
"detail": "필수 문항에 대한 응답이 누락되었거나, 응답 형식이 유효하지 않습니다.",
"errors": [
// 선택적으로 어떤 문항/필드에서 오류가 발생했는지 상세 정보 제공 가능
{
"id": "q_isi_3",
"message": "필수 응답입니다."
}
]
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "해당 설문 회차에 응답을 제출할 권한이 없습니다."
}
- 오류 응답 (409 Conflict) - 이미 해당 회차에 응답이 제출된 경우 등
{
"code": 9046, // RESPONSE_ALREADY_EXISTS 또는 유사한 코드
"message": "RESPONSE_ALREADY_SUBMITTED",
"detail": "이미 해당 설문 회차에 대한 응답이 제출되었습니다."
}
상세 에러 응답 (400 Bad Request) - 설문 응답 검증 오류
- 필수 질문 미응답
{
"code": 9040,
"message": "REQUIRED_QUESTION_NOT_ANSWERED",
"detail": "필수 질문에 응답하지 않았습니다"
}
- 필수 질문 빈 값
{
"code": 9043,
"message": "REQUIRED_QUESTION_EMPTY_VALUE",
"detail": "필수 질문에 빈 값을 입력할 수 없습니다"
}
- 질문 타입 불일치
{
"code": 9041,
"message": "QUESTION_TYPE_MISMATCH",
"detail": "질문 타입이 일치하지 않습니다"
}
- 단일 선택 질문에 다중 답변
{
"code": 9042,
"message": "SINGLE_CHOICE_MULTIPLE_ANSWERS",
"detail": "단일 선택 질문에는 하나의 답변만 가능합니다"
}
- 지원하지 않는 질문 타입
{
"code": 9044,
"message": "UNSUPPORTED_QUESTION_TYPE",
"detail": "지원하지 않는 질문 타입입니다"
}
- 선택지 값 불일치
{
"code": 9045,
"message": "OPTION_VALUE_MISMATCH",
"detail": "선택된 옵션의 값이 일치하지 않습니다"
}
상세 에러 응답 (403 Forbidden) - 회차 기간 관련 오류
- 회차 시작 전
{
"code": 9054,
"message": "ROUND_NOT_STARTED",
"detail": "아직 해당 회차 진행 기간이 시작되지 않았습니다"
}
- 회차 기간 만료
{
"code": 9055,
"message": "ROUND_EXPIRED",
"detail": "해당 회차 진행 기간이 만료되었습니다"
}
상세 에러 응답 (404 Not Found) - 리소스 없음
- 설문지 없음
{
"code": 9030,
"message": "QUESTIONNAIRE_NOT_FOUND",
"detail": "설문지를 찾을 수 없습니다"
}
- 설문 회차 없음
{
"code": 9031,
"message": "QUESTIONNAIRE_ROUND_NOT_FOUND",
"detail": "설문지 회차를 찾을 수 없습니다"
}
상세 에러 응답 (500 Internal Server Error) - 시스템 오류
- 서버 내부 오류
{
"code": 9000,
"message": "SERVER_ERROR",
"detail": "서버 내부 오류"
}
- 데이터베이스 접근 오류
{
"code": 9500,
"message": "REPOSITORY_ERROR",
"detail": "데이터베이스 접근 중 오류가 발생했습니다"
}
사용자 설문 진행 스케줄 조회 API
6.1 특정 dayIndex의 설문 스케줄 조회
모바일 클라이언트가 특정 dayIndex에 대한 사용자의 설문 진행 상태를 확인하고, 어떤 설문을 진행해야 하는지 또는 어떤 안내를 해야 하는지에 대한 정보를 받기 위해 사용합니다.
- 경로: /v1/questionnaires/users/me/schedule/next-pending/
{dayIndex} - Headers:
- Authorization: Bearer
{accessToken}(사용자 토큰, userId는 토큰에서 자동 추출) - Accept-Language: de-DE (기본값), en-US, ko-KR (필수)
- Authorization: Bearer
- Path Parameters:
- dayIndex: number (필수, 1 이상의 양수) - 조회할 특정 dayIndex
주의사항:
- dayIndex는 사용자의 현재 dayIndex와 반드시 일치해야 합니다.
- 일치하지 않을 경우 400 Bad Request 에러가 발생합니다.
- bundleId는 사용자가 직접 제공하지 않으며, 내부적으로 User Mobile Settings의
questionnaireBundleId필드에서 자동으로 조회됩니다.
요청 (Request)
Path Parameter Schema (GetUserScheduleParamsDto):
{
dayIndex: number; // 1 이상의 양수, 사용자의 현재 dayIndex와 일치해야 함
}
Parameter 설명:
- userId: Authorization Bearer 토큰에서 자동 추출 (토큰의 userId와 일치해야 함)
- dayIndex: Path Parameter로 전달되는 조회할 dayIndex
- 타입: number (1 이상의 양수)
- 검증: 사용자의 현재 dayIndex와 반드시 일치해야 함
- 예시:
/v1/questionnaires/users/me/schedule/next-pending/15
- bundleId: 내부적으로 User Mobile Settings의
questionnaireBundleId필드에서 자동 조회 (클라이언트 제공 불필요)
응답 (Response)
1. 진행할 설문이 있는 경우 (200 OK)
- 경우1: skip 불가능한 회차
{
"userId": "user_abc_123",
"bundleId": "bundle_questionnaire_2024_v1",
"currentRound": {
"id": "round_xyz_456",
"roundNumber": 1,
"startDayIndex": 29,
"endDayIndex": 35,
"isSkippable": false,
"questionnaires": [
{
"id": "q_dbas123",
"type": "DBAS16",
"orderIndex": 0
},
{
"id": "q_phq9_123",
"type": "PHQ9",
"orderIndex": 3
}
// ... 해당 회차의 나머지 미완료 설문들 (완료된 설문은 포함되지 않음)
]
}
}
- 경우2: skip 가능한 회차
{
"userId": "user_abc_123",
"bundleId": "bundle_questionnaire_2024_v1",
"currentRound": {
"id": "round_xyz_456",
"roundNumber": 2,
"startDayIndex": 29,
"endDayIndex": 35,
"isSkippable": true, // skip 가능
"remainingSkipDays": 0, // skip 할 수 있는 남아 있는 일 수를 제공
"questionnaires": [
{
"id": "q_dbas123",
"type": "DBAS16",
"orderIndex": 0
},
{
"id": "q_phq9_123",
"type": "PHQ9",
"orderIndex": 3
}
// ... 해당 회차의 나머지 미완료 설문들 (완료된 설문은 포함되지 않음)
]
}
}
2. 현재 진행할 설문이 없는 경우 (200 OK)
- 경우2-1: 중간 회차 완료 후 대기 상태
- 현재 회차의 모든 설문을 완료했고, 다음 회차 시작까지 기다리는 상태
remainingDaysToNext: 다음 회차까지 남은 일수 제공
{
"userId": "user_abc_123",
"bundleId": "bundle_questionnaire_2024_v1",
"remainingDaysToNext": 12
}
- 경우2-3: 회차 기간 만료 후 대기
- 현재 회차 참여 기간이 지났고, 다음 회차가 아직 시작되지 않은 상태
remainingDaysToNext: 다음 회차 시작까지 남은 일수 제공
{
"userId": "user_abc_123",
"bundleId": "bundle_questionnaire_2024_v1",
"remainingDaysToNext": 34
}
- 경우2-3: 최종 회차 완료
- 모든 설문 프로그램을 완료한 상태 (더 이상 진행할 설문 없음)
remainingDaysToNext필드 없음 (다음 설문이 없으므로)
{
"userId": "user_abc_123",
"bundleId": "bundle_questionnaire_2024_v1"
}
- 오류 응답 (400 Bad Request) - dayIndex 불일치
{
"code": 7009,
"message": "INVALID_DAY_INDEX",
"detail": "요청된 dayIndex가 사용자의 현재 dayIndex와 일치하지 않습니다."
}
- 오류 응답 (401 Unauthorized) - 인증 실패
{
"code": 2051,
"message": "INVALID_TOKEN",
"detail": "토큰이 유효하지 않습니다"
}
- 오류 응답 (404 Not Found) - 존재하지 않는 설문 번들
{
"code": 9010,
"message": "QUESTIONNAIRE_BUNDLE_NOT_FOUND",
"detail": "설문지 번들을 찾을 수 없습니다"
}
- 오류 응답 (404 Not Found) - 사용자 정보 없음 또는 사용자에 대한 설문 스케줄 정보가 없는 경우
{
"code": 9052,
"message": "USER_QUESTIONNAIRE_SCHEDULE_NOT_FOUND",
"detail": "사용자의 설문 스케줄을 찾을 수 없습니다"
}
- 오류 응답 (500 Internal Server Error) - 서버 내부 오류
{
"code": 9000,
"message": "SERVER_ERROR",
"detail": "서버 내부 오류"
}
{
"code": 9500,
"message": "REPOSITORY_ERROR",
"detail": "데이터베이스 접근 중 오류가 발생했습니다"
}
설문 결과 관리 API
7.1 설문 결과 조회
- HTTP 메서드: GET
- 경로: /v1/users/
{userId}/questionnaire-results/{questionnaireId} - Headers:
- Authorization: Bearer
{accessToken} - Accept-Language: de-DE (기본값), en-US, ko-KR
- Authorization: Bearer
- Query Parameters:
- roundId: 특정 회차 결과 조회 (선택, 기본값: 가장 최근 완료된 회차)
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"questionnaireId": "q_isi123",
"roundId": "round_789",
"responseId": "resp_456",
"submittedAt": 1714547000000,
"score": {
"total": 15,
"maxPossible": 28
},
"scoreLevel": {
"id": "sl_isi2",
"minScore": 8,
"maxScore": 14,
"translation": {
"language": "ko",
"label": "약간의 불면증",
"chartLabel": "수면 다소 불량",
"description": "수면의 질이 다소 저하되어 있으며 가벼운 불면 증상이 있습니다.",
"feedback": "수면 습관 개선을 위한 몇 가지 조치가 필요합니다. 취침 전 루틴을 점검하고 수면 환경을 최적화하세요."
}
},
"questionResults": [
{
"questionId": "q_123",
"orderIndex": 0,
"translation": {
"text": "최근 불면 증상으로 인한 어려움의 정도를 표시해주세요."
},
"answer": "3",
"score": 3
}
// ... 다른 문항 결과
]
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "해당 사용자의 설문 결과를 조회할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 9071,
"message": "QUESTIONNAIRE_RESULT_NOT_FOUND",
"detail": "요청한 설문 결과를 찾을 수 없습니다."
}
7.2 설문 결과 이력 조회
- HTTP 메서드: GET
- 경로: /v1/users/
{userId}/questionnaire-history/{questionnaireId} - Headers:
- Authorization: Bearer
{accessToken} - Accept-Language: de-DE (기본값), en-US, ko-KR
- Authorization: Bearer
- Query Parameters:
- startDate: 시작 날짜 (선택, 밀리초 단위 타임스탬프)
- endDate: 종료 날짜 (선택, 밀리초 단위 타임스탬프)
- page: 페이지 번호 (선택, 기본값: 1)
- pageSize: 페이지 크기 (선택, 기본값: 10)
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"questionnaireId": "q_isi123",
"translation": {
"title": "불면증 심각도 지수"
},
"history": [
{
"roundId": "round_789",
"responseId": "resp_456",
"submittedAt": 1714547000000,
"score": 15,
"scoreLevel": {
"id": "sl_isi2",
"translation": {
"label": "약간의 불면증"
}
}
},
{
"roundId": "round_456",
"responseId": "resp_123",
"submittedAt": 1711929600000,
"score": 18,
"scoreLevel": {
"id": "sl_isi3",
"translation": {
"label": "중간 정도의 불면증"
}
}
}
],
"metadata": {
"totalCount": 2,
"currentPage": 1,
"pageSize": 10,
"totalPages": 1
}
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "해당 사용자의 설문 이력을 조회할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 9010,
"message": "QUESTIONNAIRE_NOT_FOUND",
"detail": "요청한 설문을 찾을 수 없습니다."
}
7.3 설문 차트 데이터 조회
- HTTP 메서드: GET
- 경로: /v1/users/
{userId}/questionnaire-charts/{questionnaireId} - Headers:
- Authorization: Bearer
{accessToken} - Accept-Language: de-DE (기본값), en-US, ko-KR
- Authorization: Bearer
- Query Parameters:
- period: 기간 (선택, 가능한 값: "3m", "6m", "1y", "all", 기본값: "6m")
- aggregation: 집계 방식 (선택, 가능한 값: "daily", "weekly", "monthly", 기본값: "monthly")
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"questionnaireId": "q_isi123",
"translation": {
"title": "불면증 심각도 지수"
},
"period": "6m",
"aggregation": "monthly",
"chartData": {
"labels": ["2025-01", "2025-02", "2025-03", "2025-04", "2025-05", "2025-06"],
"datasets": [
{
"label": "총점",
"data": [19, 17, 16, 14, 15, 12]
}
],
"scoreLevels": [
{
"id": "sl_isi1",
"minScore": 0,
"maxScore": 7,
"translation": {
"chartLabel": "수면 상태 좋음",
"color": "#4CAF50"
}
},
{
"id": "sl_isi2",
"minScore": 8,
"maxScore": 14,
"translation": {
"chartLabel": "수면 다소 불량",
"color": "#FFEB3B"
}
},
{
"id": "sl_isi3",
"minScore": 15,
"maxScore": 21,
"translation": {
"chartLabel": "수면 불량",
"color": "#FF9800"
}
},
{
"id": "sl_isi4",
"minScore": 22,
"maxScore": 28,
"translation": {
"chartLabel": "수면 매우 불량",
"color": "#F44336"
}
}
]
}
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "해당 사용자의 차트 데이터를 조회할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 9010,
"message": "QUESTIONNAIRE_NOT_FOUND",
"detail": "요청한 설문을 찾을 수 없습니다."
}
7.4 종합 보고서 생성 요청
- HTTP 메서드: POST
- 경로: /v1/users/
{userId}/questionnaire-reports - Headers:
- Content-Type: application/json
- Authorization: Bearer
{accessToken} - Accept-Language: de-DE (기본값), en-US, ko-KR
요청 (Request)
{
"questionnaireIds": ["q_isi123", "q_psqi456", "q_ess789"],
"period": {
"startDate": 1704067200000,
"endDate": 1719792000000
},
"format": "PDF",
"includeRecommendations": true,
"includeCharts": true,
"includeDetailedResponses": false
}
응답 (Response)
- 성공 응답 (202 Accepted)
{
"reportId": "rep_123",
"userId": "user_123",
"status": "PROCESSING",
"estimatedCompletionTime": 30,
"callbackUrl": "/v1/users/{userId}/questionnaire-reports/{reportId}"
}
- 오류 응답 (400 Bad Request)
{
"code": 9001,
"message": "INVALID_INPUT_DATA",
"detail": "요청 데이터가 유효하지 않습니다."
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "해당 사용자의 보고서를 생성할 권한이 없습니다."
}
7.5 보고서 상태 및 다운로드 URL 조회
- HTTP 메서드: GET
- 경로: /v1/users/
{userId}/questionnaire-reports/{reportId} - Headers:
- Authorization: Bearer
{accessToken} - Accept-Language: de-DE (기본값), en-US, ko-KR
- Authorization: Bearer
응답 (Response) - 처리 중
- 성공 응답 (200 OK)
{
"reportId": "rep_123",
"userId": "user_123",
"status": "PROCESSING",
"progress": 65,
"estimatedCompletionTime": 10,
"createdAt": 1714550000000,
"updatedAt": 1714550500000
}
응답 (Response) - 완료됨
- 성공 응답 (200 OK)
{
"reportId": "rep_123",
"userId": "user_123",
"status": "COMPLETED",
"format": "PDF",
"fileName": "sleep_assessment_report_2025_H1.pdf",
"fileSize": 1256000,
"downloadUrl": "https://api.example.com/v1/downloads/reports/rep_123?token=xyz",
"downloadUrlExpiry": 1714560000000,
"createdAt": 1714550000000,
"completedAt": 1714551000000,
"updatedAt": 1714551000000
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "해당 사용자의 보고서를 조회할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 9072,
"message": "REPORT_NOT_FOUND",
"detail": "요청한 보고서를 찾을 수 없습니다."
}
7.6 사용자 전체 회차 결과 조회
- HTTP 메서드: GET
- 경로: /questionnaires/users/me/results/all-rounds
- Headers:
- Authorization: Bearer
{accessToken} - Accept-Language: de-DE, en-US, ko-KR (필수)
- Authorization: Bearer
사용자의 모든 완료된 회차에 대한 설문 결과를 조회합니다. 최종 보고서 생성 시 사용됩니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_abc_123",
"requestedRoundNumber": 5,
"allRounds": [
{
"id": "round_123",
"roundNumber": 1,
"questionnaireResponses": [
{
"id": "q_isi123",
"type": "ISI",
"title": "불면증 심각도 지수",
"score": {
"calculationType": "SUM",
"range": {
"min": {
"value": 0
},
"max": {
"value": 28
}
},
"userScore": 18,
"level": {
"id": "sl_isi3",
"range": {
"min": {
"value": 15
},
"max": {
"value": 21
}
},
"label": "중간 정도의 불면증",
"chartLabel": "수면 불량",
"description": "중등도의 불면 증상이 나타날 수 있습니다.",
"feedback": "중등도의 불면 증상이 나타날 수 있습니다. 의료 전문가의 도움이 필요한 상황입니다."
}
},
"completedAt": 1711929600000,
"completedDayIndex": 12
},
{
"id": "q_dbas16_123",
"type": "DBAS16",
"title": "수면에 대한 비합리적 신념",
"score": {
"calculationType": "AVERAGE",
"range": {
"min": {
"value": 0
},
"max": {
"value": 10
}
},
"userScore": 4.2,
"level": {
"id": "sl_dbas16_2",
"range": {
"min": {
"value": 3.8
},
"max": {
"value": 10
}
},
"label": "수면 부족에 대해 불편함을 느낌",
"chartLabel": "수면 부족에 대해 불편함을 느낌",
"description": "수면 부족으로 생긴 불편함이나 불안을 많이 느끼고 있는 경우를 나타냅니다.",
"feedback": "수면 부족으로 생긴 불편함이나 불안을 크게 느끼고 있습니다. 의료 전문가와 상담하여 적절한 치료 방안을 모색해 보세요."
}
},
"completedAt": 1711929600000,
"completedDayIndex": 12
},
{
"id": "q_phq9_123",
"type": "PHQ9",
"title": "우울증 선별 도구",
"score": {
"calculationType": "SUM",
"range": {
"min": {
"value": 0
},
"max": {
"value": 27
}
},
"userScore": 12,
"level": {
"id": "sl_phq9_3",
"range": {
"min": {
"value": 10
},
"max": {
"value": 14
}
},
"label": "중등도 우울증",
"chartLabel": "중등도 우울",
"description": "중등도의 우울 증상이 나타날 수 있습니다.",
"feedback": "의료 전문가와 상담하여 적절한 치료 방안을 모색해 보세요."
}
},
"completedAt": 1711929600000,
"completedDayIndex": 12
}
]
},
{
"id": "round_456",
"roundNumber": 2,
"questionnaireResponses": [
{
"id": "q_isi456",
"type": "ISI",
"title": "불면증 심각도 지수",
"score": {
"calculationType": "SUM",
"range": {
"min": {
"value": 0
},
"max": {
"value": 28
}
},
"userScore": 16,
"level": {
"id": "sl_isi3",
"range": {
"min": {
"value": 15
},
"max": {
"value": 21
}
},
"label": "중간 정도의 불면증",
"chartLabel": "수면 불량",
"description": "중등도의 불면 증상이 나타날 수 있습니다.",
"feedback": "중등도의 불면 증상이 나타날 수 있습니다. 의료 전문가의 도움이 필요한 상황입니다."
}
},
"completedAt": 1712534400000,
"completedDayIndex": 19
},
{
"id": "q_phq9_456",
"type": "PHQ9",
"title": "우울증 선별 도구",
"score": {
"calculationType": "SUM",
"range": {
"min": {
"value": 0
},
"max": {
"value": 27
}
},
"userScore": 8,
"level": {
"id": "sl_phq9_2",
"range": {
"min": {
"value": 5
},
"max": {
"value": 9
}
},
"label": "경미한 우울증",
"chartLabel": "경미한 우울",
"description": "경미한 우울 증상이 나타날 수 있습니다.",
"feedback": "우울 증상이 개선되고 있습니다. 현재 관리 방법을 유지하세요."
}
},
"completedAt": 1712534400000,
"completedDayIndex": 19
}
]
},
{
"id": "round_789",
"roundNumber": 3,
"questionnaireResponses": [
{
"id": "q_isi789",
"type": "ISI",
"title": "불면증 심각도 지수",
"score": {
"calculationType": "SUM",
"range": {
"min": {
"value": 0
},
"max": {
"value": 28
}
},
"userScore": 12,
"level": {
"id": "sl_isi2",
"range": {
"min": {
"value": 8
},
"max": {
"value": 14
}
},
"label": "약간의 불면증",
"chartLabel": "수면 다소 불량",
"description": "수면의 질이 다소 저하되어 있으며 가벼운 불면 증상이 있습니다.",
"feedback": "수면 습관 개선을 위한 몇 가지 조치가 필요합니다. 취침 전 루틴을 점검하고 수면 환경을 최적화하세요."
}
},
"completedAt": 1713139200000,
"completedDayIndex": 26
},
{
"id": "q_gad7_789",
"type": "GAD7",
"title": "범불안장애 선별도구",
"score": {
"calculationType": "SUM",
"range": {
"min": {
"value": 0
},
"max": {
"value": 21
}
},
"userScore": 6,
"level": {
"id": "sl_gad7_2",
"range": {
"min": {
"value": 5
},
"max": {
"value": 9
}
},
"label": "경미한 불안",
"chartLabel": "경미한 불안",
"description": "경미한 불안 증상이 나타날 수 있습니다.",
"feedback": "불안 증상이 경미한 수준입니다. 스트레스 관리와 휴식을 통해 개선할 수 있습니다."
}
},
"completedAt": 1713139200000,
"completedDayIndex": 26
}
]
},
{
"id": "round_890",
"roundNumber": 4,
"questionnaireResponses": [
{
"id": "q_isi890",
"type": "ISI",
"title": "불면증 심각도 지수",
"score": {
"calculationType": "SUM",
"range": {
"min": {
"value": 0
},
"max": {
"value": 28
}
},
"userScore": 8,
"level": {
"id": "sl_isi2",
"range": {
"min": {
"value": 8
},
"max": {
"value": 14
}
},
"label": "약간의 불면증",
"chartLabel": "수면 다소 불량",
"description": "수면의 질이 다소 저하되어 있으며 가벼운 불면 증상이 있습니다.",
"feedback": "수면 상태가 지속적으로 개선되고 있습니다. 현재 방법을 유지하세요."
}
},
"completedAt": 1713744000000,
"completedDayIndex": 33
}
]
},
{
"id": "round_901",
"roundNumber": 5,
"questionnaireResponses": [
{
"id": "q_isi901",
"type": "ISI",
"title": "불면증 심각도 지수",
"score": {
"calculationType": "SUM",
"range": {
"min": {
"value": 0
},
"max": {
"value": 28
}
},
"userScore": 5,
"level": {
"id": "sl_isi1",
"range": {
"min": {
"value": 0
},
"max": {
"value": 7
}
},
"label": "불면 증상이 거의 없음",
"chartLabel": "수면 상태 좋음",
"description": "해당 범위는 불면의 증상이 거의 없거나 매우 적은 경우를 나타냅니다.",
"feedback": "수면에 거의 문제가 없는 편입니다. 그러나 일상적인 수면 습관을 유지하고 스트레스를 관리하는 것이 중요합니다."
}
},
"completedAt": 1714348800000,
"completedDayIndex": 40
}
]
}
]
}
에러 응답
- 401 Unauthorized: 인증 토큰이 없거나 유효하지 않음
- 403 Forbidden: 접근 권한이 없음
- 404 Not Found: 사용자 회차 정보를 찾을 수 없음 (에러 코드: 9031)
- 500 Internal Server Error: 서버 내부 오류
{
"code": 9031,
"message": "QUESTIONNAIRE_ROUND_NOT_FOUND",
"detail": "요청한 회차를 찾을 수 없습니다."
}
사용 예시
이 API는 다음 상황에서 사용됩니다:
- 최종 보고서 생성: 사용자의 전체 치료 과정 분석
- 진행 상황 추적: 회차별 점수 변화 분석
- 데이터 내보내기: 외부 시스템으로 데이터 전송
모바일 캐싱 API
8.1 특정 번들 버전 조회
- HTTP 메서드: GET
- 경로: /v1/questionnaires/bundles/
{bundleId} - Headers:
- Authorization: Bearer
{appToken} - Accept-Language: de-DE, ko-KR, en-US (필수, 응답 언어 지정)
- Authorization: Bearer
- Path Parameters:
- bundleId: 번들 ID (필수)
- Query Parameters:
- includeQuestions: 문항 포함 여부 (선택, 기본값: true)
- includeScoreLevels: 점수 구간 포함 여부 (선택, 기본값: true)
⚠️ 언어 지정은 반드시
Accept-Language헤더로만 전달해야 하며, 더 이상language쿼리 파라미터는 지원하지 않습니다. 응답 내 번역 필드는Accept-Language에 따라 결정됩니다.
Responses
| HTTP Status Code | 설명 | Error Code(s) |
|---|---|---|
200 OK | 번들 조회 성공 | - |
404 Not Found | 번들 또는 번역 정보 없음 | 9010, 9033 |
500 Internal Server Error | 서버 내부 오류 | 9000, 9500 |
응답 (Response)
- 성공 응답 (200 OK)
{
"bundleId": "bundle_welt_001",
"language": "de-DE",
"questionnaires": [
// ISI 설문 정보
{
"id": "q_isi_uuid_example",
"type": "ISI",
"info": {
"title": "Insomnia Severity Index",
"intro": "Der \"Insomnia Severity Index\"(ISI)- Fragebogen besteht aus 7 Fragen und untersucht deine Symptome der Schlaflosigkeit und ihre Auswirkungen auf deinen Alltag.\n\nEr hilft uns bei der Einschätzung der Schwere deiner aktuellen Schlafstörungen sowie auch bei der Erstellung deines individuellen Behandlungsplanes.\n\nBitte beantworte uns die Fragen ehrlich, basierend auf deinen Erfahrungen der letzten zwei Wochen."
},
"question": {
"count": 7,
"questions": [
// ISI 문항 1
{
"id": "q_isi_q1_uuid",
"orderIndex": 0,
"type": "SINGLE_CHOICE",
"isRequired": true,
"headline": "Bitte kreuze für jede der folgenden Fragen die Zahl an, die am besten deinem Schlafmuster im letzten Monat entspricht. Bei den ersten 3 Fragen geht es um eine Beurteilung deiner Schlafschwierigkeiten.",
"text": "Schwierigkeit, einzuschlafen.",
"options": [
{ "id": "opt_isi_q1_0_uuid", "value": "0", "orderIndex": 0, "score": 0, "text": "Keine" },
{ "id": "opt_isi_q1_1_uuid", "value": "1", "orderIndex": 1, "score": 1, "text": "Leichte" },
{ "id": "opt_isi_q1_2_uuid", "value": "2", "orderIndex": 2, "score": 2, "text": "Mäßige" },
{ "id": "opt_isi_q1_3_uuid", "value": "3", "orderIndex": 3, "score": 3, "text": "Starke" },
{ "id": "opt_isi_q1_4_uuid", "value": "4", "orderIndex": 4, "score": 4, "text": "Sehr starke" }
]
},
// ... (예시: 문항 2)
{
"id": "q_isi_q2_uuid",
"orderIndex": 1,
"type": "SINGLE_CHOICE",
"isRequired": true,
"headline": "Bitte kreuze für jede der folgenden Fragen die Zahl an, die am besten deinem Schlafmuster im letzten Monat entspricht. Bei den ersten 3 Fragen geht es um eine Beurteilung deiner Schlafschwierigkeiten.",
"text": "Schwierigkeit, durchzuschlafen.",
"options": [
{ "id": "opt_isi_q2_0_uuid", "value": "0", "orderIndex": 0, "score": 0, "text": "Keine" },
{ "id": "opt_isi_q2_1_uuid", "value": "1", "orderIndex": 1, "score": 1, "text": "Leichte" },
{ "id": "opt_isi_q2_2_uuid", "value": "2", "orderIndex": 2, "score": 2, "text": "Mäßige" },
{ "id": "opt_isi_q2_3_uuid", "value": "3", "orderIndex": 3, "score": 3, "text": "Starke" },
{ "id": "opt_isi_q2_4_uuid", "value": "4", "orderIndex": 4, "score": 4, "text": "Sehr starke" }
]
}
// ... (다른 ISI 문항들 생략)
]
},
"score": {
"calculationType": "SUM",
"range": {
"min": {
"value": 0
},
"max": {
"value": 28
}
},
"levels": [
{
"id": "sl_isi_1_uuid",
"range": {
"min": {
"value": 0
},
"max": {
"value": 7
}
},
"label": "Keine klinisch signifikante Insomnie",
"chartLabel": "Guter Schlaf",
"description": "Dieser Bereich zeigt keine oder sehr geringe Anzeichen von Schlaflosigkeit.",
"feedback": "Sie haben kaum Schlafprobleme. Behalten Sie Ihre guten Schlafgewohnheiten bei."
},
{
"id": "sl_isi_2_uuid",
"range": {
"min": {
"value": 8
},
"max": {
"value": 14
}
},
"label": "Leichte Insomnie",
"chartLabel": "Etwas schlechter Schlaf",
"description": "Leichte Anzeichen von Schlaflosigkeit können auftreten.",
"feedback": "Überprüfen Sie Ihre Schlafumgebung und versuchen Sie, regelmäßige Schlafmuster beizubehalten."
},
{
"id": "sl_isi_3_uuid",
"range": {
"min": {
"value": 15
},
"max": {
"value": 21
}
},
"label": "Mittelschwere Insomnie",
"chartLabel": "Schlechter Schlaf",
"description": "Mäßige Anzeichen von Schlaflosigkeit, professionelle Hilfe könnte erforderlich sein.",
"feedback": "Es ist ratsam, einen Schlafexperten zu konsultieren, um Ihren aktuellen Zustand zu bewerten und geeignete Maßnahmen zu ergreifen."
},
{
"id": "sl_isi_4_uuid",
"range": {
"min": {
"value": 22
},
"max": {
"value": 28
}
},
"label": "Schwere Insomnie",
"chartLabel": "Sehr schlechter Schlaf",
"description": "Schwere Anzeichen von Schlaflosigkeit, die das tägliche Leben erheblich beeinträchtigen können. Professionelle Hilfe ist unbedingt erforderlich.",
"feedback": "Bitte konsultieren Sie sofort einen Schlafexperten oder Arzt für eine professionelle Behandlung."
}
]
}
},
// PHQ-9 설문 정보
{
"id": "q_phq9_uuid_example",
"type": "PHQ9",
"info": {
"title": "Gesundheitsfragebogen für Patient*innen PHQ-9",
"intro": "Die neun Fragen des Gesundheitsfragebogens für Patient*innen dienen der Einschätzung der Schwere und Häufigkeit der mit einer Depression verbundenen Gefühle oder Symptome.\n\nDa Depression in einem engen Zusammenhang mit Schlaflosigkeit steht, nutzen wir diesen Fragebogen, um uns ein noch genaueres Bild vom Zustand deines Schlafes machen zu können.\n\nBitte beantworte die Fragen ehrlich und auf Grundlage deiner Erfahrungen aus den letzten zwei Wochen."
},
"question": {
"count": 9,
"questions": [
// PHQ-9 문항 1
{
"id": "q_phq9_q1_uuid",
"orderIndex": 0,
"type": "SINGLE_CHOICE",
"isRequired": true,
"headline": "Wie oft hast du dich im Verlauf der letzten zwei Wochen durch die folgenden Beschwerden beeinträchtigt gefühlt?",
"text": "Wenig Interesse oder Freude an deinen Tätigkeiten",
"options": [
{ "id": "opt_phq9_q1_0_uuid", "value": "0", "orderIndex": 0, "score": 0, "text": "Überhaupt nicht" },
{ "id": "opt_phq9_q1_1_uuid", "value": "1", "orderIndex": 1, "score": 1, "text": "An einzelnen Tagen" },
{ "id": "opt_phq9_q1_2_uuid", "value": "2", "orderIndex": 2, "score": 2, "text": "An mehr als der Hälfte der Tage" },
{ "id": "opt_phq9_q1_3_uuid", "value": "3", "orderIndex": 3, "score": 3, "text": "Beinahe jeden Tag" }
]
},
// ... (PHQ-9 문항 2-8 생략)
// PHQ-9 문항 9
{
"id": "q_phq9_q9_uuid",
"orderIndex": 8,
"type": "SINGLE_CHOICE",
"isRequired": true,
"headline": "Wie oft hast du dich im Verlauf der letzten zwei Wochen durch die folgenden Beschwerden beeinträchtigt gefühlt?",
"text": "Gedanken, dass du lieber tot wärst oder dir Leid zufügen möchtest",
"options": [
{ "id": "opt_phq9_q9_0_uuid", "value": "0", "orderIndex": 0, "score": 0, "text": "Überhaupt nicht" },
{ "id": "opt_phq9_q9_1_uuid", "value": "1", "orderIndex": 1, "score": 1, "text": "An einzelnen Tagen" },
{ "id": "opt_phq9_q9_2_uuid", "value": "2", "orderIndex": 2, "score": 2, "text": "An mehr als der Hälfte der Tage" },
{ "id": "opt_phq9_q9_3_uuid", "value": "3", "orderIndex": 3, "score": 3, "text": "Beinahe jeden Tag" }
]
}
]
},
"score": {
"calculationType": "SUM",
"range": {
"min": {
"value": 0
},
"max": {
"value": 27
}
},
"levels": [
{
"id": "sl_phq9_1_uuid",
"range": {
"min": {
"value": 0
},
"max": {
"value": 4
}
},
"label": "Keine oder minimale depressive Symptome",
"chartLabel": "0-4 Punkte",
"description": "Kein Hinweis auf depressive Symptome.",
"feedback": "Ihre Stimmung scheint aktuell stabil zu sein."
},
{
"id": "sl_phq9_2_uuid",
"range": {
"min": {
"value": 5
},
"max": {
"value": 9
}
},
"label": "Leichte depressive Symptome",
"chartLabel": "5-9 Punkte",
"description": "Leichte depressive Symptome können auftreten.",
"feedback": "Es gibt Anzeichen für eine leicht depressive Stimmung."
},
{
"id": "sl_phq9_3_uuid",
"range": {
"min": {
"value": 10
},
"max": {
"value": 14
}
},
"label": "Mittelgradige depressive Symptome",
"chartLabel": "10-14 Punkte",
"description": "Mittelgradige Stimmungsbeeinträchtigung.",
"feedback": "Ihre Stimmung ist spürbar beeinträchtigt."
},
{
"id": "sl_phq9_4_uuid",
"range": {
"min": {
"value": 15
},
"max": {
"value": 19
}
},
"label": "Ausgeprägte depressive Symptome",
"chartLabel": "15-19 Punkte",
"description": "Deutlich beeinträchtigte Stimmung.",
"feedback": "Ihre Stimmung ist deutlich beeinträchtigt."
},
{
"id": "sl_phq9_5_uuid",
"range": {
"min": {
"value": 20
},
"max": {
"value": 27
}
},
"label": "Schwere depressive Symptome",
"chartLabel": "20-27 Punkte",
"description": "Schwere depressive Symptomatik.",
"feedback": "Ihre Symptome sind stark ausgeprägt."
}
]
},
"additionalInformationRules": [
{
"id": "air_phq9_q9_answer1_uuid",
"triggerType": "ANSWER_VALUE",
"questionId": "q_phq9_q9_uuid",
"answerValue": "1",
"content": "Falls du dich stark belastet fühlst oder Suizidgedanken hast, hol dir bitte sofort Unterstützung. Sprich mit deinem Arzt oder deiner Ärztin oder Psychotherapeut*in.\n\n📞 In akuten Krisen:\n\n➡ Deutschland: Notruf 112\n\n➡ Telefonseelsorge: 0800 111 0 111 oder 0800 111 0 222 (kostenlos & anonym)\n\nDu bist nicht allein – es gibt Hilfe."
},
{
"id": "air_phq9_q9_answer2_uuid",
"triggerType": "ANSWER_VALUE",
"questionId": "q_phq9_q9_uuid",
"answerValue": "2",
"content": "Falls du dich stark belastet fühlst oder Suizidgedanken hast, hol dir bitte sofort Unterstützung. Sprich mit deinem Arzt oder deiner Ärztin oder Psychotherapeut*in.\n\n📞 In akuten Krisen:\n\n➡ Deutschland: Notruf 112\n\n➡ Telefonseelsorge: 0800 111 0 111 oder 0800 111 0 222 (kostenlos & anonym)\n\nDu bist nicht allein – es gibt Hilfe."
},
{
"id": "air_phq9_q9_answer3_uuid",
"triggerType": "ANSWER_VALUE",
"questionId": "q_phq9_q9_uuid",
"answerValue": "3",
"content": "Warnhinweis\n\nFalls du dich stark belastet fühlst oder Suizidgedanken hast, hol dir bitte sofort Unterstützung. Sprich mit deinem Arzt oder deiner Ärztin oder Psychotherapeut*in.\n\n📞 In akuten Krisen:\n\n➡ Deutschland: Notruf 112\n\n➡ Telefonseelsorge: 0800 111 0 111 oder 0800 111 0 222 (kostenlos & anonym)\n\nDu bist nicht allein – es gibt Hilfe."
},
{
"id": "air_phq9_score_threshold_uuid",
"triggerType": "SCORE_THRESHOLD",
"minScore": 15,
"content": "Warnhinweis\n\nDeine Antworten deuten darauf hin, dass du dich gerade sehr belastet fühlst. Du bist nicht allein – es gibt Hilfe. Bitte sprich mit einem Arzt oder einer Ärztin oder Psychotherapeut*in darüber.\n\nIn akuten Krisen:\n\nDeutschland: Notruf 112\n\nTelefonseelsorge: 0800 111 0 111 oder 0800 111 0 222 (kostenlos & anonym)\n\nDu bist nicht allein – es gibt Hilfe."
}
]
},
// WIS 설문 정보
{
"id": "q_wis_uuid_example",
"type": "WIS",
"info": {
"title": "WELT Insomnia Scale",
"intro": "Der \"Welt-Insomnia-Scale(WIS)\" wurde von uns entwickelt und besteht aus insgesamt 9 Fragen, die deine Schlafumgebung und deinen Tagesrhythmus berücksichtigen. Deine Antworten helfen uns, eine individuell an deine Bedürfnisse angepasste Strategie zur Verbesserung deines Schlafes entwickeln zu können.\n\nHierbei gibt es keine falschen oder richtigen Antworten, antworte einfach spontan und nach deinem Ermessen.",
"postDescription": "Danke fürs Ausfüllen! Deine Antworten helfen, die Therapie in der App besser auf dich abzustimmen."
},
"question": {
"count": 9,
"questions": [
// WIS 문항 1
{
"id": "q_wis_q1_uuid",
"orderIndex": 0,
"type": "SINGLE_CHOICE",
"isRequired": true,
"headline": "Im folgenden Fragebogen geht es um deine Schlafgewohnheiten, dein Schlafumfeld und deinen Tagesrhythmus.",
"text": "Nimmst du derzeit Schlafmittel ein?",
"options": [
{ "id": "opt_wis_q1_0_uuid", "value": "0", "orderIndex": 0, "text": "Nein" },
{ "id": "opt_wis_q1_1_uuid", "value": "1", "orderIndex": 1, "text": "Ja, täglich" },
{ "id": "opt_wis_q1_2_uuid", "value": "2", "orderIndex": 2, "text": "Ja, aber nur bei Bedarf" }
]
},
// WIS 문항 2
{
"id": "q_wis_q2_uuid",
"orderIndex": 1,
"type": "SINGLE_CHOICE",
"isRequired": true,
"headline": "Im folgenden Fragebogen geht es um deine Schlafgewohnheiten, dein Schlafumfeld und deinen Tagesrhythmus.",
"text": "Schläfst du alleine oder teilst du dein Schlafzimmer mit jemand anderem?",
"options": [
{ "id": "opt_wis_q2_0_uuid", "value": "0", "orderIndex": 0, "text": "Ich schlafe alleine" },
{ "id": "opt_wis_q2_1_uuid", "value": "1", "orderIndex": 1, "text": "Ich schlafe manchmal mit jemand anderem" },
{ "id": "opt_wis_q2_2_uuid", "value": "2", "orderIndex": 2, "text": "Ich schlafe immer mit jemand anderem" }
]
},
// ... (다른 WIS 문항들 생략)
// WIS 문항 6 (TIME 타입)
{
"id": "q_wis_q6_uuid",
"orderIndex": 5,
"type": "TIME",
"isRequired": true,
"headline": "Im folgenden Fragebogen geht es um deine Schlafgewohnheiten, dein Schlafumfeld und deinen Tagesrhythmus.",
"text": "Wann würdest du idealerweise schlafen gehen?",
"range": {
"min": {
"value": 0,
"label": "00:00"
},
"max": {
"value": 1440,
"label": "24:00"
}
}
}
]
},
"score": {
"calculationType": "CUSTOM"
},
"additionalInformationRules": [
{
"id": "wis-rule-001",
"triggerType": "ANSWER_VALUE",
"questionId": "q_wis_q1_uuid",
"answerValue": "1",
"presentationType": "INLINE",
"content": "Bitte gib den Namen des Medikaments an."
},
{
"id": "wis-rule-002",
"triggerType": "ANSWER_VALUE",
"questionId": "q_wis_q1_uuid",
"answerValue": "2",
"presentationType": "INLINE",
"content": "Bitte gib den Namen des Medikaments an."
}
]
}
]
}
- 오류 응답 (404 Not Found)
{
"code": 9010,
"message": "QUESTIONNAIRE_BUNDLE_NOT_FOUND",
"detail": "요청한 번들 버전을 찾을 수 없습니다."
}
{
"code": 9033,
"message": "TRANSLATION_NOT_FOUND",
"detail": "요청한 언어의 번역을 찾을 수 없습니다"
}
- 오류 응답 (500 Internal Server Error)
{
"code": 9000,
"message": "SERVER_ERROR",
"detail": "서버 내부 오류"
}
{
"code": 9500,
"message": "REPOSITORY_ERROR",
"detail": "데이터베이스 접근 중 오류가 발생했습니다"
}
데이터 관리 및 개인정보 보호 API (GDPR 준수)
📌 구현 순서: 핵심 기능 구현 후 GDPR 준수를 위해 구현합니다.
이 API들은 GDPR 준수 및 데이터 보관 정책 요구사항을 지원하기 위해 관리자 또는 사용자가 설문 데이터 생명주기를 관리하는 기능을 제공합니다.
9.1 사용자 설문 데이터 아카이빙 API (관리자용)
- HTTP 메서드: POST
- 경로: /v1/questionnaires/admin/users/
{userId}/archive - Headers:
- Authorization: Bearer
{adminAccessToken}
- Authorization: Bearer
참고: 비활성 상태로 1년 이상 경과한 사용자의 설문 데이터를 콜드 스토리지로 이전합니다. (관련 데이터:
QuestionnaireResponse,QuestionResponse,QuestionnaireRound)
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"status": "ARCHIVED",
"archivedAt": 1735689600000,
"details": {
"archivedResponseCount": 15,
"archivedRoundCount": 4
}
}
- 오류 응답 (404 Not Found) - 사용자 없음
{
"code": 6044,
"message": "USER_NOT_FOUND",
"detail": "사용자를 찾을 수 없습니다."
}
- 오류 응답 (400 Bad Request) - 아카이빙 불가
{
"code": 9101,
"message": "ARCHIVING_NOT_ALLOWED",
"detail": "활성 상태이거나 아카이빙 조건(비활성 1년 경과)을 만족하지 않아 아카이빙할 수 없습니다."
}
- 오류 응답 (500 Server Error) - 아카이빙 실패
{
"code": 9100,
"message": "ARCHIVING_FAILED",
"detail": "설문 데이터 아카이빙 중 오류가 발생했습니다."
}
9.2 사용자 설문 데이터 복원 API (관리자용)
- HTTP 메서드: POST
- 경로: /v1/questionnaires/admin/users/
{userId}/restore - Headers:
- Authorization: Bearer
{adminAccessToken}
- Authorization: Bearer
참고: 콜드 스토리지에 아카이빙된 사용자 설문 데이터를 주 데이터베이스로 복원합니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"status": "ACTIVE",
"restoredAt": 1735776000000,
"details": {
"restoredResponseCount": 15,
"restoredRoundCount": 4
}
}
- 오류 응답 (404 Not Found) - 아카이브 데이터 없음
{
"code": 9102,
"message": "ARCHIVED_DATA_NOT_FOUND",
"detail": "아카이빙된 사용자 설문 데이터를 찾을 수 없습니다."
}
- 오류 응답 (500 Server Error) - 복원 실패
{
"code": 9103,
"message": "RESTORATION_FAILED",
"detail": "설문 데이터 복원 중 오류가 발생했습니다."
}
9.3 사용자 설문 데이터 영구 삭제 API (관리자용)
- HTTP 메서드: DELETE
- 경로: /v1/questionnaires/admin/users/
{userId}/data - Headers:
- Authorization: Bearer
{adminAccessToken}
- Authorization: Bearer
주의: 이 작업은 되돌릴 수 없습니다. 주 데이터베이스 및 콜드 스토리지에서 사용자의 모든 설문 관련 데이터를 영구 삭제합니다.
응답 (Response)
-
성공 응답 (204 No Content)
-
오류 응답 (500 Server Error) - 삭제 실패
{
"code": 9104,
"message": "DELETION_FAILED",
"detail": "설문 데이터 삭제 중 오류가 발생했습니다."
}
9.4 사용자 설문 데이터 익명화 API (관리자용)
- HTTP 메서드: POST
- 경로: /v1/questionnaires/admin/users/
{userId}/anonymize - Headers:
- Authorization: Bearer
{adminAccessToken}
- Authorization: Bearer
참고: 사용자의 개인 식별 정보를 제거하고 통계 분석 등을 위해 설문 응답 데이터를 보존합니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"status": "ANONYMIZED",
"anonymizedAt": 1735862400000,
"details": {
"anonymizedResponseCount": 15
}
}
- 오류 응답 (500 Server Error) - 익명화 실패
{
"code": 9105,
"message": "ANONYMIZATION_FAILED",
"detail": "설문 데이터 익명화 중 오류가 발생했습니다."
}
9.5 내 설문 데이터 추출 요청 API (사용자용)
- HTTP 메서드: GET
- 경로: /v1/questionnaires/users/me/data-export
- 쿼리 파라미터:
- format: 추출 형식 (기본값: "JSON", 가능한 값: "JSON", "CSV")
- questionnaireTypes: 특정 설문 타입만 추출 (선택, 콤마로 구분. 예: "ISI,PHQ9")
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"message": "Questionnaire data export started. You will be notified when it is ready.",
"exportId": "q_export_abc123"
}
- 오류 응답 (400 Bad Request) - 형식 오류
{
"code": 9107,
"message": "INVALID_EXPORT_FORMAT",
"detail": "지원되지 않는 추출 형식입니다. (JSON 또는 CSV 사용)"
}
- 오류 응답 (500 Server Error) - 추출 실패
{
"code": 9106,
"message": "EXPORT_FAILED",
"detail": "설문 데이터 추출 시작 중 오류가 발생했습니다."
}
9.6 특정 사용자 설문 데이터 추출 요청 API (관리자용)
- HTTP 메서드: GET
- 경로: /v1/questionnaires/admin/users/
{userId}/data-export - 쿼리 파라미터:
- format: 추출 형식 (기본값: "JSON", 가능한 값: "JSON", "CSV")
- questionnaireTypes: 특정 설문 타입만 추출 (선택, 콤마로 구분. 예: "ISI,PHQ9")
- Headers:
- Authorization: Bearer
{adminAccessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"message": "Questionnaire data export started for user user_123.",
"exportId": "q_export_def456"
}
관련 문서
- Agent Data 도메인 엔드포인트: /domains/common/core-domains/agent-data/endpoints
오류 코드
설문 도메인 API에서 사용하는 주요 오류 코드는 다음과 같습니다.
| HTTP 상태 코드 | 오류 코드 | 메시지 | 설명 |
|---|---|---|---|
| 500 | 9000 | SERVER_ERROR | 서버 내부 오류 |
| 400 | 9001 | INVALID_INPUT_DATA | 요청 데이터가 유효하지 않음 (필수 필드 누락, 잘못된 형식 등) |
| 409 | 9002 | QUESTIONNAIRE_ALREADY_EXISTS | 이미 존재하는 설문 (questionnaireType이 중복됨) |
| 404 | 9010 | QUESTIONNAIRE_BUNDLE_NOT_FOUND | 요청한 설문 번들을 찾을 수 없음 |
| 404 | 9004 | QUESTION_NOT_FOUND | 요청한 문항을 찾을 수 없음 |
| 404 | 9005 | ROUND_NOT_FOUND | 요청한 회차를 찾을 수 없음 |
| 403 | 2060 | PERMISSION_DENIED | 요청한 작업에 대한 권한 없음 (공통 오류 코드 사용) |
| 409 | 9021 | VERSION_ALREADY_EXISTS | 해당 버전 번호가 이미 존재함 |
| 404 | 9020 | QUESTIONNAIRE_VERSION_NOT_FOUND | 요청한 설문 버전을 찾을 수 없음 |
| 409 | 9023 | ANOTHER_VERSION_ACTIVE | 다른 버전이 이미 활성화되어 있음 |
| 409 | 9024 | NO_ACTIVE_VERSION | 활성화된 버전이 없어 비활성화할 수 없음 |
| 409 | 9031 | QUESTIONNAIRE_CANNOT_BE_DELETED | 사용자 응답이 존재하여 설문을 삭제할 수 없음 |
| 409 | 9041 | QUESTION_CANNOT_BE_DELETED | 사용자 응답이 존재하여 문항을 삭제할 수 없음 |
| 409 | 9051 | INVALID_STATUS_TRANSITION | 현재 상태에서 요청한 상태로 변경 불가능 |
| 409 | 9061 | RESPONSE_ALREADY_EXISTS | 이미 진행 중인 설문 응답이 존재함 |
| 404 | 9062 | RESPONSE_NOT_FOUND | 요청한 응답을 찾을 수 없음 |
| 409 | 9063 | RESPONSE_ALREADY_SUBMITTED | 이미 제출 완료된 응답은 수정 불가능 |
| 409 | 9064 | INVALID_RESPONSE_STATUS | 현재 상태에서 요청한 작업 수행 불가능 |
| 400 | 9065 | REQUIRED_ANSWERS_MISSING | 필수 문항에 대한 응답이 누락됨 |
| 404 | 9071 | QUESTIONNAIRE_RESULT_NOT_FOUND | 요청한 설문 결과를 찾을 수 없음 |
| 404 | 9072 | REPORT_NOT_FOUND | 요청한 보고서를 찾을 수 없음 |
| 500 | 9081 | REPORT_GENERATION_FAILED | 보고서 생성 중 오류 발생 |
| 400 | 9082 | INVALID_CHART_PARAMETERS | 차트 데이터 요청에 유효하지 않은 파라미터 |
| 404 | 9091 | USER_QUESTIONNAIRE_DATA_NOT_FOUND | 해당 사용자의 설문 데이터를 찾을 수 없음 |
| 500 | 9099 | UNKNOWN_QUESTIONNAIRE_ERROR | 알 수 없는 설문 관련 내부 오류 발생 |
| 500 | 9100 | ARCHIVING_FAILED | 설문 데이터 아카이빙 중 오류 발생 |
| 400 | 9101 | ARCHIVING_NOT_ALLOWED | 아카이빙 조건(비활성 1년 경과)을 만족하지 않아 아카이빙할 수 없음 |
| 404 | 9102 | ARCHIVED_DATA_NOT_FOUND | 아카이빙된 사용자 설문 데이터를 찾을 수 없음 |
| 500 | 9103 | RESTORATION_FAILED | 설문 데이터 복원 중 오류 발생 |
| 500 | 9104 | DELETION_FAILED | 설문 데이터 삭제 중 오류 발생 |
| 500 | 9105 | ANONYMIZATION_FAILED | 설문 데이터 익명화 중 오류 발생 |
| 500 | 9106 | EXPORT_FAILED | 설문 데이터 추출 중 오류 발생 |
| 400 | 9107 | INVALID_EXPORT_FORMAT | 지원되지 않는 추출 형식 (JSON 또는 CSV 사용) |
| 404 | 6100 | USER_NOT_FOUND | 사용자를 찾을 수 없음 (Sleep 도메인과 코드 공유 가능성 확인 필요) |
| 400 | 9110 | NO_QUESTIONNAIRE_SCHEDULE_FOR_USER | 해당 사용자에 대한 설문 진행 정보를 찾을 수 없음 |
변경 이력
| 버전 | 날짜 | 작성자 | 변경 내용 |
| ----- | ---------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- |
| 0.1.0 | 2025-05-12 | bok@weltcorp.com | 최초 작성 |
| 0.2.0 | 2025-05-13 | bok@weltcorp.com | 모바일 캐싱을 위한 API 엔드포인트 추가 |
| 0.3.0 | 2025-05-13 | bok@weltcorp.com | GDPR 준수 및 데이터 관리 API 추가 (아카이빙, 복원, 삭제, 익명화, 추출) 및 관련 오류 코드 추가 |
| 0.4.0 | 2025-05-16 | bok@welt.com | 사용자 다음 진행 설문 조회 API 엔드포인트 추가 (GET /v1/users/me/next-pending-questionnaire) |
| 0.4.1 | 2025-05-16 | bok@welt.com | GET /v1/users/me/next-pending-questionnaire API 응답 간소화 (currentRound.questionnaires 내 정보 축소) |
| 0.4.2 | 2025-05-16 | bok@welt.com | GET /v1/users/me/next-pending-questionnaire API 응답의 currentRound.questionnaires에 진행해야 할 설문만 포함하도록 수정 |
| 0.4.3 | 2025-05-16 | bok@welt.com | GET /v1/questionnaires/active-bundle API 응답의 설문 식별자 필드명을 id에서 questionnaireId로 변경하여 통일성 확보 |
| 0.4.4 | 2025-05-16 | bok@welt.com | GET /v1/users/me/next-pending-questionnaire API 응답에서 nextQuestionnaireToProceed 필드 제거 |
| 0.4.5 | 2025-05-16 | bok@welt.com | GET /v1/users/me/next-pending-questionnaire API 응답에서 lastCompletedRound 필드 제거 |
| 0.4.6 | 2025-05-16 | bok@welt.com | GET /v1/users/me/next-pending-questionnaire API "진행할 설문 없는 경우" 응답 수정 (messageKey 제거, currentRound 추가) |
| 0.4.7 | 2025-05-16 | bok@welt.com | GET /v1/users/me/next-pending-questionnaire API "진행할 설문 없는 경우" 응답의 currentRound.status를 COMPLETED로 수정 (도메인 모델과 일치) |
| 0.4.8 | 2025-05-16 | bok@welt.com | GET /v1/users/me/next-pending-questionnaire API 응답에서 nextAction 필드 제거 |
| 0.4.9 | 2025-05-16 | bok@welt.com | GET /v1/users/me/next-pending-questionnaire API 응답에서 roundTitleKey 필드 제거 |
| 0.5.0 | 2025-05-20 | bok@welt.com | GET /v1/users/me/next-pending-questionnaire 엔드포인트를 GET /v1/questionnaires/users/me/schedule/next-pending로 변경하고 관련 설명 수정 |
| 0.5.1 | 2025-05-20 | bok@welt.com | 4.7 회차 누적 결과 조회 API 추가 - GET method로 특정 회차까지의 누적 설문 결과 조회 기능 |
| 0.6.0 | 2025-05-23 | bok@welt.com | 7.6 사용자 전체 회차 결과 조회 API 추가 - 최종 보고서를 위한 모든 회차 설문 결과 조회 기능 |
| 0.6.1 | 2025-05-30 | elizabeth@weltcorp.com | 설문 관련 에러 코드를 5000번대에서 9000번대로 변경 - questionnaire-error-codes.enum.ts와 일치하도록 수정 |
| 0.6.2 | 2025-06-13 | elizabeth@weltcorp.com | 8.1 번들 조회 API에서 언어 지정 방식 변경: Accept-Language 헤더만 지원, language 쿼리 파라미터 제거 및 관련 문서 설명 수정 |
| 0.6.3 | 2025-06-16 | elizabeth@weltcorp.com | 8.1 번들 조회 API의 200 OK 성공 Response DTO 수정 | |
| 0.6.5 | 2025-06-17 | elizabeth@weltcorp.com | 6.1 API에 bundleId query parameter 추가, 번들 업데이트 패턴 적용, questionnaires 배열에서 isCompleted 필드 제거하여 미완료 설문만 반환하도록 수정 |
| 0.6.6 | 2025-06-18 | elizabeth@weltcorp.com | 설문 스케줄링 기능 대폭 개선 - 새로운 컨트롤러 및 DTO 추가, 에러 처리 시스템 강화, 도메인 로직 개선, 사용자 인증 가드 업데이트, 계약 인터페이스 개선 |
| 0.6.0 | 2025-06-23 | elizabeth@weltcorp.com | GET /v1/questionnaires/users/me/schedule/next-pending 엔드포인트를 RESTful 설계에 맞게 GET /v1/questionnaires/bundles/{bundleId}/users/me/schedule/next-pending로 변경, query parameter를 path parameter로 개선, userId는 Authorization 토큰에서 추출 |