mirror of
https://github.com/ktds-dg0501/kt-event-marketing.git
synced 2025-12-06 06:46:25 +00:00
변경 사항: - 이벤트생성플로우 outer: FE → Gateway → User Service 호출 패턴 추가 - user-로그인 inner: 전화번호 → 이메일 기반 인증으로 변경 - user-회원가입 inner: 국세청 API 제거, 이메일 중복검사 추가 - event-목적선택 inner: Gateway 경유, 요청/응답 한글화 - ai-트렌드분석및추천 inner: 과거 이벤트 데이터 제거, Timeout 5분으로 변경 - analytics-대시보드조회 inner: Redis TTL 5분 → 1시간으로 변경 모든 파일에 Repository CRUD 작업 한글 설명 적용 (SQL 제거) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
148 lines
5.4 KiB
Plaintext
148 lines
5.4 KiB
Plaintext
@startuml user-로그인
|
|
!theme mono
|
|
|
|
title User Service - 로그인 내부 시퀀스 (UFR-USER-020)
|
|
|
|
actor Client
|
|
participant "UserController" as Controller <<API Layer>>
|
|
participant "UserService" as Service <<Business Layer>>
|
|
participant "AuthenticationService" as AuthService <<Business Layer>>
|
|
participant "UserRepository" as UserRepo <<Data Layer>>
|
|
participant "PasswordEncoder" as PwdEncoder <<Utility>>
|
|
participant "JwtTokenProvider" as JwtProvider <<Utility>>
|
|
participant "Redis\nCache" as Redis <<E>>
|
|
participant "User DB\n(PostgreSQL)" as UserDB <<E>>
|
|
|
|
note over Controller, UserDB
|
|
**UFR-USER-020: 로그인**
|
|
- 입력: 이메일, 비밀번호
|
|
- 비밀번호 검증 (bcrypt compare)
|
|
- JWT 토큰 발급
|
|
- 세션 저장 (Redis)
|
|
- 최종 로그인 시각 업데이트
|
|
end note
|
|
|
|
Client -> Controller: POST /api/users/login\n{"email": "user@example.com",\n"password": "password123"}
|
|
activate Controller
|
|
|
|
Controller -> Controller: 입력값 검증\n(필수 필드, 이메일 형식 확인)
|
|
|
|
Controller -> AuthService: authenticate(email, password)
|
|
activate AuthService
|
|
|
|
== 1단계: 사용자 조회 ==
|
|
|
|
AuthService -> Service: findByEmail(email)
|
|
activate Service
|
|
Service -> UserRepo: findByEmail(email)
|
|
activate UserRepo
|
|
UserRepo -> UserDB: 이메일로 사용자 조회\n(사용자ID, 비밀번호해시, 역할,\n이름, 전화번호 조회)
|
|
activate UserDB
|
|
UserDB --> UserRepo: 사용자 정보 반환 또는 없음
|
|
deactivate UserDB
|
|
UserRepo --> Service: Optional<User>
|
|
deactivate UserRepo
|
|
Service --> AuthService: Optional<User>
|
|
deactivate Service
|
|
|
|
alt 사용자 없음
|
|
AuthService --> Controller: throw AuthenticationFailedException\n("이메일 또는 비밀번호를 확인해주세요")
|
|
Controller --> Client: 401 Unauthorized\n{"code": "AUTH_001",\n"message": "이메일 또는 비밀번호를\n확인해주세요"}
|
|
deactivate AuthService
|
|
deactivate Controller
|
|
|
|
else 사용자 존재
|
|
|
|
== 2단계: 비밀번호 검증 ==
|
|
|
|
AuthService -> PwdEncoder: matches(rawPassword, passwordHash)
|
|
activate PwdEncoder
|
|
PwdEncoder -> PwdEncoder: bcrypt compare\n(입력 비밀번호 vs 저장된 해시)
|
|
PwdEncoder --> AuthService: boolean (일치 여부)
|
|
deactivate PwdEncoder
|
|
|
|
alt 비밀번호 불일치
|
|
AuthService --> Controller: throw AuthenticationFailedException\n("이메일 또는 비밀번호를 확인해주세요")
|
|
Controller --> Client: 401 Unauthorized\n{"code": "AUTH_001",\n"message": "이메일 또는 비밀번호를\n확인해주세요"}
|
|
deactivate AuthService
|
|
deactivate Controller
|
|
|
|
else 비밀번호 일치
|
|
|
|
== 3단계: JWT 토큰 생성 ==
|
|
|
|
AuthService -> JwtProvider: generateToken(userId, role)
|
|
activate JwtProvider
|
|
JwtProvider -> JwtProvider: JWT 토큰 생성\n(Claims: userId, role=OWNER,\nexp=7일)
|
|
JwtProvider --> AuthService: JWT 토큰
|
|
deactivate JwtProvider
|
|
|
|
== 4단계: 세션 저장 ==
|
|
|
|
AuthService -> Redis: 세션 정보 저장\nKey: user:session:{token}\nValue: {userId, role}\nTTL: 7일
|
|
activate Redis
|
|
Redis --> AuthService: 저장 완료
|
|
deactivate Redis
|
|
|
|
== 5단계: 최종 로그인 시각 업데이트 (비동기) ==
|
|
|
|
AuthService ->> Service: updateLastLoginAt(userId)
|
|
activate Service
|
|
note right of Service
|
|
**비동기 처리**
|
|
- @Async 어노테이션 사용
|
|
- 로그인 응답 지연 방지
|
|
- 별도 스레드풀에서 실행
|
|
end note
|
|
Service ->> UserRepo: updateLastLoginAt(userId)
|
|
activate UserRepo
|
|
UserRepo ->> UserDB: 사용자 최종 로그인 시각 갱신\n(현재 시각으로 업데이트)
|
|
activate UserDB
|
|
UserDB -->> UserRepo: 업데이트 완료
|
|
deactivate UserDB
|
|
UserRepo -->> Service: void
|
|
deactivate UserRepo
|
|
Service -->> AuthService: void (비동기 완료)
|
|
deactivate Service
|
|
|
|
note over AuthService, Service
|
|
**비동기 화살표 설명**
|
|
- `->>`: 비동기 호출 (호출 후 즉시 반환)
|
|
- `-->>`: 비동기 응답 (별도 스레드에서 완료)
|
|
end note
|
|
|
|
== 6단계: 응답 반환 ==
|
|
|
|
AuthService -> AuthService: 로그인 응답 DTO 생성
|
|
AuthService --> Controller: LoginResponse\n{token, userId, userName, role, email}
|
|
deactivate AuthService
|
|
|
|
Controller --> Client: 200 OK\n{"token": "eyJhbGc...",\n"userId": 123,\n"userName": "홍길동",\n"role": "OWNER",\n"email": "hong@example.com"}
|
|
deactivate Controller
|
|
end
|
|
end
|
|
|
|
note over Controller, UserDB
|
|
**보안 처리**
|
|
- 비밀번호: bcrypt compare (원본 노출 안 됨)
|
|
- 에러 메시지: 이메일/비밀번호 구분 없이 동일 메시지 반환 (Timing Attack 방어)
|
|
- JWT 토큰: 7일 만료, 서버 세션과 동기화
|
|
|
|
**보안 강화 (향후 구현)**
|
|
- Rate Limiting: IP당 5분에 5회 로그인 실패 시 임시 차단 (15분)
|
|
- Account Lockout: 동일 계정 10회 실패 시 계정 잠금 (관리자 해제)
|
|
- MFA: 2단계 인증 추가 (SMS/TOTP)
|
|
- Anomaly Detection: 비정상 로그인 패턴 감지 (지역, 디바이스 변경)
|
|
|
|
**성능 최적화**
|
|
- 최종 로그인 시각 업데이트: 비동기 처리 (@Async)
|
|
- 평균 응답 시간: 0.5초 이내
|
|
- P95 응답 시간: 1.0초 이내
|
|
- Redis 세션 조회: 0.1초 이내
|
|
|
|
**에러 코드**
|
|
- AUTH_001: 인증 실패 (이메일 또는 비밀번호 불일치)
|
|
end note
|
|
|
|
@enduml
|