User API 엔드포인트
목차
관련 문서
- Auth 도메인 엔드포인트: /domains/common/core-domains/auth/endpoints
접근 권한 매트릭스
| 엔드포인트 | 시스템 관리자 | 사용자 (자신) | 서비스 계정 (제한적) | 비고 |
|---|---|---|---|---|
| GET /v1/users | ✓ | ✘ | ✓ (제한적) | |
| POST /v1/users | ✓ | ✘ | ✘ | Auth 연동, 직접 호출 시 강력 권한 |
| GET /v1/users/lookup-by-email | ✓ | ✘ | ✘ | 이메일로 userId 조회 |
GET /v1/users/{userId} GET /v1/users/me | ✓ | 자신만 | ✓ (제한적) | accountType, guestExpiresAt, upgradedAt 포함 |
PATCH /v1/users/{userId} PATCH /v1/users/me | ✓ | 자신만 | ✓ (제한적) | 이름, profileData 수정 (계정 타입 직접 수정 불가) |
DELETE /v1/users/{userId} DELETE /v1/users/me | ✓ | 자신만 | ✘ | 비활성화 요청 (Soft delete) |
DELETE /v1/users/{userId}/data | ✓ | ✘ | ✘ | 개발 환경 전용, 데이터 완전 삭제 |
| POST /v1/users/service-accounts | ✓ | ✘ | ✘ | |
GET /v1/users/{userId}/profile GET /v1/users/me/profile | ✓ | 자신만 | ✓ (제한적) | |
PATCH /v1/users/{userId}/profile PATCH /v1/users/me/profile | ✓ | 자신만 | ✓ (제한적) | 언어, 타임존 수정 |
GET /v1/users/{userId}/status-history GET /v1/users/me/status-history | ✓ | 자신만 | ✘ | |
POST /v1/users/{userId}/status/activate | ✓ | ✘ | ✘ | 내부 시스템/관리자 |
POST /v1/users/{userId}/status/deactivate | ✓ | ✘ | ✘ | 내부 시스템/관리자 |
POST /v1/users/{userId}/status/reactivate | ✓ | ✘ | ✘ | 관리자 |
POST /v1/users/{userId}/status/lock | ✓ | ✘ | ✘ | 관리자, Auth 연계 |
POST /v1/users/{userId}/status/unlock | ✓ | ✘ | ✘ | 관리자, Auth 연계 |
POST /v1/users/{userId}/status/suspend | ✓ | ✘ | ✘ | 관리자 |
POST /v1/users/{userId}/status/unsuspend | ✓ | ✘ | ✘ | 관리자 |
POST /v1/users/{userId}/status/ban | ✓ | ✘ | ✘ | 관리자 |
POST /v1/users/{userId}/account/guest-expiry/cancel | ✓ | ✘ | ✘ | Step-up 이후 게스트 만료 타이머 해제 |
POST /v1/users/{userId}/account/cleanup-guest | ✓ | ✘ | ✘ | 만료된 게스트 계정 정리 (관리자/스케줄러용) |
| GET /v1/users/state/current | ✓ | 자신만 | ✘ | 사용자 현재 상태 조회 |
GET /v1/users/{userId}/day-mapping GET /v1/users/me/day-mapping | ✓ | 자신만 | ✘ | 현재 활성 주기의 일차-날짜 매핑 |
POST /v1/users/{userId}/service-period/suspend POST /v1/users/me/service-period/suspend | ✓ | 자신만 | ✘ | |
POST /v1/users/{userId}/service-period/resume POST /v1/users/me/service-period/resume | ✓ | 자신만 | ✘ | |
GET /v1/users/{userId}/service-period/status GET /v1/users/me/service-period/status | ✓ | 자신만 | ✘ | |
POST /v1/users/{userId}/tester/mark | ✓ | ✘ | ✘ | 관리자 |
POST /v1/users/{userId}/tester/unmark | ✓ | ✘ | ✘ | 관리자 |
GET /v1/users/{userId}/data-access GET /v1/users/me/data-access | ✓ | 자신만 | ✘ | GDPR |
POST /v1/users/{userId}/data-deletion POST /v1/users/me/data-deletion | ✓ | 자신만 | ✘ | GDPR |
참고:
- ✓: 접근 가능
- ✘: 접근 불가
- (내부): 내부 시스템 간 호출 가능성
- (제한적): 특정 필드만 조회/수정 가능 (예: 서비스 계정은 자신의 이름 등)
- (자신만): 자신의 데이터에만 접근 가능
사용자 계정 관리 API
📌 기술 구현 문서: 사용자 계정 관리 API 구현
사용자 생성
- HTTP 메서드: POST
- 경로: /v1/users
- Headers:
- Content-Type: application/json
- Authorization: Bearer
{appToken 또는 internalToken}
- 비고: 주로 Auth 도메인의 회원가입(/auth/register) 프로세스 내부에서 호출될 수 있음. 직접 노출 시 강력한 권한 필요.
요청 (Request) - Auth 도메인에서 전달하는 예시
{
"email": "user@example.com",
"name": "Initial Name", // Auth에서 기본값 또는 사용자 입력값 전달
"userType": "USER",
"initialStatus": "PENDING" // Auth에서 이메일 인증 필요시 PENDING으로 요청
// Auth에서 관리하는 password 필드는 여기서 처리하지 않음
}
응답 (Response)
- 성공 응답 (201 Created)
{
"id": "user_123",
"email": "user@example.com",
"name": "Initial Name",
"status": "PENDING",
"userType": "USER",
"createdAt": 1711011600000,
"updatedAt": 1711011600000
}
- 오류 응답 (400 Bad Request)
{
"code": 4001,
"message": "INVALID_INPUT_DATA",
"detail": "요청 데이터가 유효하지 않습니다. (예: 필수 필드 누락)"
}
- 오류 응답 (409 Conflict)
{
"code": 4002,
"message": "USER_EMAIL_ALREADY_EXISTS",
"detail": "이미 사용 중인 이메일입니다."
}
서비스 계정 생성
- HTTP 메서드: POST
- 경로: /v1/users/service-accounts
- Headers:
- Content-Type: application/json
- Authorization: Bearer
{adminToken}
요청 (Request)
{
"name": "Backend Service A",
"description": "Service account for internal backend communication"
}
응답 (Response)
- 성공 응답 (201 Created)
{
"id": "sa_abc",
"email": "sa_abc@service.welt", // 시스템에서 자동 생성된 이메일 형식
"name": "Backend Service A",
"status": "ACTIVE", // 서비스 계정은 생성 시 바로 ACTIVE
"userType": "SERVICE_ACCOUNT",
"createdAt": 1711011800000,
"updatedAt": 1711011800000
// API Key 정보는 별도 관리 또는 응답 포함 (설계 필요)
}
- 오류 응답 (403 Forbidden)
{
"code": 2060, // Auth 에러 코드 재사용
"message": "PERMISSION_DENIED",
"detail": "서비스 계정을 생성할 권한이 없습니다."
}
사용자 조회
- HTTP 메서드: GET
- 경로: /v1/users/
{userId}또는 /v1/users/me - Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
- 비고:
/v1/users/me는 현재 로그인한 사용자 자신의 정보를 조회할 때 사용합니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "user_123",
"email": "user@example.com",
"name": "홍길동",
"status": "ACTIVE",
"userType": "USER",
"accountType": "REGISTERED",
"guestAccountId": null,
"guestExpiresAt": null,
"upgradedAt": 1714600000000,
"profileData": { "customField": "value" },
"createdAt": 1711929600000,
"updatedAt": 1714600050000,
"deletedAt": null
}
- 오류 응답 (404 Not Found)
{
"code": 4003,
"message": "USER_NOT_FOUND",
"detail": "사용자를 찾을 수 없습니다."
}
- 오류 응답 (403 Forbidden) - 다른 사용자 조회 시도 시
{
"code": 2060, // Auth 에러 코드 재사용
"message": "PERMISSION_DENIED",
"detail": "다른 사용자의 정보를 조회할 권한이 없습니다."
}
이메일로 사용자 조회
- HTTP 메서드: GET
- 경로: /v1/users/lookup-by-email
- Query Parameters:
- email: 조회할 사용자의 이메일 주소 (필수)
- Headers:
- Authorization: Bearer
{adminToken}
- Authorization: Bearer
- 비고: 관리자만 접근 가능. 이메일을 통해 사용자 ID 및 기본 정보를 조회합니다.
요청 (Request) 예시
GET /v1/users/lookup-by-email?email=user@example.com
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123"
}
- 오류 응답 (400 Bad Request) - 이메일 파라미터 누락 또는 형식 오류
{
"code": 7010,
"message": "INVALID_EMAIL_PARAMETER",
"detail": "이메일 주소가 필요하거나 형식이 올바르지 않습니다."
}
- 오류 응답 (403 Forbidden) - 권한 없음
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "이메일로 사용자를 조회할 권한이 없습니다."
}
- 오류 응답 (404 Not Found) - 사용자 없음
{
"code": 7002,
"message": "USER_NOT_FOUND",
"detail": "해당 이메일의 사용자를 찾을 수 없습니다."
}
사용자 정보 수정
- HTTP 메서드: PATCH
- 경로: /v1/users/
{userId}또는 /v1/users/me - Headers:
- Content-Type: application/json
- Authorization: Bearer
{accessToken}
- 비고: 사용자는 자신의 이름(
name)과 확장 필드(profileData)만 수정 가능. 이메일, 비밀번호, 상태 등은 다른 API 또는 프로세스를 통해 변경됨. 관리자는 추가 필드 수정 가능./v1/users/me는 현재 로그인한 사용자 자신의 정보를 수정할 때 사용합니다.
요청 (Request) - 사용자가 이름 수정 시
{
"name": "김길동"
}
요청 (Request) - 관리자가 profileData 수정 시
{
"profileData": {
"customField": "newValue",
"anotherField": 123
}
}
응답 (Response)
- 성공 응답 (200 OK)
{
"id": "user_123",
"email": "user@example.com",
"name": "김길동", // 수정된 이름
"status": "ACTIVE",
"userType": "USER",
"profileData": { "customField": "newValue", "anotherField": 123 }, // 수정된 profileData
"createdAt": 1711929600000,
"updatedAt": 1714525000000, // 업데이트 시간 변경
"deletedAt": null
}
- 오류 응답 (400 Bad Request)
{
"code": 4001,
"message": "INVALID_INPUT_DATA",
"detail": "수정할 수 없는 필드를 포함하고 있거나 데이터 형식이 잘못되었습니다."
}
- 오류 응답 (403 Forbidden) - 권한 없는 필드 수정 시도 시
{
"code": 2060, // Auth 에러 코드 재사용
"message": "PERMISSION_DENIED",
"detail": "요청한 정보를 수정할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 4003,
"message": "USER_NOT_FOUND",
"detail": "사용자를 찾을 수 없습니다."
}
사용자 비활성화 요청
- HTTP 메서드: DELETE
- 경로: /v1/users/
{userId}또는 /v1/users/me - Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
- 비고: 실제 데이터 삭제가 아닌,
status를INACTIVE로 변경하고deletedAt타임스탬프를 설정하는 Soft Delete 방식. 사용자는 자신의 계정만 비활성화 가능./v1/users/me는 현재 로그인한 사용자가 자신의 계정을 비활성화할 때 사용합니다. - 게스트 계정 지원: 게스트 계정(
guests.*IAM Group 소속)도 동일한 API를 통해 자발적 탈퇴가 가능합니다. 게스트 탈퇴 시 기존 만료 타이머(TimeMachine 스케줄)는 자동으로 해제됩니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"message": "사용자 계정이 성공적으로 비활성화 요청되었습니다.",
"userId": "user_123",
"status": "INACTIVE", // 변경된 상태
"deletedAt": 1714526000000 // 설정된 시간
}
- 오류 응답 (403 Forbidden) - 다른 사용자 비활성화 시도 시
{
"code": 2060, // Auth 에러 코드 재사용
"message": "PERMISSION_DENIED",
"detail": "다른 사용자를 비활성화할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 4003,
"message": "USER_NOT_FOUND",
"detail": "사용자를 찾을 수 없습니다."
}
- 오류 응답 (409 Conflict) - 이미 비활성 상태일 경우
{
"code": 4011,
"message": "INVALID_STATUS_TRANSITION",
"detail": "이미 비활성화된 사용자입니다."
}
개발용 사용자 데이터 삭제
- HTTP 메서드: DELETE
- 경로: /v1/users/
{userId}/data - Headers:
- Authorization: Bearer
{adminToken}
- Authorization: Bearer
- 비고: 개발 및 테스트 환경에서만 사용 가능한 API. 프로덕션 환경에서는 접근 불가. 사용자 데이터를 데이터베이스에서 완전히 삭제함. 관련된 모든 도메인 연관 데이터도 함께 삭제됨.
응답 (Response)
- 성공 응답 (200 OK)
{
"message": "사용자 데이터가 성공적으로 삭제되었습니다.",
"userId": "user_123",
"deletedAt": 1714538000000
}
- 오류 응답 (403 Forbidden) - 권한 없음 또는 프로덕션 환경
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "개발 환경에서만 사용 가능한 API이거나, 해당 작업에 대한 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 7002,
"message": "USER_NOT_FOUND",
"detail": "사용자를 찾을 수 없습니다."
}
- 오류 응답 (500 Internal Server Error)
{
"code": 5000,
"message": "INTERNAL_SERVER_ERROR",
"detail": "삭제 처리 중 서버 오류가 발생했습니다."
}
게스트 계정 API
📌 관련 문서: Auth 게스트 Step-up 설계, User 도메인 요구사항
게스트 만료 스케줄 취소
- HTTP 메서드: POST
- 경로: /v1/users/
{userId}/account/guest-expiry/cancel - 권한: 시스템 관리자 또는 자동화 서비스 (Auth Step-up 흐름)
- 설명: 게스트 계정이 Step-up 인증에 성공했을 때 호출하여
guestExpiresAt타이머를 해제하고 만료 스케줄을 취소합니다.
요청 예시
{
"reason": "STEP_UP_COMPLETED",
"triggeredBy": "auth.identity-level.changed",
"identityLevel": "registered"
}
응답 예시 (200 OK)
{
"userId": "user_123",
"accountType": "REGISTERED",
"guestExpiresAt": null,
"upgradedAt": 1714600000000,
"processedBy": "system"
}
게스트 계정 정리
- HTTP 메서드: POST
- 경로: /v1/users/
{userId}/account/cleanup-guest - 권한: 시스템 관리자 또는 백그라운드 스케줄러
- 설명: 만료된 게스트 계정에 대해 토큰 폐기, 그룹/플랜 제거, 삭제 또는 익명화 프로세스를 실행합니다.
요청 예시
{
"reason": "EXPIRED_NOT_UPGRADED",
"strategy": "ANONYMIZE"
}
응답 예시 (202 Accepted)
{
"userId": "user_456",
"guestAccountId": "guest-4f52c7fa",
"groupIds": ["guests.kr"],
"guestExpiresAt": 1714300000000,
"cleanupStrategy": "ANONYMIZE",
"status": "SCHEDULED"
}
참고: v1.2.0부터 게스트 식별은
groupIds에guests.*패턴이 포함되어 있는지로 판단합니다.
⚠️ 주의사항
- 게스트 정리 API는
guestExpiresAt이 현재 시간보다 이전인 경우에만 실행해야 합니다.- 정리 완료 후
GuestAccountLifecycle에CLEANED이벤트를 기록하고 Audit 로그를 남겨야 합니다.
{
"code": 7004,
"message": "USER_DATA_HARD_DELETION_FAILED",
"detail": "사용자 데이터 삭제 중 오류가 발생했습니다."
}
개발용 이메일 기반 사용자 데이터 삭제
- HTTP 메서드: DELETE
- 경로: /v1/users/data
- Headers:
- Authorization: Bearer
{adminToken}
- Authorization: Bearer
- Query Parameters:
- email: 삭제할 사용자의 이메일 주소 (필수)
- 비고: 개발 및 테스트 환경에서만 사용 가능한 API. 프로덕션 환경에서는 접근 불가. 사용자 ID를 모르는 경우, 이메일을 통해 사용자를 찾고 데이터를 완전히 삭제함.
요청 (Request) 예시
DELETE /v1/users/data?email=user@example.com
응답 (Response)
- 성공 응답 (200 OK)
{
"message": "사용자 데이터가 성공적으로 삭제되었습니다.",
"email": "user@example.com",
"userId": "user_123", // 삭제된 사용자 ID
"deletedAt": 1714538000000
}
- 오류 응답 (403 Forbidden) - 권한 없음 또는 프로덕션 환경
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "개발 환경에서만 사용 가능한 API이거나, 해당 작업에 대한 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 4007,
"message": "USER_EMAIL_NOT_FOUND",
"detail": "해당 이메일의 사용자를 찾을 수 없습니다."
}
- 오류 응답 (500 Internal Server Error)
{
"code": 4080,
"message": "USER_DATA_DELETION_FAILED",
"detail": "사용자 데이터 삭제 중 오류가 발생했습니다."
}
사용자 프로필 관리 API
프로필 조회
- HTTP 메서드: GET
- 경로: /v1/users/
{userId}/profile 또는 /v1/users/me/profile - Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
- 비고:
/v1/users/me/profile은 현재 로그인한 사용자 자신의 프로필을 조회할 때 사용합니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"userName": "홍길동",
"language": "ko-KR",
"timezoneId": "Asia/Seoul",
"offsetInMinutes": 540,
"createdAt": 1711929600000,
"updatedAt": 1714523700000
}
- 오류 응답 (404 Not Found) - 사용자 또는 프로필 없음
{
"code": 4004, // USER_PROFILE_NOT_FOUND
"message": "USER_PROFILE_NOT_FOUND",
"detail": "사용자 프로필을 찾을 수 없습니다."
}
- 오류 응답 (403 Forbidden) - 다른 사용자 프로필 조회 시도 시
{
"code": 2060, // Auth 에러 코드 재사용
"message": "PERMISSION_DENIED",
"detail": "다른 사용자의 프로필을 조회할 권한이 없습니다."
}
프로필 수정
- HTTP 메서드: PATCH
- 경로: /v1/users/
{userId}/profile 또는 /v1/users/me/profile - Headers:
- Content-Type: application/json
- Authorization: Bearer
{accessToken}
- 비고:
/v1/users/me/profile은 현재 로그인한 사용자 자신의 프로필을 수정할 때 사용합니다.
요청 (Request) - 사용자 이름만 수정하는 경우
{
"userName": "김길동"
}
요청 (Request) - 언어만 수정하는 경우
{
"language": "en-US"
}
요청 (Request) - 타임존만 수정하는 경우
{
"timezoneId": "Europe/Berlin"
}
요청 (Request) - 모든 필드 수정하는 경우
{
"userName": "김길동",
"language": "en-US",
"timezoneId": "Europe/Berlin"
}
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"userName": "김길동",
"language": "en-US",
"timezoneId": "Europe/Berlin",
"offsetInMinutes": 60,
"createdAt": 1711929600000,
"updatedAt": 1714527000000
}
- 오류 응답 (400 Bad Request)
{
"code": 4001,
"message": "INVALID_INPUT_DATA",
"detail": "지원하지 않는 언어 코드 또는 타임존 ID 형식입니다."
}
- 오류 응답 (403 Forbidden) - 다른 사용자 프로필 수정 시도 시
{
"code": 2060, // Auth 에러 코드 재사용
"message": "PERMISSION_DENIED",
"detail": "다른 사용자의 프로필을 수정할 권한이 없습니다."
}
- 오류 응답 (404 Not Found) - 사용자 또는 프로필 없음
{
"code": 4004,
"message": "USER_PROFILE_NOT_FOUND", // 또는 USER_NOT_FOUND
"detail": "사용자 또는 프로필을 찾을 수 없습니다."
}
사용자 상태 관리 API
상태 변경 이력 조회
- HTTP 메서드: GET
- 경로: /v1/users/
{userId}/status-history 또는 /v1/users/me/status-history - Query Parameters:
page: 페이지 번호 (기본값: 1)pageSize: 페이지 크기 (기본값: 10)sortBy: 정렬 기준 (기본값: changedAt)sortOrder: 정렬 순서 (기본값: DESC)
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
- 비고:
/v1/users/me/status-history는 현재 로그인한 사용자 자신의 상태 변경 이력을 조회할 때 사용합니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"items": [
{
"id": "hist_abc",
"userId": "user_123",
"oldStatus": "PENDING",
"newStatus": "ACTIVE",
"reason": "Email verified",
"changedBy": "system",
"changedAt": 1711012000000
},
{
"id": "hist_def",
"userId": "user_123",
"oldStatus": "ACTIVE",
"newStatus": "INACTIVE",
"reason": "User requested deactivation",
"changedBy": "user_123",
"changedAt": 1714526000000
}
// ... other history items
],
"metadata": {
"totalCount": 2,
"currentPage": 1,
"pageSize": 10,
"totalPages": 1
}
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "다른 사용자의 상태 이력을 조회할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 4003,
"message": "USER_NOT_FOUND",
"detail": "사용자를 찾을 수 없습니다."
}
계정 활성화
- HTTP 메서드: POST
- 경로: /v1/users/
{userId}/status/activate - Headers:
- Content-Type: application/json
- Authorization: Bearer
{adminToken 또는 internalToken}
- 비고: 주로 PENDING 상태의 사용자를 활성화할 때 사용. Auth 도메인의 이메일 인증 완료 이벤트에 의해 내부적으로 트리거될 수 있음.
요청 (Request)
{
"reason": "Email verified by Auth service"
}
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"oldStatus": "PENDING",
"newStatus": "ACTIVE",
"changedAt": 1711012000000
}
- 오류 응답 (409 Conflict) - 상태 전이 불가
{
"code": 4011,
"message": "INVALID_STATUS_TRANSITION",
"detail": "현재 상태(예: BANNED)에서는 활성화할 수 없습니다."
}
계정 비활성화
- HTTP 메서드: POST
- 경로: /v1/users/
{userId}/status/deactivate - Headers:
- Content-Type: application/json
- Authorization: Bearer
{adminToken 또는 accessToken}
- 비고: 사용자가 직접 요청 시 DELETE /v1/users/
{userId}사용. 관리자가 강제 비활성화 시 이 엔드포인트 사용 가능.
요청 (Request)
{
"reason": "Admin initiated deactivation due to policy violation."
}
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"oldStatus": "ACTIVE",
"newStatus": "INACTIVE",
"changedAt": 1714528000000
}
- 오류 응답 (409 Conflict) - 상태 전이 불가
{
"code": 4011,
"message": "INVALID_STATUS_TRANSITION",
"detail": "이미 비활성화 상태입니다."
}
계정 재활성화
- HTTP 메서드: POST
- 경로: /v1/users/
{userId}/status/reactivate - Headers:
- Content-Type: application/json
- Authorization: Bearer
{adminToken}
요청 (Request)
{
"reason": "User issue resolved, reactivated by admin."
}
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"oldStatus": "INACTIVE",
"newStatus": "ACTIVE",
"changedAt": 1714529000000
}
- 오류 응답 (409 Conflict) - 상태 전이 불가
{
"code": 4011,
"message": "INVALID_STATUS_TRANSITION",
"detail": "비활성화 상태가 아닌 사용자는 재활성화할 수 없습니다."
}
계정 잠금
- HTTP 메서드: POST
- 경로: /v1/users/
{userId}/status/lock - Headers:
- Content-Type: application/json
- Authorization: Bearer
{adminToken 또는 internalToken}
- 비고: 관리자 조치 또는 Auth 도메인에서 로그인 실패 등으로 트리거될 수 있음.
요청 (Request)
{
"reason": "Multiple failed login attempts detected by Auth service."
}
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"oldStatus": "ACTIVE",
"newStatus": "LOCKED",
"changedAt": 1714530000000
}
- 오류 응답 (409 Conflict) - 상태 전이 불가
{
"code": 4011,
"message": "INVALID_STATUS_TRANSITION",
"detail": "현재 상태에서는 잠금 처리할 수 없습니다."
}
계정 잠금 해제
- HTTP 메서드: POST
- 경로: /v1/users/
{userId}/status/unlock - Headers:
- Content-Type: application/json
- Authorization: Bearer
{adminToken 또는 internalToken}
- 비고: 관리자 조치 또는 Auth 도메인에서 시간 만료 등으로 트리거될 수 있음. 이전 상태로 복귀.
요청 (Request)
{
"reason": "User verified identity, unlocked by admin."
}
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"oldStatus": "LOCKED",
"newStatus": "ACTIVE", // 잠금 이전 상태로 복귀
"changedAt": 1714531000000
}
- 오류 응답 (409 Conflict) - 상태 전이 불가
{
"code": 4011,
"message": "INVALID_STATUS_TRANSITION",
"detail": "잠금 상태가 아닌 사용자는 잠금 해제할 수 없습니다."
}
계정 이용 정지
- HTTP 메서드: POST
- 경로: /v1/users/
{userId}/status/suspend - Headers:
- Content-Type: application/json
- Authorization: Bearer
{adminToken}
요청 (Request)
{
"reason": "Temporary suspension due to terms of service violation.",
"suspendUntil": 1717200000000 // 선택적: 정지 만료 시간
}
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"oldStatus": "ACTIVE",
"newStatus": "SUSPENDED",
"changedAt": 1714532000000
}
- 오류 응답 (409 Conflict) - 상태 전이 불가
{
"code": 4011,
"message": "INVALID_STATUS_TRANSITION",
"detail": "현재 상태에서는 이용 정지 처리할 수 없습니다."
}
계정 정지 해제
- HTTP 메서드: POST
- 경로: /v1/users/
{userId}/status/unsuspend - Headers:
- Content-Type: application/json
- Authorization: Bearer
{adminToken}
요청 (Request)
{
"reason": "Suspension period ended or issue resolved."
}
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"oldStatus": "SUSPENDED",
"newStatus": "ACTIVE",
"changedAt": 1714533000000
}
- 오류 응답 (409 Conflict) - 상태 전이 불가
{
"code": 4011,
"message": "INVALID_STATUS_TRANSITION",
"detail": "이용 정지 상태가 아닌 사용자는 정지 해제할 수 없습니다."
}
계정 영구 정지
- HTTP 메서드: POST
- 경로: /v1/users/
{userId}/status/ban - Headers:
- Content-Type: application/json
- Authorization: Bearer
{adminToken}
요청 (Request)
{
"reason": "Permanent ban due to repeated severe violations."
}
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"oldStatus": "SUSPENDED", // 또는 ACTIVE 등 이전 상태
"newStatus": "BANNED",
"changedAt": 1714534000000
}
- 오류 응답 (409 Conflict) - 상태 전이 불가
{
"code": 4011,
"message": "INVALID_STATUS_TRANSITION",
"detail": "이미 영구 정지된 사용자입니다."
}
치료 주기 관리 API
사용자 현재 상태 조회
- HTTP 메서드: GET
- 경로: /v1/users/state/current
- Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
- 비고: 현재 로그인한 사용자의 상태 정보와 일차-날짜 매핑 정보를 함께 조회합니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"userCycleId": "cycle_456",
"planId": "plan_789",
"startedDate": 1714521600000,
"currentUserTime": 1715126400000,
"currentDayIndex": 4,
"isSuspended": false,
"language": "ko",
"timezoneId": "Asia/Seoul",
"isTimeMachineActivated": false,
"suspensions": [
{
"sequence": 1,
"startDate": 1714521600000,
"endDate": 1714694400000,
"durationDays": 2
}
],
"dayMappings": [
{
"dayIndex": 1,
"date": "2025-05-03"
},
{
"dayIndex": 2,
"date": "2025-05-04"
},
{
"dayIndex": 3,
"date": "2025-05-07"
},
{
"dayIndex": 4,
"date": "2025-05-08"
}
],
"suspensionPeriods": [
{
"startDate": 1714867200000,
"endDate": 1714953600000,
"reason": "휴가"
}
]
}
- 오류 응답 (404 Not Found) - 활성 주기가 없는 경우
{
"code": 4041,
"message": "ACTIVE_CYCLE_NOT_FOUND",
"detail": "현재 활성화된 치료 주기가 없습니다."
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "사용자 상태를 조회할 권한이 없습니다."
}
현재 활성 주기의 일차-날짜 매핑 조회
- HTTP 메서드: GET
- 경로: /v1/users/
{userId}/day-mapping 또는 /v1/users/me/day-mapping - Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
- 비고: 현재 활성화된 치료 주기의 일차(dayIndex)와 실제 날짜의 매핑을 조회합니다. 치료 활동 일시 정지 기간은 제외되어 일차가 계산됩니다.
/v1/users/me/day-mapping은 현재 로그인한 사용자 자신의 치료 주기 정보를 조회할 때 사용합니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"cycleId": "cycle_456",
"currentDayIndex": 4,
"dayMappings": [
{
"dayIndex": 1,
"date": "2025-05-03"
},
{
"dayIndex": 2,
"date": "2025-05-04"
},
{
"dayIndex": 3,
"date": "2025-05-07"
},
{
"dayIndex": 4,
"date": "2025-05-08"
}
],
"suspensionPeriods": [
{
"startDate": 1714867200000,
"endDate": 1714953600000
}
]
}
- 오류 응답 (404 Not Found) - 활성 주기가 없는 경우
{
"code": 4041,
"message": "ACTIVE_CYCLE_NOT_FOUND",
"detail": "현재 활성화된 치료 주기가 없습니다."
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "다른 사용자의 치료 주기 정보를 조회할 권한이 없습니다."
}
서비스 이용 기간 관리 API
📌 기술 구현 문서: User 서비스 중단/재개 구현
서비스 중단
- HTTP 메서드: POST
- 경로: /v1/users/
{userId}/service-period/suspend 또는 /v1/users/me/service-period/suspend - Headers:
- Content-Type: application/json
- Authorization: Bearer
{accessToken}
- 비고:
/v1/users/me/service-period/suspend는 현재 로그인한 사용자가 자신의 서비스를 중단할 때 사용합니다.
요청 (Request)
{
"durationDays": 7, // 선택적: 중단 기간(일). 없으면 수동 재개 필요.
"reason": "개인 사정" // 선택적: 중단 사유
}
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"isSuspended": true,
"suspendedAt": "2025-07-29T10:00:00.000Z",
"resumedAt": null,
"expiresAt": "2025-10-27T00:00:00.000Z", // 만료일은 변경되지 않거나, 재계산 로직에 따라 다름
"remainingServiceDays": 60 // 남은 일수는 재계산 로직에 따라 다름
}
- 오류 응답 (400 Bad Request)
{
"code": 4001,
"message": "INVALID_INPUT_DATA",
"detail": "durationDays는 1 이상 90 이하의 정수여야 합니다."
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "서비스 기간을 중단할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 4003,
"message": "USER_NOT_FOUND",
"detail": "사용자를 찾을 수 없습니다."
}
- 오류 응답 (409 Conflict)
{
"code": 4011,
"message": "INVALID_STATUS_TRANSITION",
"detail": "이미 중단된 상태입니다."
}
서비스 재개
- HTTP 메서드: POST
- 경로: /v1/users/
{userId}/service-period/resume 또는 /v1/users/me/service-period/resume - Headers:
- Content-Type: application/json
- Authorization: Bearer
{accessToken}
- 비고:
/v1/users/me/service-period/resume은 현재 로그인한 사용자가 자신의 서비스를 재개할 때 사용합니다.
요청 (Request)
{
"reason": "서비스 다시 이용 시작" // 선택적: 재개 사유
}
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"isSuspended": false,
"suspendedAt": "2025-07-29T10:00:00.000Z", // 마지막 중단 시작 시각
"resumedAt": "2025-08-05T11:30:00.000Z", // 재개 시각
"expiresAt": "2025-11-03T00:00:00.000Z", // 중단 기간만큼 연장된 새 만료일
"remainingServiceDays": 60 // 재개 시점 기준 남은 일수
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "서비스 기간을 재개할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 4003,
"message": "USER_NOT_FOUND",
"detail": "사용자를 찾을 수 없습니다."
}
- 오류 응답 (409 Conflict)
{
"code": 4011,
"message": "INVALID_STATUS_TRANSITION",
"detail": "현재 중단 상태가 아닙니다."
}
서비스 상태 조회
- HTTP 메서드: GET
- 경로: /v1/users/
{userId}/service-period/status 또는 /v1/users/me/service-period/status - Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
- 비고:
/v1/users/me/service-period/status는 현재 로그인한 사용자 자신의 서비스 상태를 조회할 때 사용합니다.
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"isSuspended": false,
"suspendedAt": "2025-07-29T10:00:00.000Z", // 마지막 중단 시작 시각
"resumedAt": "2025-08-05T11:30:00.000Z", // 마지막 재개 시각
"expiresAt": "2025-11-03T00:00:00.000Z", // 현재 유효한 만료일
"remainingServiceDays": 60 // 현재 기준 남은 일수
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "서비스 상태를 조회할 권한이 없습니다."
}
- 오류 응답 (404 Not Found)
{
"code": 4003,
"message": "USER_NOT_FOUND",
"detail": "사용자를 찾을 수 없습니다."
}
테스터 관리 API
테스터 지정
- HTTP 메서드: POST
- 경로: /v1/users/
{userId}/tester/mark - Headers:
- Content-Type: application/json
- Authorization: Bearer
{adminToken}
요청 (Request)
{
"reason": "Assigning user to QA testing group."
}
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"updatedAt": 1714535000000
}
- 오류 응답 (400 Bad Request) - 이미 테스터일 경우
{
"code": 4031, // USER_ALREADY_TESTER
"message": "USER_ALREADY_TESTER",
"detail": "사용자가 이미 테스터로 지정되어 있습니다."
}
테스터 지정 해제
- HTTP 메서드: POST
- 경로: /v1/users/
{userId}/tester/unmark - Headers:
- Content-Type: application/json
- Authorization: Bearer
{adminToken}
요청 (Request)
{
"reason": "Removing user from QA testing group."
}
응답 (Response)
- 성공 응답 (200 OK)
{
"userId": "user_123",
"updatedAt": 1714536000000
}
- 오류 응답 (400 Bad Request) - 테스터가 아닐 경우
{
"code": 4032, // USER_NOT_TESTER
"message": "USER_NOT_TESTER",
"detail": "사용자가 테스터로 지정되어 있지 않습니다."
}
개인정보 보호 API (GDPR 등)
데이터 접근 요청 처리
- HTTP 메서드: GET
- 경로: /v1/users/
{userId}/data-access 또는 /v1/users/me/data-access - Headers:
- Authorization: Bearer
{accessToken}
- Authorization: Bearer
- 비고: 사용자가 자신의 모든 데이터에 대한 사본을 요청합니다. (구현 우선순위 낮음)
/v1/users/me/data-access는 현재 로그인한 사용자 자신의 데이터 접근을 요청할 때 사용합니다.
응답 (Response)
- 성공 응답 (200 OK) - 예시: JSON 형식
{
"userId": "user_123",
"requestedAt": 1714537000000,
"data": {
"account": {
"id": "user_123",
"email": "user@example.com", // 마스킹 처리 필요할 수 있음
"name": "홍길동",
"status": "ACTIVE",
"userType": "USER",
"createdAt": 1711929600000,
"updatedAt": 1714536000000
},
"profile": {
"language": "ko",
"timezone": "Asia/Seoul",
// ... profileData 포함 여부 결정
},
"statusHistory": [
// ... 상태 변경 이력 배열
]
// IAM, Sleep 등 다른 도메인 데이터 포함 여부는 별도 논의 필요
}
}
- 오류 응답 (403 Forbidden)
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "데이터에 접근할 권한이 없습니다."
}
데이터 삭제 요청 처리
- HTTP 메서드: POST
- 경로: /v1/users/
{userId}/data-deletion 또는 /v1/users/me/data-deletion - Headers:
- Content-Type: application/json
- Authorization: Bearer
{accessToken}
- 비고: 사용자가 자신의 모든 데이터 삭제를 요청합니다. (구현 우선순위 낮음)
/v1/users/me/data-deletion은 현재 로그인한 사용자 자신의 데이터 삭제를 요청할 때 사용합니다.
요청 (Request)
{
"reason": "User requested data deletion under GDPR.",
"requestorId": "user_123" // 요청자 ID (본인 또는 관리자)
}
응답 (Response)
- 성공 응답 (200 OK)
{
"message": "사용자 데이터 삭제 요청이 접수되었으며, 비활성화 및 삭제/익명화가 스케줄링됩니다.",
"userId": "user_123",
"status": "INACTIVE", // 즉시 비활성화
"deletionScheduledAt": 1717209600000 // 예상 삭제/익명화 시점 (예: 30일 후)
}
- 오류 응답 (403 Forbidden) - 권한 없음 또는 프로덕션 환경
{
"code": 2060,
"message": "PERMISSION_DENIED",
"detail": "데이터 삭제를 요청할 권한이 없습니다."
}
- 오류 응답 (409 Conflict) - 이미 비활성화 또는 삭제 처리 진행 중
{
"code": 4011,
"message": "INVALID_STATUS_TRANSITION",
"detail": "이미 비활성화되었거나 삭제 절차가 진행 중인 사용자입니다."
}
오류 코드
User 도메인 API에서 사용하는 주요 오류 코드는 다음과 같습니다. (User 도메인 오류 관리 가이드 참조)
| HTTP 상태 코드 | 오류 코드 (User: 4xxx) | 메시지 (Error Class) | 설명 |
|---|---|---|---|
| 500 | (공유) 2000 | SERVER_ERROR | 서버 내부 오류 |
| 401 | (Auth) 2001 | UNAUTHORIZED | 인증이 필요합니다 |
| 403 | (Auth) 2002 | FORBIDDEN | 권한이 없습니다 |
| 403 | (Auth) 2060 | PERMISSION_DENIED | 요청한 작업/리소스에 대한 권한이 없습니다 |
| 400 | 4001 | INVALID_INPUT_DATA (InvalidUserInputError) | 요청 본문 또는 쿼리 파라미터가 유효하지 않음 |
| 409 | 4002 | USER_EMAIL_ALREADY_EXISTS (UserEmailAlreadyExistsError) | 이미 사용 중인 이메일 주소 |
| 404 | 4003 | USER_NOT_FOUND (UserNotFoundError) | 요청한 사용자를 찾을 수 없음 |
| 404 | 4004 | USER_PROFILE_NOT_FOUND (UserProfileNotFoundError) | 요청한 사용자 프로필을 찾을 수 없음 |
| 500 | 4005 | SERVICE_ACCOUNT_CREATION_FAILED (ServiceAccountCreationError) | 서비스 계정 생성 실패 (내부 오류) |
| 404 | 4007 | USER_EMAIL_NOT_FOUND (UserEmailNotFoundError) | 요청한 이메일 주소로 사용자를 찾을 수 없음 |
| 409 | 4011 | INVALID_STATUS_TRANSITION (InvalidStatusTransitionError) | 현재 사용자 상태에서 요청한 작업 불가 |
| 403 | 4012 | CANNOT_DEACTIVATE_SELF (CannotDeactivateSelfError) | 자기 자신을 비활성화할 수 없음 (관리자 등) |
| 400 | 4021 | INVALID_LANGUAGE_CODE (InvalidLanguageCodeError) | 유효하지 않은 언어 코드 (프로필 수정 시) |
| 400 | 4022 | INVALID_TIMEZONE_FORMAT (InvalidTimezoneFormatError) | 유효하지 않은 타임존 ID 형식 (프로필 수정 시) |
| 400 | 4031 | USER_ALREADY_TESTER (UserAlreadyTesterError) | 사용자가 이미 테스터로 지정됨 |
| 400 | 4032 | USER_NOT_TESTER (UserNotTesterError) | 사용자가 테스터로 지정되어 있지 않음 |
| 404 | 4041 | ACTIVE_CYCLE_NOT_FOUND (ActiveCycleNotFoundError) | 현재 활성화된 치료 주기가 없음 |
| 500 | 4042 | DATA_ACCESS_REQUEST_FAILED (DataAccessRequestError) | GDPR 데이터 접근 요청 처리 실패 (내부 오류) |
| 500 | 4043 | DATA_DELETION_REQUEST_FAILED (DataDeletionRequestError) | GDPR 데이터 삭제 요청 처리 실패 (내부 오류) |
| 403 | 4051 | INVALID_USER_TYPE_FOR_OPERATION (InvalidUserTypeForOperationError) | 해당 사용자 유형으로 작업 수행 불가 |
| 500 | 4080 | USER_DATA_DELETION_FAILED (UserDataDeletionFailedError) | 사용자 데이터 완전 삭제 실패 (개발 환경용) |
| 500 | 4099 | UNKNOWN_USER_ERROR (UnknownUserError) | 알 수 없는 사용자 관련 내부 오류 발생 |
참고: 위 목록은 User 도메인 고유 오류 중심으로 작성되었으며, Auth 도메인 오류 등 다른 공통 오류 코드도 함께 사용될 수 있습니다.
변경 이력
| 버전 | 날짜 | 작성자 | 변경 내용 |
|---|---|---|---|
| 0.1.0 | 2025-04-17 | bok@weltcorp.com | 최초 작성 |
| 0.2.0 | 2025-07-29 | AI Assistant | 서비스 중단/재개 API 추가, 오류 코드 업데이트, 접근 권한 매트릭스 수정, 전체 구조 재정렬 |
| 0.2.1 | 2025-07-30 | AI Assistant | GET /v1/users/{userId}/profile 엔드포인트 명세 추가 및 접근 권한 매트릭스 업데이트 |
| 0.2.2 | 2025-05-08 | bok@weltcorp.com | 개발 환경용 사용자 데이터 삭제 API 엔드포인트 및 오류 코드 추가 |
| 0.2.3 | 2025-05-08 | bok@weltcorp.com | 개발 환경용 이메일 기반 사용자 데이터 삭제 API 엔드포인트 및 오류 코드 추가 |
| 0.4.1 | 2025-07-21 | bok@weltcorp.com | 프로필 수정 API 필드명을 schema.prisma와 일치하도록 수정 (timezone → timezoneId, userName 필드 추가, offsetInMinutes 응답 포함) |
| 0.5.0 | 2025-10-27 | bok@weltcorp.com | 게스트 계정 조회 필드 및 만료/정리 API 추가, Step-up 후 만료 취소 API 추가 |
| 0.6.0 | 2025-12-17 | bok@weltcorp.com | 게스트 계정 자발적 탈퇴 지원 명시 (DELETE /v1/users/me) |