Sleep API 엔드포인트
목차
관련 문서
- Agent Data 도메인 엔드포인트: /domains/common/core-domains/agent-data/endpoints
접근 권한 매트릭스
| 엔드포인트 | System Admin | IAM Admin | Service Account | Regular User | 비고 |
|---|---|---|---|---|---|
| POST /v1/sleep/logs/day-index | ✓ | ✓ | ✓ | ✓ | 당일 일차만 가능 |
PATCH /v1/sleep/logs/day-index/{dayIndex} | ✓ | ✓ | ✓ | ✓ | 당일 일차만 가능 |
GET /v1/sleep/logs/day-index/{dayIndex} | ✓ | ✓ | ✓ | ✓ | |
| GET /v1/sleep/logs/day-index-range | ✓ | ✓ | ✓ | ✓ | 일차 범위 조회 |
| POST /v1/sleep/logs/temporary | ✓ | ✓ | ✓ | ✓ | 임시 기록 저장 |
PUT /v1/sleep/logs/temporary/complete/day-index/{dayIndex} | ✓ | ✓ | ✓ | ✓ | 임시→완전 전환 |
GET /v1/sleep/goals/day-index/{dayIndex} | ✓ | ✓ | ✓ | ✓ | |
| GET /v1/sleep/goals/day-index-range | ✓ | ✓ | ✓ | ✓ | 일차 범위 조회 |
GET /v1/sleep/goals/users/{userId}/latest | ✓ | ✓ | ✓ | ✘ | 특정 사용자 최근 목표 조회 |
| GET /v1/sleep/goals/users/me/latest | ✓ | ✓ | ✓ | ✓ | 내 최근 목표 조회 |
| PUT /v1/sleep/goals/target-wake-time | ✓ | ✓ | ✓ | ✓ | rTIB 처방일에만 가능 |
GET /v1/sleep/rtib/day-index/{dayIndex} | ✓ | ✓ | ✓ | ✓ | |
| GET /v1/sleep/rtib/eligibility | ✓ | ✓ | ✓ | ✓ | rTIB 계산 자격 확인 |
GET /v1/sleep/goal-adherence/day-index/{dayIndex} | ✓ | ✓ | ✓ | ✓ | |
| GET /v1/sleep/goal-adherence/day-index-range | ✓ | ✓ | ✓ | ✓ | 일차 범위 조회 |
| GET /v1/sleep/statistics/weekly | ✓ | ✓ | ✓ | ✓ | 주차별 통계 |
| GET /v1/sleep/statistics/weekly/efficiency | ✓ | ✓ | ✓ | ✓ | 수면 효율 통계 |
| GET /v1/sleep/statistics/weekly/quality | ✓ | ✓ | ✓ | ✓ | 수면의 질 통계 |
| GET /v1/sleep/statistics/weekly/tst | ✓ | ✓ | ✓ | ✓ | 총 수면 시간 통계 |
| GET /v1/sleep/statistics/weekly/medication | ✓ | ✓ | ✓ | ✓ | 수면제 복용 통계 |
| GET /v1/sleep/statistics/weekly/sol | ✓ | ✓ | ✓ | ✓ | SOL 통계 |
| GET /v1/sleep/statistics/weekly/nap-time | ✓ | ✓ | ✓ | ✓ | 낮잠 시간 통계 |
| GET /v1/sleep/statistics/weekly/factors | ✓ | ✓ | ✓ | ✓ | 영향 요인 통계 |
| GET /v1/sleep/statistics/weekly/goal-adherence | ✓ | ✓ | ✓ | ✓ | 목표 달성 통계 |
| GET /v1/sleep/statistics/custom-range | ✓ | ✓ | ✓ | ✓ | 사용자 지정 범위 |
GET /v1/sleep/admin/data/{userId} | ✓ | ✓ | ✓ | ✘ | 관리자 데이터 접근 |
POST /v1/sleep/admin/users/{userId}/archive | ✓ | ✓ | ✘ | ✘ | 사용자 데이터 아카이빙 |
POST /v1/sleep/admin/users/{userId}/restore | ✓ | ✓ | ✘ | ✘ | 사용자 데이터 복원 |
DELETE /v1/sleep/admin/users/{userId}/data | ✓ | ✓ | ✘ | ✘ | 사용자 데이터 영구 삭제 |
POST /v1/sleep/admin/users/{userId}/anonymize | ✓ | ✓ | ✘ | ✘ | 사용자 데이터 익명화 |
| GET /v1/sleep/users/me/data-export | ✘ | ✘ | ✘ | ✓ | 내 데이터 추출 요청 |
GET /v1/sleep/admin/users/{userId}/data-export | ✓ | ✓ | ✘ | ✘ | 특정 사용자 데이터 추출 요청 |
참고:
- ✓: 접근 가능
- ✘: 접근 불가
- (범위 내): 할당된 조직/팀 범위 내에서만 접근 가능
- (자신만): 자신의 데이터에만 접근 가능
수면 기록 API
📌 구현 순서: 수면 기록 관리는 Sleep 도메인의 핵심 기능이며 가장 먼저 구현되어야 합니다.
수면 기록 API는 사용자의 일일 수면 데이터를 생성, 조회, 수정하는 기능을 제공합니다. 수면 기록은 당일 일차에 한해 생성 및 수정이 가능하며, 일차가 변경된 이후에는 수정이 불가능합니다.
2.1 수면 기록 생성 API
- HTTP 메서드: POST
- 경로: /v1/sleep/logs/day-index
- Headers:
- Content-Type: application/json
- Authorization: Bearer
{accessToken}
요청 (Request)
{
"dayIndex": 5,
"dns": false,
"pill": false,
"negativeFactorIds": [1, 2, 3],
"positiveFactorIds": [4],
"napMinutes": 30,
"lot": 1748268000000,
"aet": 1748300400000,
"sleepQuality": 3,
"solMinutes": 15,
"wasoMinutes": 20,
"tstMinutes": 505
}
참고:
dns가 true인 경우(전혀 못 잤을 경우) 필수 항목은negativeFactorIds,pill,napMinutes입니다.dns가 false인 경우(잠을 잤을 경우) 필수 항목은lot,aet,sleepQuality,solMinutes,wasoMinutes,positiveFactorIds,negativeFactorIds,pill,napMinutes입니다.lot,aet는 ISO 8601 형식의 Date 객체로 제공해야 하며, 5분 단위여야 합니다.lot(잠자리에 든 시각)는 18:00 이후 또는 새벽시간(0~6시)이어야 합니다.tstMinutes는 선택적 필드이며, 제공할 경우 시스템이 계산한 값과 정확히 일치해야 합니다. (TST = TIB - SOL - WASO)- 당일 일차(현재 진행 중인 일차)에만 생성이 가능합니다.
응답 (Response)
- 성공 응답 (201 Created)
{
"sleepLog": {
"id": "d2f6d3e7-bf74-45dd-aeef-102a3f9671d3",
"dayIndex": 5,
"date": "2025-05-27",
"dns": false,
"lot": 1748300400000,
"aet": 1748332800000,
"tstMinutes": 505,
"sleepEfficiency": 0.94,
"sleepQuality": 3,
"positiveFactorIds": [4],
"negativeFactorIds": [1, 2, 3],
"pill": false,
"napMinutes": 30,
"positiveCustomFactors": [],
"negativeCustomFactors": [],
"timezoneId": "Asia/Seoul",
"timezoneOffset": 540,
"isTemporary": false,
"createdAt": 1748311037142,
"updatedAt": 1748311037142
},
"goalAdherence": {
"id": "adh_12345",
"dayIndex": 7,
"date": "2025-05-10",
"sleepGoalId": "sg_12345",
"bedTimeGoalMet": true,
"wakeTimeGoalMet": false,
"createdAt": 1715315400000,
"updatedAt": 1715315400000
}
}
참고:
tstMinutes(총 수면 시간)와sleepEfficiency(수면 효율)는 시스템에서 자동 계산됩니다.goalAdherence는 수면 목표가 존재하지 않으면 Null입니다.- 응답의
date는 사용자 시간대 기준 날짜 문자열(YYYY-MM-DD)입니다.lot,aet는 ISO 8601 형식의 Date 객체로 응답됩니다.createdAt,updatedAt은 Unix timestamp(밀리초) 형식입니다.sleepQuality는 1(매우 나쁨)부터 5(매우 좋음)까지의 수면의 질 점수입니다.
- 오류 응답 (400 Bad Request - DNS=false일 때 필수 필드 누락)
{
"code": 10001,
"message": "MISSING_REQUIRED_FIELDS",
"detail": "잠을 잤을 경우 필수 입력 항목이 누락되었습니다.",
"fields": ["sleepQuality", "lot", "aet"]
}
- 오류 응답 (400 Bad Request - 날짜 유효성 검증 실패)
{
"code": 10009,
"message": "DATE_VALIDATION_FAILED",
"detail": "수면 기록은 당일 일차에 한해서만 생성/수정이 가능합니다."
}
- 오류 응답 (400 Bad Request - 시간 유효성 검증 실패)
{
"code": 10008,
"message": "SLEEP_TIME_VALIDATION_FAILED",
"detail": "LOT는 18:00 이후여야 하고, 시간 값은 5분 단위여야 하며, AET는 LOT보다 이후여야 합니다."
}
- 오류 응답 (400 Bad Request - TST 불일치)
{
"code": 10013,
"message": "INVALID_TST",
"detail": "계산된 총 수면 시간(TST)과 제공된 값이 일치하지 않습니다."
}
- 오류 응답 (400 Bad Request - DNS=true일 때 수면 데이터 포함)
{
"code": 10014,
"message": "UNEXPECTED_SLEEP_DATA",
"detail": "DNS=true인 경우 수면 관련 데이터(lot, aet, solMinutes, wasoMinutes, tstMinutes)를 입력할 수 없습니다."
}
- 오류 응답 (403 Forbidden - 치료 활동 일시 정지)
{
"code": 10010,
"message": "TREATMENT_SUSPENDED",
"detail": "치료 활동 일시 정지 상태에서는 수면 기록을 생성할 수 없습니다."
}
- 오류 응답 (409 Conflict - 중복 기록)
{
"code": 10090,
"message": "SLEEP_LOG_ALREADY_EXISTS",
"detail": "해당 날짜에 이미 수면 기록이 존재합니다."
}
2.2 수면 기록 수정 API
- HTTP 메서드: PATCH
- 경로: /v1/sleep/logs/day-index/
{dayIndex} - Headers:
- Content-Type: application/json
- Authorization: Bearer
{accessToken}
요청 (Request)
{
"dns": false,
"lot": 1715299700000,
"sleepQuality": 3,
"negativeFactorIds": [2, 4],
"pill": true
}
참고: 수정 API는 부분 업데이트를 지원하므로 변경하려는 필드만 포함하면 됩니다.
dns상태를 변경할 경우, 해당 상태에 맞는 필수 항목 검증이 다시 적용됩니다.dns를 false에서 true로 변경 시, DNS에 필요한 데이터 외의 모든 항목은 자동 초기화됩니다. 당일 일차(현재 진행 중인 일차)에만 수정이 가능합니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "sl_12345",
"dayIndex": 7,
"date": "2025-05-10",
"dns": false,
"lot": 1715299700000,
"aet": 1715329800000,
"tstMinutes": 465,
"sleepEfficiency": 0.92,
"solMinutes": 30,
"wasoMinutes": 15,
"sleepQuality": 3,
"positiveFactorIds": [1, 3, 5],
"negativeFactorIds": [2, 4],
"pill": true,
"napMinutes": 20,
"positiveCustomFactors": ["좋은 베개"],
"negativeCustomFactors": ["옆방 소음"],
"timezoneId": "Asia/Seoul",
"timezoneOffset": 540,
"isTemporary": false,
"createdAt": 1715311800000,
"updatedAt": 1715313600000
}
- 오류 응답 (404 Not Found)
{
"code": 10040,
"message": "SLEEP_LOG_NOT_FOUND",
"detail": "해당 일차의 수면 기록을 찾을 수 없습니다."
}
2.3 수면 기록 조회 API (일차별)
- HTTP 메서드: GET
- 경로: /v1/sleep/logs/day-index/
{dayIndex} - Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "sl_12345",
"dayIndex": 7,
"date": "2025-05-10",
"dns": false,
"lot": 1748300400000,
"aet": 1748332800000,
"tstMinutes": 465,
"sleepEfficiency": 0.92,
"solMinutes": 30,
"wasoMinutes": 15,
"sleepQuality": 3,
"positiveFactorIds": [1, 3, 5],
"negativeFactorIds": [2, 4],
"pill": true,
"napMinutes": 20,
"positiveCustomFactors": ["좋은 베개"],
"negativeCustomFactors": ["옆방 소음"],
"timezoneId": "Asia/Seoul",
"timezoneOffset": 540,
"isTemporary": false,
"createdAt": 1715311800000,
"updatedAt": 1715313600000
}
참고:
tstMinutes(총 수면 시간)와sleepEfficiency(수면 효율)는 시스템에서 자동 계산됩니다.date는 사용자 시간대 기준 날짜 문자열(YYYY-MM-DD)입니다.lot,aet,createdAt,updatedAt은 Unix timestamp(밀리초) 형식입니다.
- 오류 응답 (404 Not Found)
{
"code": 10040,
"message": "SLEEP_LOG_NOT_FOUND",
"detail": "해당 일차의 수면 기록을 찾을 수 없습니다."
}
2.4 수면 기록 조회 API (일차 범위)
- HTTP 메서드: GET
- 경로: /v1/sleep/logs/day-index-range
- 쿼리 파라미터:
- startDayIndex: 시작 일차
- endDayIndex: 종료 일차
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"items": [
{
"sleepLog": {
"id": "1b09aed9-ed4a-4c0c-ac9e-0450cf1dfc70",
"dayIndex": 1,
"date": "2025-06-12",
"dns": false,
"lot": 1749650400000,
"aet": 1749679200000,
"tstMinutes": 480,
"sleepEfficiency": 1,
"solMinutes": 0,
"wasoMinutes": 0,
"sleepQuality": 4,
"positiveFactorIds": [3, 4],
"negativeFactorIds": [3, 4],
"pill": true,
"napMinutes": 30,
"positiveCustomFactors": ["충분한 운동", "따뜻한 샤워"],
"negativeCustomFactors": [],
"timezone": {
"id": "Asia/Seoul",
"offsetInMinutes": 540
},
"isTemporary": false,
"createdAt": 1749716192050,
"updatedAt": 1749716343687
},
"goalAdherence": null
},
{
"sleepLog": {
"id": "e4abdcc0-be20-42d2-ba57-fc8e77b4221e",
"dayIndex": 2,
"date": "2025-06-17",
"dns": false,
"lot": 1750082400000,
"aet": 1750114800000,
"tstMinutes": 505,
"sleepEfficiency": 0.93519,
"solMinutes": 15,
"wasoMinutes": 20,
"sleepQuality": 4,
"positiveFactorIds": [1],
"negativeFactorIds": [3],
"pill": false,
"napMinutes": 30,
"positiveCustomFactors": [],
"negativeCustomFactors": [],
"timezone": {
"id": "Asia/Seoul",
"offsetInMinutes": 540
},
"isTemporary": false,
"createdAt": 1750145181477,
"updatedAt": 1750145773922
},
"goalAdherence": null
},
{
"sleepLog": {
"id": "b70a376b-c548-488d-a9b1-450222a3c314",
"dayIndex": 3,
"date": "2025-06-18",
"dns": false,
"lot": 1750183200000,
"aet": 1750194000000,
"tstMinutes": 145,
"sleepEfficiency": 0.80556,
"solMinutes": 15,
"wasoMinutes": 20,
"sleepQuality": 4,
"positiveFactorIds": [3, 4],
"negativeFactorIds": [2],
"pill": false,
"napMinutes": 30,
"positiveCustomFactors": ["충분한 운동", "따뜻한 샤워"],
"negativeCustomFactors": ["늦은 카페인 섭취", "스마트폰 사용"],
"timezone": {
"id": "Asia/Seoul",
"offsetInMinutes": 540
},
"isTemporary": false,
"createdAt": 1750211600306,
"updatedAt": 1750224769996
},
"goalAdherence": null
},
{
"sleepLog": {
"id": "80117adb-d727-462c-8e84-f60b5180e398",
"dayIndex": 9,
"date": "2025-06-24",
"dns": true,
"lot": null,
"aet": null,
"tstMinutes": null,
"sleepEfficiency": null,
"solMinutes": null,
"wasoMinutes": null,
"sleepQuality": null,
"positiveFactorIds": [],
"negativeFactorIds": [2],
"pill": false,
"napMinutes": 30,
"positiveCustomFactors": [],
"negativeCustomFactors": [],
"timezone": {
"id": "Asia/Seoul",
"offsetInMinutes": 540
},
"isTemporary": false,
"createdAt": 1750754142818,
"updatedAt": 1750755467951
},
"goalAdherence": {
"id": "4b5a87d5-2c8d-436a-a591-220238e1294c",
"targetDayIndex": 9,
"targetDate": "2025-06-24",
"sleepGoalId": "dsfdsafdsafdasfasdf",
"lotSuccess": false,
"aetSuccess": false,
"createdAt": 1750753836510,
"updatedAt": 1750753831032
}
}
],
"count": 4,
"startDayIndex": 1,
"endDayIndex": 9
}
2.5 임시 수면 기록 저장 API
- HTTP 메서드: POST
- 경로: /v1/sleep/logs/temporary
- Headers:
- Content-Type: application/json
- Authorization: Bearer
{accessToken}
요청 (Request)
{
"dayIndex": 7,
"lot": 1715300400000,
"sleepQuality": 4,
"pill": false,
"timezoneId": "Asia/Seoul",
"timezoneOffset": 540
}
참고: 임시 수면 기록은 최소한
lot,aet,sleepQuality,pill중 하나 이상의 정보가 필요합니다. 일차(dayIndex)는 필수로 지정해야 합니다.
응답 (Response)
- 성공 응답 (201 Created)
{
"id": "sl_12345",
"dayIndex": 7,
"date": "2025-05-10",
"dns": false,
"lot": 1715300400000,
"sleepQuality": 4,
"pill": false,
"timezoneId": "Asia/Seoul",
"timezoneOffset": 540,
"isTemporary": true,
"createdAt": 1715311800000,
"updatedAt": 1715311800000
}
2.6 임시 수면 기록 완성 API
- HTTP 메서드: PUT
- 경로: /v1/sleep/logs/temporary/complete/day-index/
{dayIndex} - Headers:
- Content-Type: application/json
- Authorization: Bearer
{accessToken}
요청 (Request)
{
"dns": false,
"aet": 1715329800000,
"solMinutes": 30,
"wasoMinutes": 15,
"positiveFactorIds": [1, 3, 5],
"negativeFactorIds": [2],
"napMinutes": 20
}
참고: 이 API는 기존 임시 기록을 완전한 수면 기록으로 전환합니다. 필수 항목 중 누락된 항목을 모두 포함해야 합니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "sl_12345",
"dayIndex": 7,
"date": "2025-05-10",
"dns": false,
"lot": 1715300400000,
"aet": 1715329800000,
"tstMinutes": 450,
"sleepEfficiency": 0.9,
"solMinutes": 30,
"wasoMinutes": 15,
"sleepQuality": 4,
"positiveFactorIds": [1, 3, 5],
"negativeFactorIds": [2],
"pill": false,
"napMinutes": 20,
"timezoneId": "Asia/Seoul",
"timezoneOffset": 540,
"isTemporary": false,
"createdAt": 1715311800000,
"updatedAt": 1715315400000
}
- 오류 응답 (404 Not Found)
{
"code": 10045,
"message": "TEMPORARY_SLEEP_LOG_NOT_FOUND",
"detail": "해당 일차의 임시 수면 기록을 찾을 수 없습니다."
}
수면 목표 및 rTIB API
📌 구현 순서: 수면 기록 API 구현 후 진행합니다.
수면 목표 및 rTIB API는 수면 목표 조회, rTIB(권장 침대 체류 시간) 계산 및 제공, 목표 기상 시각 설정 등의 기능을 제공합니다. rTIB 계산은 직전 7일간의 유효한 수면 기록을 기반으로 수행됩니다.
3.1 수면 목표 조회 API (일차별)
- HTTP 메서드: GET
- 경로: /v1/sleep/goals/day-index/
{dayIndex} - Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "sg_12345",
"targetDayIndex": 8,
"targetLOT": 1715295600000,
"targetAET": 1715324400000,
"rTIBMinutes": 480,
"goalType": "RTIB_ALGORITHM"
}
- 오류 응답 (404 Not Found)
{
"code": 10041,
"message": "SLEEP_GOAL_NOT_FOUND",
"detail": "해당 일차의 수면 목표를 찾을 수 없습니다."
}
3.2 수면 목표 조회 API (일차 범위)
- HTTP 메서드: GET
- 경로: /v1/sleep/goals/day-index-range
- 쿼리 파라미터:
- startDayIndex: 시작 일차
- endDayIndex: 종료 일차
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"items": [
{
"id": "sg_12345",
"targetDayIndex": 8,
"targetLOT": 1715295600000,
"targetAET": 1715324400000,
"rTIBMinutes": 480,
"goalType": "RTIB_ALGORITHM"
},
{
"id": "sg_12346",
"targetDayIndex": 9,
"targetLOT": 1715382000000,
"targetAET": 1715410800000,
"rTIBMinutes": 480,
"goalType": "SYSTEM"
}
],
"count": 2,
"startTargetDayIndex": 8,
"endTargetDayIndex": 9
}
- 오류 응답 (400 Bad Request)
{
"code": 10002,
"message": "INVALID_PARAMETERS",
"detail": "잘못된 파라미터입니다. startDayIndex는 endDayIndex보다 작거나 같아야 합니다."
}
- 오류 응답 (400 Bad Request - 일차 범위 초과)
{
"code": 10012,
"message": "INVALID_DAY_INDEX",
"detail": "유효하지 않은 일차 값입니다."
}
3.3 목표 기상 시각 설정 API
- HTTP 메서드: PATCH
- 경로: /v1/sleep/goals/target-wake-time
- Headers:
- Content-Type: application/json
- Authorization: Bearer
{accessToken}
중요: 이 API는 rTIB를 처방받은 당일에 사용하며, 다음 일차(내일)의 목표 수면 시간을 설정하는 용도입니다. 목표 기상 시각 변경 시 목표 취침 시각도 연동되어 자동으로 계산됩니다.
rTIB 처방은 일반적으로 다음과 같은 흐름으로 이루어집니다:
- 사용자가 7일차에 수면 기록을 작성하면, 최소 4개 이상의 유효한 수면 기록이 확보된 경우 즉시 rTIB가 계산됩니다.
- 이 계산된 rTIB는 8일차부터 적용될 수면 목표를 위한 것입니다.
- 사용자는 7일차에 처방받은 rTIB에 대해 목표 기상 시각을 설정할 수 있으며, 이렇게 설정된 목표는 8일차부터 적용됩니다.
예를 들어, 현재 7일차(dayIndex: 7)에 rTIB 처방을 받았다면, 이 API를 통해 8일차(dayIndex: 8)의 목표 기상 시각을 설정합니다.
요청 (Request)
{
"targetAET": "07:30",
"targetDayIndex": 8,
"targetDate": "2025-05-11"
}
참고:
targetDayIndex: 목표를 적용할 다음 일차(현재 일차 + 1)targetDate: 목표가 적용될 실제 날짜 (YYYY-MM-DD 형식)targetAET: 설정하고자 하는 목표 기상 시각 (HH:MM 형식)
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "sg_12345",
"targetDayIndex": 8,
"targetDate": "2025-05-11",
"targetLOT": 1715385000000,
"targetAET": 1715412600000,
"rTIBInMinutes": 480,
"goalType": "USER",
"timezoneId": "Asia/Seoul",
"timezoneOffset": 540,
"createdAt": 1715225400000,
"updatedAt": 1715315400000
}
- 오류 응답 (400 Bad Request)
{
"code": 10016,
"message": "TARGET_WAKE_TIME_CHANGE_NOT_ALLOWED",
"detail": "목표 기상 시각은 rTIB 처방을 받은 당일에만 다음 일차를 위해 설정할 수 있습니다."
}
3.4 최근 수면 목표 조회 API (사용자용)
- HTTP 메서드: GET
- 경로: /v1/sleep/goals/users/me/latest
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "sg_12345",
"targetDayIndex": 8,
"targetLOT": 1715295600000,
"targetAET": 1715324400000,
"rTIBMinutes": 480,
"goalType": "RTIB_ALGORITHM"
}
- 오류 응답 (404 Not Found)
{
"code": 10041,
"message": "SLEEP_GOAL_NOT_FOUND",
"detail": "수면 목표를 찾을 수 없습니다."
}
3.5 최근 수면 목표 조회 API (관리자용)
- HTTP 메서드: GET
- 경로: /v1/sleep/goals/users/
{userId}/latest - Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
중요: 이 API는 관리자 및 서비스 계정만 접근 가능합니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"goal": {
"id": "sg_12345",
"targetDayIndex": 8,
"targetLOT": 1715295600000,
"targetAET": 1715324400000,
"rTIBMinutes": 480,
"goalType": "RTIB_ALGORITHM"
}
}
- 오류 응답 (404 Not Found)
{
"code": 10044,
"message": "USER_NOT_FOUND",
"detail": "사용자를 찾을 수 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 10041,
"message": "SLEEP_GOAL_NOT_FOUND",
"detail": "해당 사용자의 수면 목표를 찾을 수 없습니다."
}
3.7 rTIB 조회 API
- HTTP 메서드: GET
- 경로: /v1/sleep/rtib/day-index/
{dayIndex} - Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "rtib_123",
"dayIndex": 7,
"date": "2025-05-10",
"rTIB": 480,
"calculationBasis": {
"avgTstMinutes": 450,
"avgSe": 0.9,
"avgDse": 500,
"startDayIndex": 1,
"endDayIndex": 6,
"validLogCount": 7,
"isFirstRtib": false
},
"calculatedOnSleepLogCreation": false,
"createdAt": 1715225400000
}
- 오류 응답 (404 Not Found)
{
"code": 10042,
"message": "RTIB_RECOMMENDATION_NOT_FOUND",
"detail": "해당 일차의 rTIB 처방을 찾을 수 없습니다."
}
3.8 rTIB 계산 자격 확인 API
- HTTP 메서드: GET
- 경로: /v1/sleep/rtib/eligibility
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"eligible": true,
"reason": "FOLLOW_UP_RTIB_ELIGIBLE",
"details": {
"lastRtibDayIndex": 1,
"daysSinceLastRtib": 7,
"validLogsCount": 6
}
}
- 성공 응답 (자격 없음) (200 OK)
{
"eligible": false,
"reason": "INSUFFICIENT_DATA",
"details": {
"lastRtibDayIndex": 1,
"daysSinceLastRtib": 7,
"validLogsCount": 3,
"requiredLogs": 5
}
}
3.9 수면 목표 달성 여부 조회 API (일차별)
- HTTP 메서드: GET
- 경로: /v1/sleep/goal-adherence/day-index/
{dayIndex} - Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "adh_12345",
"dayIndex": 7,
"date": "2025-05-10",
"sleepGoalId": "sg_12345",
"bedTimeGoalMet": true,
"wakeTimeGoalMet": false,
"createdAt": 1715315400000,
"updatedAt": 1715315400000,
"goal": {
"targetLOT": 1715295600000,
"targetAET": 1715324400000
},
"actual": {
"lot": 1715299700000,
"aet": 1715329800000
}
}
3.10 수면 목표 달성 여부 조회 API (일차 범위)
- HTTP 메서드: GET
- 경로: /v1/sleep/goal-adherence/day-index-range
- 쿼리 파라미터:
- startDayIndex: 시작 일차
- endDayIndex: 종료 일차
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"items": [
{
"id": "adh_12345",
"dayIndex": 7,
"date": "2025-05-10",
"bedTimeGoalMet": true,
"wakeTimeGoalMet": false,
"goal": {
"targetLOT": 1715295600000,
"targetAET": 1715324400000
},
"actual": {
"lot": 1715299700000,
"aet": 1715329800000
}
},
{
"id": "adh_12346",
"dayIndex": 8,
"date": "2025-05-11",
"bedTimeGoalMet": true,
"wakeTimeGoalMet": true,
"goal": {
"targetLOT": 1715382000000,
"targetAET": 1715410800000
},
"actual": {
"lot": 1715380700000,
"aet": 1715409100000
}
}
],
"count": 2,
"startDayIndex": 7,
"endDayIndex": 8
}
수면 통계 API
📌 구현 순서: 수면 기록 및 목표 API 구현 후 진행합니다.
수면 통계 API는 주차별 수면 데이터 통계 및 다양한 시간 범위의 수면 데이터를 제공합니다. 주차는 연속된 7일 단위이며, 시작 일차(dayIndex)를 기준으로 합니다.
4.1 주차별 종합 통계 API
- HTTP 메서드: GET
- 경로: /v1/sleep/statistics/weekly
- 쿼리 파라미터:
- startDayIndex: 주차 시작 일차
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"userCycleId": "uc_456",
"startDayIndex": 7,
"endDayIndex": 13,
"se": {
"dailyData": [
{ "dayIndex": 7, "date": "2025-05-10", "value": 0.9 },
{ "dayIndex": 8, "date": "2025-05-11", "value": 0.94 },
{ "dayIndex": 9, "date": "2025-05-12", "value": 0.88 },
{ "dayIndex": 10, "date": "2025-05-13", "value": 0.92 },
{ "dayIndex": 11, "date": "2025-05-14", "value": 0.85 },
{ "dayIndex": 12, "date": "2025-05-15", "value": null },
{ "dayIndex": 13, "date": "2025-05-16", "value": 0.91 }
],
"average": 0.9,
"categories": {
"poor": 1,
"moderate": 3,
"good": 2
}
},
"sleepQuality": {
"dailyData": [
{ "dayIndex": 7, "date": "2025-05-10", "value": 3 },
{ "dayIndex": 8, "date": "2025-05-11", "value": 4 },
{ "dayIndex": 9, "date": "2025-05-12", "value": 3 },
{ "dayIndex": 10, "date": "2025-05-13", "value": 4 },
{ "dayIndex": 11, "date": "2025-05-14", "value": 2 },
{ "dayIndex": 12, "date": "2025-05-15", "value": null },
{ "dayIndex": 13, "date": "2025-05-16", "value": 3 }
],
"distribution": {
"1": { "count": 0, "percentage": 0 },
"2": { "count": 1, "percentage": 16.7 },
"3": { "count": 3, "percentage": 50.0 },
"4": { "count": 2, "percentage": 33.3 },
"5": { "count": 0, "percentage": 0 }
}
},
"tstMinutes": {
"dailyData": [
{ "dayIndex": 7, "date": "2025-05-10", "value": 450 },
{ "dayIndex": 8, "date": "2025-05-11", "value": 480 },
{ "dayIndex": 9, "date": "2025-05-12", "value": 440 },
{ "dayIndex": 10, "date": "2025-05-13", "value": 460 },
{ "dayIndex": 11, "date": "2025-05-14", "value": 420 },
{ "dayIndex": 12, "date": "2025-05-15", "value": 0 },
{ "dayIndex": 13, "date": "2025-05-16", "value": 455 }
],
"average": 450.8,
"min": 420,
"max": 480
},
"sleepMedication": {
"dailyData": [
{ "dayIndex": 7, "date": "2025-05-10", "value": true },
{ "dayIndex": 8, "date": "2025-05-11", "value": false },
{ "dayIndex": 9, "date": "2025-05-12", "value": false },
{ "dayIndex": 10, "date": "2025-05-13", "value": false },
{ "dayIndex": 11, "date": "2025-05-14", "value": true },
{ "dayIndex": 12, "date": "2025-05-15", "value": true },
{ "dayIndex": 13, "date": "2025-05-16", "value": false }
],
"totalDays": 3,
"percentage": 42.9
},
"solMinutes": {
"dailyData": [
{ "dayIndex": 7, "date": "2025-05-10", "value": 30 },
{ "dayIndex": 8, "date": "2025-05-11", "value": 20 },
{ "dayIndex": 9, "date": "2025-05-12", "value": 35 },
{ "dayIndex": 10, "date": "2025-05-13", "value": 25 },
{ "dayIndex": 11, "date": "2025-05-14", "value": 40 },
{ "dayIndex": 12, "date": "2025-05-15", "value": null },
{ "dayIndex": 13, "date": "2025-05-16", "value": 30 }
],
"average": 30,
"min": 20,
"max": 40
},
"napMinutes": {
"dailyData": [
{ "dayIndex": 7, "date": "2025-05-10", "value": 20 },
{ "dayIndex": 8, "date": "2025-05-11", "value": 0 },
{ "dayIndex": 9, "date": "2025-05-12", "value": 30 },
{ "dayIndex": 10, "date": "2025-05-13", "value": 0 },
{ "dayIndex": 11, "date": "2025-05-14", "value": 15 },
{ "dayIndex": 12, "date": "2025-05-15", "value": 45 },
{ "dayIndex": 13, "date": "2025-05-16", "value": 0 }
],
"average": 15.7,
"count": 110
},
"sleepFactors": {
"positive": {
"topFactors": [
{ "id": 3, "title": "좋은 기분", "count": 4, "percentage": 66.7 },
{ "id": 1, "title": "야외에서의 운동", "count": 3, "percentage": 50.0 },
{ "id": 5, "title": "이완 운동", "count": 2, "percentage": 33.3 }
],
"dailyData": [
{
"dayIndex": 7,
"date": "2025-05-10",
"factors": [
{ "id": 1, "title": "야외에서의 운동" },
{ "id": 3, "title": "좋은 기분" },
{ "id": 5, "title": "이완 운동" }
]
},
{ "dayIndex": 8, "date": "2025-05-11", "factors": [{ "id": 3, "title": "좋은 기분" }] },
{
"dayIndex": 9,
"date": "2025-05-12",
"factors": [
{ "id": 1, "title": "야외에서의 운동" },
{ "id": 3, "title": "좋은 기분" }
]
},
{ "dayIndex": 10, "date": "2025-05-13", "factors": [{ "id": 4, "title": "낮 동안의 햇빛" }] },
{
"dayIndex": 11,
"date": "2025-05-14",
"factors": [
{ "id": 1, "title": "야외에서의 운동" },
{ "id": 5, "title": "이완 운동" }
]
},
{ "dayIndex": 12, "date": "2025-05-15", "factors": [] },
{ "dayIndex": 13, "date": "2025-05-16", "factors": [{ "id": 3, "title": "좋은 기분" }] }
]
},
"negative": {
"topFactors": [
{ "id": 2, "title": "스트레스나 걱정", "count": 5, "percentage": 71.4 },
{ "id": 4, "title": "저녁에 카페인/알코올 섭취", "count": 2, "percentage": 28.6 },
{ "id": 5, "title": "통증이나 불편함", "count": 1, "percentage": 14.3 }
],
"dailyData": [
{
"dayIndex": 7,
"date": "2025-05-10",
"factors": [
{ "id": 2, "title": "스트레스나 걱정" },
{ "id": 4, "title": "저녁에 카페인/알코올 섭취" }
]
},
{ "dayIndex": 8, "date": "2025-05-11", "factors": [{ "id": 2, "title": "스트레스나 걱정" }] },
{ "dayIndex": 9, "date": "2025-05-12", "factors": [{ "id": 2, "title": "스트레스나 걱정" }] },
{ "dayIndex": 10, "date": "2025-05-13", "factors": [{ "id": 5, "title": "통증이나 불편함" }] },
{
"dayIndex": 11,
"date": "2025-05-14",
"factors": [
{ "id": 2, "title": "스트레스나 걱정" },
{ "id": 4, "title": "저녁에 카페인/알코올 섭취" }
]
},
{ "dayIndex": 12, "date": "2025-05-15", "factors": [{ "id": 2, "title": "스트레스나 걱정" }] },
{ "dayIndex": 13, "date": "2025-05-16", "factors": [] }
]
}
},
"goalAdherence": {
"dailyData": [
{
"dayIndex": 7,
"targetLOT": 1715295600000,
"actualBedTime": 1715299700000,
"bedTimeGoalMet": true,
"targetAET": 1715324400000,
"actualWakeTime": 1715329800000,
"wakeTimeGoalMet": false
},
{
"dayIndex": 8,
"targetLOT": 1715382000000,
"actualBedTime": 1715380700000,
"bedTimeGoalMet": true,
"targetAET": 1715410800000,
"actualWakeTime": 1715409100000,
"wakeTimeGoalMet": true
},
{
"dayIndex": 9,
"targetLOT": 1715468400000,
"actualBedTime": 1715470400000,
"bedTimeGoalMet": true,
"targetAET": 1715497200000,
"actualWakeTime": 1715498400000,
"wakeTimeGoalMet": true
},
{
"dayIndex": 10,
"targetLOT": 1715554800000,
"actualBedTime": 1715553400000,
"bedTimeGoalMet": true,
"targetAET": 1715583600000,
"actualWakeTime": 1715582400000,
"wakeTimeGoalMet": true
},
{
"dayIndex": 11,
"targetLOT": 1715641200000,
"actualBedTime": 1715643600000,
"bedTimeGoalMet": false,
"targetAET": 1715670000000,
"actualWakeTime": 1715665600000,
"wakeTimeGoalMet": true
},
{
"dayIndex": 12,
"targetLOT": 1715727600000,
"actualBedTime": null,
"bedTimeGoalMet": null,
"targetAET": 1715756400000,
"actualWakeTime": null,
"wakeTimeGoalMet": null
},
{
"dayIndex": 13,
"targetLOT": 1715814000000,
"actualBedTime": 1715815800000,
"bedTimeGoalMet": true,
"targetAET": 1715842800000,
"actualWakeTime": 1715843500000,
"wakeTimeGoalMet": true
}
],
"bedTimeMetCount": 5,
"wakeTimeMetCount": 5,
"totalDaysWithGoal": 6
}
}
4.2 수면 효율 통계 API
- HTTP 메서드: GET
- 경로: /v1/sleep/statistics/weekly/efficiency
- 쿼리 파라미터:
- startDayIndex: 주차 시작 일차
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK): 위 응답의
se부분과 동일한 형식
4.3 수면의 질 통계 API
- HTTP 메서드: GET
- 경로: /v1/sleep/statistics/weekly/quality
- 쿼리 파라미터:
- startDayIndex: 주차 시작 일차
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK): 위 응답의
sleepQuality부분과 동일한 형식
4.4 총 수면 시간 통계 API
- HTTP 메서드: GET
- 경로: /v1/sleep/statistics/weekly/tst
- 쿼리 파라미터:
- startDayIndex: 주차 시작 일차
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK): 위 응답의
tst부분과 동일한 형식
4.5 수면제 복용 통계 API
- HTTP 메서드: GET
- 경로: /v1/sleep/statistics/weekly/medication
- 쿼리 파라미터:
- startDayIndex: 주차 시작 일차
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK): 위 응답의
sleepMedication부분과 동일한 형식
4.6 SOL 통계 API
- HTTP 메서드: GET
- 경로: /v1/sleep/statistics/weekly/sol
- 쿼리 파라미터:
- startDayIndex: 주차 시작 일차
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK): 위 응답의
sol부분과 동일한 형식
4.7 낮잠 시간 통계 API
- HTTP 메서드: GET
- 경로: /v1/sleep/statistics/weekly/nap-time
- 쿼리 파라미터:
- startDayIndex: 주차 시작 일차
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK): 위 응답의
napTime부분과 동일한 형식
4.8 수면 영향 요인 통계 API
- HTTP 메서드: GET
- 경로: /v1/sleep/statistics/weekly/factors
- 쿼리 파라미터:
- startDayIndex: 주차 시작 일차
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK): 위 응답의
sleepFactors부분과 동일한 형식
4.9 목표 달성 통계 API
- HTTP 메서드: GET
- 경로: /v1/sleep/statistics/weekly/goal-adherence
- 쿼리 파라미터:
- startDayIndex: 주차 시작 일차
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK): 위 응답의
goalAdherence부분과 동일한 형식
4.10 사용자 지정 범위 통계 API
- HTTP 메서드: GET
- 경로: /v1/sleep/statistics/custom-range
- 쿼리 파라미터:
- startDayIndex: 시작 일차 (필수)
- endDayIndex: 종료 일차 (옵션)
- aggregationType: 집계 유형 (옵션, 기본값: "DAILY", 가능한 값: "DAILY", "WEEKLY", "MONTHLY", "QUARTERLY")
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
참고: 이 API는 백엔드 시스템의 유연한 데이터 조회 요구사항을 지원하기 위한 것으로, 특정 일차 범위를 지정하여 데이터를 조회하거나 특정 집계 단위로 데이터를 제공합니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"userCycleId": "uc_456",
"startDayIndex": 1,
"endDayIndex": 30,
"aggregationType": "WEEKLY",
"data": [
{
"startDayIndex": 1,
"endDayIndex": 7,
"averageTstMinutes": 445.8,
"averageSe": 0.91,
"medicationDays": 2,
"goalAdherence": {
"bedTimeMetCount": 5,
"wakeTimeMetCount": 6,
"totalDaysWithGoal": 7
}
},
{
"startDayIndex": 8,
"endDayIndex": 14,
"averageTstMinutes": 450.8,
"averageSe": 0.9,
"medicationDays": 3,
"goalAdherence": {
"bedTimeMetCount": 5,
"wakeTimeMetCount": 5,
"totalDaysWithGoal": 6
}
},
{
"startDayIndex": 15,
"endDayIndex": 21,
"averageTstMinutes": 460.0,
"averageSe": 0.92,
"medicationDays": 1,
"goalAdherence": {
"bedTimeMetCount": 6,
"wakeTimeMetCount": 6,
"totalDaysWithGoal": 7
}
},
{
"startDayIndex": 22,
"endDayIndex": 28,
"averageTstMinutes": 455.5,
"averageSe": 0.93,
"medicationDays": 2,
"goalAdherence": {
"bedTimeMetCount": 5,
"wakeTimeMetCount": 6,
"totalDaysWithGoal": 7
}
},
{
"startDayIndex": 29,
"endDayIndex": 30,
"averageTstMinutes": 470.0,
"averageSe": 0.94,
"medicationDays": 0,
"goalAdherence": {
"bedTimeMetCount": 2,
"wakeTimeMetCount": 2,
"totalDaysWithGoal": 2
}
}
],
"summary": {
"averageTstMinutes": 452.9,
"minTstMinutes": 420,
"maxTstMinutes": 485,
"averageSe": 0.92,
"totalMedicationDays": 8,
"medicationPercentage": 26.7,
"averageBedTimeAdherence": 0.77,
"averageWakeTimeAdherence": 0.83
}
}
4.11 관리자용 사용자 데이터 접근 API
- HTTP 메서드: GET
- 경로: /v1/sleep/admin/data/
{userId} - 쿼리 파라미터:
- startDate: 시작 날짜 (YYYY-MM-DD, 옵션)
- endDate: 종료 날짜 (YYYY-MM-DD, 옵션)
- startDayIndex: 시작 일차 (옵션)
- endDayIndex: 종료 일차 (옵션)
- includeStatistics: 통계 포함 여부 (기본값: false)
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
중요: 이 API는 관리자 및 서비스 계정만 접근 가능합니다. 시스템은 관리자의 데이터 접근에 대한 감사 로그를 기록합니다.
응답 (Response)
- 성공 응답 (200 OK): 수면 기록, 목표, rTIB 처방 및 통계 정보를 포함하는 종합 데이터
데이터 관리 및 개인정보 보호 API
📌 구현 순서: 핵심 기능 구현 후 GDPR 준수를 위해 구현합니다.
이 API들은 GDPR 준수 및 데이터 보관 정책 요구사항을 지원하기 위해 관리자 또는 사용자가 데이터 생명주기를 관리하는 기능을 제공합니다.
5.1 사용자 데이터 아카이빙 API (관리자용)
- HTTP 메서드: POST
- 경로: /v1/sleep/admin/users/
{userId}/archive - Headers:
- Authorization: Bearer
{adminAccessToken}
- Authorization: Bearer
참고: 비활성 상태로 1년 이상 경과한 사용자의 데이터를 콜드 스토리지로 이전합니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"status": "ARCHIVED",
"archivedAt": 1735689600000
}
- 오류 응답 (404 Not Found)
{
"code": 10044,
"message": "USER_NOT_FOUND",
"detail": "사용자를 찾을 수 없습니다."
}
- 오류 응답 (400 Bad Request)
{
"code": 10101,
"message": "ARCHIVING_NOT_ALLOWED",
"detail": "활성 상태이거나 아카이빙 조건(비활성 1년 경과)을 만족하지 않아 아카이빙할 수 없습니다."
}
- 오류 응답 (500 Server Error)
{
"code": 10100,
"message": "ARCHIVING_FAILED",
"detail": "데이터 아카이빙 중 오류가 발생했습니다."
}
5.2 사용자 데이터 복원 API (관리자용)
- HTTP 메서드: POST
- 경로: /v1/sleep/admin/users/
{userId}/restore - Headers:
- Authorization: Bearer
{adminAccessToken}
- Authorization: Bearer
참고: 콜드 스토리지에 아카이빙된 사용자 데이터를 주 데이터베이스로 복원합니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"status": "ACTIVE",
"restoredAt": 1735776000000
}
- 오류 응답 (404 Not Found)
{
"code": 10102,
"message": "ARCHIVED_DATA_NOT_FOUND",
"detail": "아카이빙된 사용자 데이터를 찾을 수 없습니다."
}
- 오류 응답 (500 Server Error)
{
"code": 10103,
"message": "RESTORATION_FAILED",
"detail": "데이터 복원 중 오류가 발생했습니다."
}
5.3 사용자 데이터 영구 삭제 API (관리자용)
- HTTP 메서드: DELETE
- 경로: /v1/sleep/admin/users/
{userId}/data - Headers:
- Authorization: Bearer
{adminAccessToken}
- Authorization: Bearer
주의: 이 작업은 되돌릴 수 없습니다. 주 데이터베이스 및 콜드 스토리지에서 사용자 데이터를 영구 삭제합니다.
응답 (Response)
-
성공 응답 (204 No Content)
-
오류 응답 (500 Server Error)
{
"code": 10104,
"message": "DELETION_FAILED",
"detail": "데이터 삭제 중 오류가 발생했습니다."
}
5.4 사용자 데이터 익명화 API (관리자용)
- HTTP 메서드: POST
- 경로: /v1/sleep/admin/users/
{userId}/anonymize - Headers:
- Authorization: Bearer
{adminAccessToken}
- Authorization: Bearer
참고: 사용자의 개인 식별 정보를 제거하고 통계 분석 등을 위해 데이터를 보존합니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"status": "ANONYMIZED",
"anonymizedAt": 1735862400000
}
- 오류 응답 (500 Server Error)
{
"code": 10105,
"message": "ANONYMIZATION_FAILED",
"detail": "데이터 익명화 중 오류가 발생했습니다."
}
5.5 내 데이터 추출 요청 API (사용자용)
- HTTP 메서드: GET
- 경로: /v1/sleep/users/me/data-export
- 쿼리 파라미터:
- format: 추출 형식 (기본값: "JSON", 가능한 값: "JSON", "CSV")
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"message": "Data export started. You will be notified when it is ready.",
"exportId": "export_abc123"
}
- 오류 응답 (400 Bad Request)
{
"code": 10107,
"message": "INVALID_EXPORT_FORMAT",
"detail": "지원되지 않는 추출 형식입니다. (JSON 또는 CSV 사용)"
}
- 오류 응답 (500 Server Error)
{
"code": 10106,
"message": "EXPORT_FAILED",
"detail": "데이터 추출 시작 중 오류가 발생했습니다."
}
5.6 특정 사용자 데이터 추출 요청 API (관리자용)
- HTTP 메서드: GET
- 경로: /v1/sleep/admin/users/
{userId}/data-export - 쿼리 파라미터:
- format: 추출 형식 (기본값: "JSON", 가능한 값: "JSON", "CSV")
- Headers:
- Authorization: Bearer
{adminAccessToken}
- Authorization: Bearer
응답 (Response)
- 성공 응답 (200 OK)
{
"message": "Data export started for user user_123.",
"exportId": "export_def456"
}
오류 코드
Sleep 도메인 API에서 사용하는 오류 코드는 다음과 같습니다:
| HTTP 상태 코드 | 오류 코드 | 메시지 | 설명 | 대응 방법 |
|---|---|---|---|---|
| 500 | 10000 | SERVER_ERROR | 서버 내부 오류 | 서버 로그 확인 및 시스템 관리자에게 문의 |
| 400 | 10001 | MISSING_REQUIRED_FIELDS | 필수 입력 항목이 누락되었습니다 | 누락된 필드를 확인하고 모든 필수 항목을 포함하여 다시 요청 |
| 400 | 10002 | INVALID_PARAMETERS | 잘못된 파라미터입니다 | 파라미터 값과 형식을 확인하여 올바른 값으로 다시 요청 |
| 400 | 10003 | INVALID_FORMAT | 입력 형식이 유효하지 않습니다 | 올바른 형식으로 데이터 제공(시간, 날짜 등) |
| 400 | 10004 | INVALID_TIMEZONE | 유효하지 않은 시간대 ID | 올바른 시간대 ID 사용(예: "Asia/Seoul") |
| 400 | 10005 | INVALID_SLEEP_QUALITY | 유효하지 않은 수면의 질 값 | 1-5 사이의 정수 값 사용 |
| 400 | 10006 | INVALID_TIME_RANGE | 유효하지 않은 시간 범위 | 시작 시간이 종료 시간보다 이전인지 확인 |
| 400 | 10007 | INVALID_FACTOR_ID | 유효하지 않은 영향 요인 ID | 존재하는 영향 요인 ID 사용 |
| 400 | 10008 | TOO_MANY_CUSTOM_FACTORS | 사용자 정의 요인이 너무 많습니다 | 최대 10개까지만 입력 |
| 400 | 10009 | SLEEP_TIME_VALIDATION_FAILED | 수면 시간 검증에 실패했습니다 | 잠자리에 든 시각(LOT)은 18:00 이후여야 하고, 일어난 시각(AET)은 LOT보다 이후여야 함 |
| 400 | 10010 | DATE_VALIDATION_FAILED | 날짜 검증에 실패했습니다 | 수면 기록은 당일 일차에만 생성/수정 가능합니다. |
| 403 | 10011 | TREATMENT_SUSPENDED | 치료 활동 일시 정지 상태입니다 | 치료 활동 재개 후 다시 시도 |
| 400 | 10012 | INVALID_DAY_INDEX | 유효하지 않은 일차 값 | 존재하는 치료 주기 일차 값 사용 |
| 400 | 10013 | INVALID_RTIB | 유효하지 않은 rTIB 값 | 유효한 rTIB 처방 ID 사용 |
| 400 | 10014 | INVALID_TST | 계산된 총 수면 시간(TST)과 제공된 값이 일치하지 않습니다 | 올바른 TST 값 입력 또는 필드 제거 |
| 400 | 10015 | UNEXPECTED_SLEEP_DATA | DNS=true인 경우 수면 관련 데이터를 입력할 수 없습니다 | DNS=true일 때는 lot, aet, solMinutes, wasoMinutes, tstMinutes 필드 제거 |
| 400 | 10016 | TARGET_WAKE_TIME_CHANGE_NOT_ALLOWED | 목표 기상 시각 변경이 허용되지 않습니다 | rTIB 처방일 당일 일차에만 변경 가능 |
| 400 | 10020 | CUSTOM_FACTOR_TOO_LONG | 사용자 정의 요인이 너무 깁니다 | 각 항목은 최대 100자까지 입력 가능 |
| 403 | 10030 | INSUFFICIENT_PERMISSIONS | 권한이 충분하지 않습니다 | 필요한 권한을 확인하고 적절한 계정 사용 |
| 404 | 10040 | SLEEP_LOG_NOT_FOUND | 수면 기록을 찾을 수 없습니다 | 날짜 또는 ID 확인 |
| 404 | 10041 | SLEEP_GOAL_NOT_FOUND | 수면 목표를 찾을 수 없습니다 | 날짜 또는 ID 확인 |
| 404 | 10042 | RTIB_RECOMMENDATION_NOT_FOUND | rTIB 처방을 찾을 수 없습니다 | 날짜 또는 ID 확인 |
| 404 | 10043 | SLEEP_GOAL_ADHERENCE_NOT_FOUND | 수면 목표 달성 기록을 찾을 수 없습니다 | 날짜 또는 ID 확인 |
| 404 | 10044 | USER_NOT_FOUND | 사용자를 찾을 수 없습니다 | 사용자 ID 확인 |
| 404 | 10045 | TEMPORARY_SLEEP_LOG_NOT_FOUND | 임시 수면 기록을 찾을 수 없습니다 | 날짜 확인 또는 임시 기록 먼저 생성 |
| 500 | 10050 | STATISTICS_CALCULATION_FAILED | 통계 계산에 실패했습니다 | 서버 로그 확인 및 시스템 관리자에게 문의 |
| 400 | 10051 | INSUFFICIENT_DATA_FOR_STATISTICS | 통계를 계산하기 위한 데이터가 충분하지 않습니다 | 더 많은 수면 기록 입력 후 다시 시도 |
| 409 | 10090 | SLEEP_LOG_ALREADY_EXISTS | 해당 날짜에 이미 수면 기록이 존재합니다 | 기존 기록 수정 또는 다른 날짜 사용 |
| 409 | 10091 | SLEEP_GOAL_ALREADY_EXISTS | 해당 날짜에 이미 수면 목표가 존재합니다 | 기존 목표 수정 또는 다른 날짜 사용 |
| 429 | 10092 | RATE_LIMIT_EXCEEDED | 요청 횟수가 제한을 초과했습니다 | 잠시 후 다시 시도 |
| 500 | 10100 | ARCHIVING_FAILED | 데이터 아카이빙 중 오류가 발생했습니다. | 서버 로그 확인 및 시스템 관리자에게 문의 |
| 400 | 10101 | ARCHIVING_NOT_ALLOWED | 아카이빙 조건(비활성 1년 경과)을 만족하지 않아 아카이빙할 수 없습니다. | 사용자 상태 및 마지막 활동 시간 확인 |
| 404 | 10102 | ARCHIVED_DATA_NOT_FOUND | 아카이빙된 사용자 데이터를 찾을 수 없습니다. | 사용자 ID 및 아카이브 상태 확인 |
| 500 | 10103 | RESTORATION_FAILED | 데이터 복원 중 오류가 발생했습니다. | 서버 로그 확인 및 시스템 관리자에게 문의 |
| 500 | 10104 | DELETION_FAILED | 데이터 삭제 중 오류가 발생했습니다. | 서버 로그 확인 및 시스템 관리자에게 문의 |
| 500 | 10105 | ANONYMIZATION_FAILED | 데이터 익명화 중 오류가 발생했습니다. | 서버 로그 확인 및 시스템 관리자에게 문의 |
| 500 | 10106 | EXPORT_FAILED | 데이터 추출 중 오류가 발생했습니다. | 서버 로그 확인 및 시스템 관리자에게 문의 |
| 400 | 10107 | INVALID_EXPORT_FORMAT | 지원되지 않는 추출 형식입니다. | 요청 파라미터 확인 (JSON 또는 CSV 사용) |
| 500 | 10099 | UNKNOWN_SLEEP_ERROR | 알 수 없는 수면 도메인 오류가 발생했습니다 | 서버 로그 확인 및 시스템 관리자에게 문의 |
변경 이력
| 버전 | 날짜 | 작성자 | 변경 내용 |
|---|---|---|---|
| 0.1.0 | 2025-05-05 | bok@weltcorp.com | 최초 작성 |
| 0.2.0 | 2025-05-10 | bok@weltcorp.com | 시간 검증, 날짜 검증 관련 API 설명 추가 |
| 0.3.0 | 2025-05-15 | bok@weltcorp.com | 임시 수면 기록 관련 API 추가 |
| 0.4.0 | 2025-05-20 | bok@weltcorp.com | 주차별 통계 API, 사용자 지정 범위 통계 API 추가 |
| 0.5.0 | 2025-05-25 | bok@weltcorp.com | 관리자용 데이터 접근 API 추가 |
| 0.6.0 | 2025-05-30 | bok@weltcorp.com | lot, aet를 Unix timestamp(밀리초) 형식으로 변경 |
| 0.7.0 | 2025-05-31 | bok@weltcorp.com | 오류 코드를 6000번대 체계로 변경 |
| 0.8.0 | 2025-06-01 | bok@weltcorp.com | 수면 기록 생성/수정 API에 일차(day-index) 기반 엔드포인트 추가 |
| 0.9.0 | 2025-06-02 | bok@weltcorp.com | 날짜(date) 기반 API 제거, 일차(day-index) 기반 API로 통일 |
| 0.10.0 | 2025-06-03 | bok@weltcorp.com | 수면 기록 수정 API의 HTTP 메서드를 PUT에서 PATCH로 변경 (부분 업데이트 명확화) |
| 0.11.0 | 2025-06-04 | bok@weltcorp.com | 요청 body에 날짜(date) 필드 추가 및 설명 보완 |
| 0.12.0 | 2025-06-05 | bok@weltcorp.com | 목표 기상 시각 설정 API 설명 개선 - 다음 일차 목표 설정 흐름 명확화 |
| 0.13.0 | 2025-06-06 | bok@weltcorp.com | rTIB 처방 시점 및 적용 흐름 명확화 - 7일차 처방, 8일차 적용 명시 |
| 0.14.0 | 2025-06-07 | bok@weltcorp.com | 요청 body에서 날짜(date) 필드 제거, 일차(dayIndex)만 사용하도록 변경 |
| 0.15.0 | 2025-05-13 | bok@weltcorp.com | GDPR 준수 및 데이터 관리 API 추가 (아카이빙, 복원, 삭제, 익명화, 추출) 및 관련 오류 코드 추가 |
| 0.16.0 | 2025-05-23 | dalia@weltcorp.com | 수면 기록 생성 API 관련 누락된 오류 코드 추가 및 Request, Response 수정 |
| 0.17.0 | 2025-05-27 | dalia@weltcorp.com | 에러 코드 변경 및 수면기록 생성 API Request 수정 |
| 0.18.0 | 2025-07-28 | bok@weltcorp.com | 최근 수면 목표 조회 API 추가 (사용자용 및 관리자용), 사용자용은 /users/me 패턴 적용, 모든 수면 목표 API 응답 형식 통일 |