회원가입 API
회원가입 API는 신규 사용자 계정 생성 및 관련 프로세스를 처리합니다. 이메일 인증, 약관 동의, Access Code 검증 후 사용자 계정을 생성합니다.
이 API는 사용자의 기본 정보, 이메일, 비밀번호, 약관 동의 내역 등을 받아 새로운 사용자 계정을 생성합니다.
회원가입 흐름 및 정책에 대한 자세한 내용은 회원가입 프로세스 가이드을 참조하세요. (가이드 문서가 있다면 링크)
선행 조건: 사용자 등록을 위해서는 먼저 이메일 인증 API의 '이메일 인증 코드 발송' 및 '이메일 인증 코드 확인'을 통해 emailVerificationId를 발급받아야 합니다.
회원가입
이메일 인증, 약관 동의, Access Code 검증 후 사용자 계정을 생성합니다.
- HTTP Method:
POST - Path:
/de/v1/auth/register - 인증: App Token 필요 (Authorization: Bearer
{appToken})
Headers
| Header | Type | Description | Required |
|---|---|---|---|
Content-Type | application/json | 요청 본문 형식을 지정합니다. | Yes |
Authorization | string | Bearer <app-token> | Yes |
Request Body (RegisterUserDto)
비밀번호는 클라이언트에서 SHA-256 해싱하여 전송해야 합니다. 해싱 시 appSecret과 deviceUuid를 솔트로 사용합니다.
{
"email": "user@example.com",
"emailVerificationId": "verificationIdFromEmailService",
"passwordHash": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6",
"accessCode": "ABCD1234EFGH5678",
"deviceUuid": "client-device-unique-id",
"profile": {
"userName": "홍길동",
"language": "ko-KR",
"timezone": {
"id": "Asia/Seoul",
"offsetInMinutes": 540
}
},
"agreements": [
{
"versionId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"isAgreed": true
}
// 필요한 모든 약관 포함 (최소 1개)
]
}
| 필드 | 타입 | 설명 | 필수 (Yes/No) |
|---|---|---|---|
email | string | 사용자 이메일 주소 | Yes |
emailVerificationId | string | 이메일 인증 코드 확인 API를 통해 발급받은 ID | Yes |
passwordHash | string | 클라이언트에서 SHA-256 해시된 사용자 비밀번호 (솔트: appSecret + deviceUuid) | Yes |
accessCode | string | 사용자 접근 코드 (16자) | Yes |
deviceUuid | string | 사용자 디바이스 고유 UUID | Yes |
agreements | AgreementDto[] | 동의한 약관 목록 (최소 1개 항목 필요). 자세한 내용은 하단의 "AgreementDto 상세" 섹션 참조 | Yes |
agreements[].versionId | string | 약관 버전 고유 ID (DB의 AgreementsVersion 테이블 ID). | Yes |
agreements[].isAgreed | boolean | 동의 여부 | Yes |
profile | object | 사용자 프로필 정보 | Yes |
profile.userName | string | 사용자 이름 (예: '홍길동') (선택 사항) | No |
profile.language | string | 사용자 언어 설정 (LanguageCodes 참조) (예: 'ko-KR', 'en-US') (profile 제공 시 필수) | Yes |
profile.timezone | object | 사용자 시간대 설정 (profile 제공 시 필수) | Yes |
profile.timezone.id | string | Timezone ID (예: 'Europe/Berlin', 'Asia/Seoul') (profile.timezone 제공 시 필수) | Yes |
profile.timezone.offsetInMinutes | number | UTC로부터의 시간대 오프셋(분) (profile.timezone 제공 시 필수) | Yes |
Responses
| HTTP Status Code | 설명 | Error Code(s) |
|---|---|---|
201 Created | 회원가입 성공 | - |
400 Bad Request | 잘못된 요청 | 2008, 3001, 3003, 3016 |
401 Unauthorized | 앱 토큰 인증 실패 | 2051 |
404 Not Found | 리소스 없음 | 6001 |
409 Conflict | 충돌 | 2024, 3002, 7001 |
412 Precondition Failed | 사전 조건 실패 | 2080 |
429 Too Many Requests | 요청 제한 초과 | 3045 |
500 Internal Server Error | 서버 내부 오류 | 2000 |
201 Created - 회원가입 성공
{
"success": true
}
| 필드 | 타입 | 설명 | 필수 |
|---|---|---|---|
success | boolean | 회원가입 성공 여부를 나타냅니다. | Yes |
400 Bad Request - 잘못된 요청
이메일 미인증, 유효하지 않은 Access Code, 만료된 Access Code, Access Code 그룹 누락, 가입 정보 검증 실패 등 다양한 원인으로 발생할 수 있습니다.
예시: 이메일 미인증
{
"code": 2008, // AuthErrorCode.EMAIL_NOT_VERIFIED
"message": "EMAIL_NOT_VERIFIED",
"detail": "이메일이 인증되지 않았습니다"
}
예시: 유효하지 않은 Access Code
{
"code": 3001, // AccessCodeErrorCode.INVALID_CODE
"message": "INVALID_CODE",
"detail": "The provided access code is invalid."
}
예시: 만료된 Access Code
{
"code": 3003, // AccessCodeErrorCode.CODE_EXPIRED
"message": "CODE_EXPIRED",
"detail": "The access code has expired."
}
예시: 유효하지 않은 Access Code 그룹
{
"code": 3016, // AccessCodeErrorCode.INVALID_CODE_GROUP
"message": "INVALID_CODE_GROUP",
"detail": "Access code is not associated with a valid group."
}
기타 BadRequestException으로 변환될 수 있는 다양한 유효성 검사 오류가 발생할 수 있습니다. AuthErrorCode 및 AccessCodeErrorCode를 참고하세요.
401 Unauthorized - 앱 토큰 인증 실패
{
"code": 2051, // AuthErrorCode.INVALID_TOKEN
"message": "INVALID_TOKEN",
"detail": "토큰이 유효하지 않습니다"
}
404 Not Found - 리소스 없음
예시: Access Code에 연결된 그룹 정보를 IAM에서 찾을 수 없음
{
"code": 6001, // IAMErrorCode.GROUP_NOT_FOUND
"message": "GROUP_NOT_FOUND",
"detail": "그룹 '542b868-c1c8-4446-a71c-9b326fc77fc0'을(를) 찾을 수 없습니다 (IAM 관점)",
"metadata": {
"groupId": "542b868-c1c8-4446-a71c-9b326fc77fc0"
}
}
409 Conflict - 충돌
예시: 이미 사용 중인 이메일 (선제적 확인 - Auth Domain)
{
"code": 2024, // AuthErrorCode.EMAIL_ALREADY_EXISTS
"message": "DUPLICATE_EMAIL",
"detail": "이미 등록된 이메일 주소입니다"
}
이 오류는 auth 도메인의 AuthErrorCode.EMAIL_ALREADY_EXISTS(2024) 에러로, RegistrationService의 registerUser 메서드 초입에서 API 요청 처리 시작 시점에 선제적으로 이메일 사용 여부를 확인할 때 발생합니다. 이 확인은 UserErrorCode.USER_EMAIL_ALREADY_EXISTS(7001) 에러보다 먼저 수행됩니다.
예시: 이미 사용 중인 이메일 (사용자 생성 시 최종 확인 - User Domain)
{
"code": 7001, // UserErrorCode.USER_EMAIL_ALREADY_EXISTS
"message": "USER_EMAIL_ALREADY_EXISTS",
"detail": "이미 존재하는 이메일입니다."
}
이 오류는 user 도메인의 UserErrorCode.USER_EMAIL_ALREADY_EXISTS(7001) 에러로, CreateUserCommand 핸들러 내부에서 prisma를 통해 사용자 데이터 생성 중 최종적으로 이메일 중복이 확인될 때 발생합니다.
예시: 이미 사용된 Access Code
{
"code": 3002, // AccessCodeErrorCode.CODE_ALREADY_USED
"message": "CODE_ALREADY_USED",
"detail": "This access code has already been used."
}
412 Precondition Failed - 사전 조건 실패
예시: 필수 약관 미동의
{
"code": 2080, // AuthErrorCode.REQUIRED_AGREEMENTS_NOT_AGREED
"message": "REQUIRED_AGREEMENTS_NOT_AGREED",
"detail": "필수 약관에 동의하지 않았습니다"
}
429 Too Many Requests - 요청 제한 초과
예시: Access Code 검증 시도 제한 초과
{
"code": 3045, // AccessCodeErrorCode.RATE_LIMIT_EXCEEDED
"message": "RATE_LIMIT_EXCEEDED",
"detail": "Request rate limit exceeded for access code validation.",
"metadata": {
"remainingLockoutSeconds": 60 // 예시 값
}
}
500 Internal Server Error - 서버 내부 오류
{
"code": 2000, // AuthErrorCode.SERVER_ERROR
"message": "SERVER_ERROR",
"detail": "서버 내부 오류"
}
설명
registration.service.ts의registerUser메서드에 해당하며,RegistrationController를 통해 노출됩니다.- 주요 검증 단계 (서비스 로직 내):
- 이메일 인증 검증 (
verifyEmail) - 액세스 코드 검증 및 상세 정보 조회 (
validateAccessCode) - 액세스 코드 그룹 ID 검증 (
validateGroupId) - 필수 약관 동의 여부 검증 (
validateRequiredAgreementsAcceptance)
- 이메일 인증 검증 (
- 성공 시 사용자 계정이 생성되고,
user.registered이벤트가 발생합니다. AccessTokenService.generateTokens가 호출되어 토큰이 생성되지만, 이 API 응답으로 토큰을 직접 반환하지 않습니다. 클라이언트는 등록 후 별도의 로그인 API를 통해 토큰을 받아야 합니다.AuthenticatedRequest의ip및user-agent정보가 사용자 생성 시 활용됩니다.
AgreementDto 상세
agreements 배열에 포함되는 객체에 대한 설명입니다.
| 필드 | 타입 | 설명 | 필수 |
|---|---|---|---|
versionId | string | 동의한 약관 버전의 고유 ID (AgreementsVersion 테이블 PK) | Yes |
isAgreed | boolean | 해당 약관 버전에 동의했는지 여부 | Yes |
참고: registration.service.ts 내부 로직에서 versionId를 사용하여 AgreementsVersion 엔티티를 조회하고, 이를 통해 agreementsId (부모 Agreements 엔티티의 ID)를 가져와 CreateUserCommand에 전달합니다. 따라서 API 요청 시 클라이언트는 versionId와 isAgreed만 정확히 보내면 됩니다.
ProfileDto 상세
RegisterUserDto의 profile 객체에 대한 상세 설명입니다.
| 필드 | 타입 | 설명 | 예시 | 필수 |
|---|---|---|---|---|
userName | string | 사용자 이름 | 홍길동 | No |
language | string | 사용자 언어 설정 | ko-KR | Yes |
timezone | TimezoneDto | 사용자 시간대 설정 (TimezoneDto 참조) | (TimezoneDto 상세 섹션 참조) | Yes |
TimezoneDto 상세
ProfileDto 내의 timezone 객체에 대한 상세 설명입니다.
| 필드 | 타입 | 설명 | 예시 | 필수 |
|---|---|---|---|---|
id | string | Timezone ID (예: 'Europe/Berlin') | Asia/Seoul | Yes |
offsetInMinutes | number | UTC로부터의 시간대 오프셋 (분, Kotlin: Int, Swift: Int) | 540 | Yes |
변경 이력
| 버전 | 날짜 | 작성자 | 변경 내용 |
|---|---|---|---|
| 0.1.0 | 2025-05-19 | elizabeth@weltcorp.com | 최초 문서 작성 |
| 0.2.0 | 2025-05-27 | elizabeth@weltcorp.com | 오류 코드 표준화 (2002 → 2051 INVALID_TOKEN) |