Auth Operation 도메인 비즈니스 규칙
Event Storming 기반으로 도출된 Auth Operation Domain의 비즈니스 규칙을 정의합니다.
1. 불변식 (Invariants)
1.1 UserOperationLogin
로그인 실패 횟수 제한
- 규칙: 5회 연속 로그인 실패 시 계정 자동 잠금 (1분간)
- 위반 시: AccountLocked 이벤트 발행
계정 잠금 상태 불변성
- 규칙: 잠긴 계정으로 로그인 시도 시 추가 잠금 시간 연장 없이 거부
- 위반 시: AccountLockedLoginAttempted 이벤트 발행, 로그인 거부
1.2 Token
토큰 페이로드 필수 정보
- 규칙: JWT 토큰은 계정 타입(at), 토큰 타입(type), 도메인(dom) 정보를 필수 포함
- 위반 시: TokenValidationFailed 이벤트 발행
1.3 Invitation
초대 단일 사용 원칙
- 규칙: 초대는 1회만 사용 가능하며, 사용 완료 후 재사용 불가
- 위반 시: InvitationValidationFailed 이벤트 발행, 가입 거부
초대-계정 트랜잭션 일관성
- 규칙: 초대 기반 계정 생성과 초대 상태 업데이트는 원자적으로 처리
- 위반 시: 트랜잭션 롤백
2. 유효성 규칙 (Validation Rules)
2.1 OperationUser
이메일 형식 검증
- 규칙: 계정 생성 시 유효한 이메일 형식 검증 필수
- 위반 시: 예외 발생
비밀번호 길이 검증
- 규칙: 비밀번호는 10~20자리여야 함
- 위반 시: 예외 발생
비밀번호 복잡도 검증
- 규칙: 비밀번호는 숫자, 문자, 특수문자(
!@#$%^&*()_+-=[]{}|;:,.<>?) 중 2가지 이상 포함 - 위반 시: 예외 발생
전화번호 검증
- 규칙: 전화번호는 정규화(sanitize) 및 유효성 검증 필수
- 위반 시: 예외 발생
2.2 Token
토큰 시그니처 검증
- 규칙: JWT 토큰의 시그니처 유효성 검증 필수
- 위반 시: TokenValidationFailed 이벤트 발행, UNAUTHORIZED 에러 반환
토큰 만료 검증
- 규칙: JWT 토큰의 만료 시간 검증 필수
- 위반 시: TokenValidationFailed 이벤트 발행, UNAUTHORIZED 에러 반환
2.3 Invitation
초대 존재 여부 검증
- 규칙: 초대 UUID로 초대 정보 조회 가능 여부 검증
- 위반 시: InvitationValidationFailed 이벤트 발행
초대 만료 검증
- 규칙: 초대의 만료 시간이 현재 시간 이후인지 검증
- 위반 시: InvitationValidationFailed 이벤트 발행
초대 사용 상태 검증
- 규칙: 초대가 이미 사용되지 않았는지 검증 (UserId가 null)
- 위반 시: InvitationValidationFailed 이벤트 발행
3. 상태 전이 규칙 (State Transition Rules)
3.1 LoginAttempt 상태 전이
[초기 상태]
↓ (로그인 실패)
[실패 횟수 증가] (1~4회)
├─→ (로그인 성공)
│ [실패 횟수 초기화]
│
└─→ (5회 실패)
[계정 잠금] (1분간)
↓ (1분 경과)
[잠금 해제 + 실패 횟수 초기화]
전환 조건:
- 로그인 실패 → 실패 횟수 증가: LoginAttemptRecorded 이벤트 발행
- 로그인 성공 → 실패 횟수 초기화: LoginAttemptCountReset 이벤트 발행
- 5회 실패 → 계정 잠금: AccountLocked 이벤트 발행
- 1분 경과 → 잠금 자동 해제
3.2 Invitation 상태 전이
[생성됨] (UserId: null, 만료 시간 미래)
├─→ (회원가입 성공)
│ [사용 완료] (UserId: 설정, 만료 시간: 현재)
│
└─→ (만료 시간 경과)
[만료됨] (사용 불가)
전환 조건:
- 생성 → 사용 완료: InvitationMarkedAsUsed 이벤트 발행, 단일 트랜잭션 처리
- 생성 → 만료: 시간 경과에 따른 자동 전환
4. 권한 규칙 (Authorization Rules)
4.1 인증 권한
| API | PlatformAdmin | SiteAdmin | SiteMember | 비인증 | 비고 |
|---|---|---|---|---|---|
| LoginAccount | ✓ | ✓ | ✓ | ✓ | 공개 API |
| RefreshAccountToken | ✓ | ✓ | ✓ | ✗ | 인증된 사용자 |
4.2 계정 생성 권한
| API | PlatformAdmin | SiteAdmin | SiteMember | 비인증 | 비고 |
|---|---|---|---|---|---|
| CreateAccount | ✓ | ✓ | ✗ | ✗ | 직접 계정 생성 |
| CreateAccountByInvitation | ✓ | ✓ | ✓ | ✓ | 초대를 통한 계정 생성 |
4.3 초대 관리 권한
| API | PlatformAdmin | SiteAdmin | SiteMember | 비인증 | 비고 |
|---|---|---|---|---|---|
| InviteAccountToSite | ✓ | ✓ | ✗ | ✗ | 관리자만 |
| ResendAccountInvitation | ✓ | ✓ | ✗ | ✗ | 관리자만 |
| GetInvitationByUUID | ✓ | ✓ | ✓ | ✓ | 초대 정보 조회 |
| GetAccountInvitationsBySiteId | ✓ | ✓ | ✗ | ✗ | 사이트별 초대 목록 |
5. 계산/파생 규칙 (Derivation Rules)
5.1 토큰 발급 계산
액세스 토큰 만료 시간
- 파생: 로그인 성공 시 액세스 토큰 만료 시간 자동 계산
- 계산식:
AccessTokenExpiresAt := NOW() + AccessTokenTTL
리프레시 토큰 만료 시간
- 파생: 로그인 성공 시 리프레시 토큰 만료 시간 자동 계산
- 계산식:
RefreshTokenExpiresAt := NOW() + RefreshTokenTTL
임시 액세스 토큰 만료 시간
- 파생: 보안 코드 검증 성공 시 임시 토큰 만료 시간 자동 계산 (30분)
- 계산식:
TemporaryAccessTokenExpiresAt := NOW() + 30분
5.2 계정 잠금 해제 시간 계산
잠금 해제 시간
- 파생: 계정 잠금 시 해제 시간 자동 계산
- 계산식:
UnlockTime := LockedAt + 1분
6. 제약 사항 (Constraints)
6.1 보안 제약
비밀번호 암호화 저장
- 제약: 비밀번호는 bcrypt 표준 포맷으로 해싱하여 저장
- 키 관리: SERVER_PEPPER는 환경 변수로 관리
토큰 검증 재시도 정책
- 제약: 토큰 검증 요청 시 최대 3회까지 재시도
- 타임아웃: 1분
리프레시 토큰 저장 의무
- 제약: 리프레시 토큰은 반드시 데이터베이스에 저장
6.2 데이터 보호 제약
토큰 검증 인터셉터
- 제약: 모든 요청에 대해 토큰 디코딩 및 검증 인터셉터 적용 필수
- 예외 처리: 검증 실패 시 UNAUTHORIZED 에러 반환
6.3 감사 및 컴플라이언스 제약
로그인 시도 이력 기록 의무
- 제약: 모든 로그인 시도(성공/실패)에 대해 이력 기록 필수
- 기록 정보: 시간, 계정 이메일, 성공/실패 여부, IP 주소
7. 정책 상세 (Policy Details from Event Storming)
7.1 로그인 실패 처리 정책
| When | Then |
|---|---|
| PasswordVerificationFailed | LoginAttemptRecorded 발행 (실패 횟수 증가) |
| LoginAttemptRecorded (5회) | AccountLocked 발행 (1분간 잠금) |
| LoginSucceeded | LoginAttemptCountReset 발행 |
7.2 초대 기반 회원가입 정책
| When | Then |
|---|---|
| InvitationValidated | AccountCreatedViaInvitation 발행 |
| AccountCreatedViaInvitation | InvitationMarkedAsUsed 발행 (동일 트랜잭션) |
| InvitationValidationFailed | 가입 거부, 에러 반환 |
변경 이력
| 버전 | 날짜 | 작성자 | 변경 내용 |
|---|---|---|---|
| 0.58.0 | 2025-12-16 | mook@weltcorp.com | 문서 최초 작성 |