mirror of
https://github.com/ktds-dg0501/kt-event-marketing.git
synced 2025-12-06 12:06:24 +00:00
- 4개 주요 비즈니스 플로우 외부 시퀀스 다이어그램 작성 * 사용자인증플로우: 회원가입, 로그인, 로그아웃 * 이벤트생성플로우: AI 추천, 이미지 생성, 다중 채널 배포 * 고객참여플로우: 이벤트 참여, 당첨자 추첨 * 성과분석플로우: 실시간 대시보드 조회 - Event-Driven 아키텍처 반영 (Kafka Event Topics + Job Topics) - Resilience 패턴 전면 적용 (Circuit Breaker, Retry, Timeout, Fallback) - Cache-Aside 패턴 적용 (Redis 캐싱) - 논리 아키텍처 및 유저스토리 기반 설계 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
249 lines
8.2 KiB
Plaintext
249 lines
8.2 KiB
Plaintext
@startuml 사용자인증플로우
|
|
!theme mono
|
|
|
|
title KT AI 기반 소상공인 이벤트 자동 생성 서비스 - 사용자 인증 플로우 (외부 시퀀스)
|
|
|
|
actor "사용자\n(소상공인)" as User
|
|
participant "Frontend\n(Web/Mobile)" as Frontend
|
|
participant "API Gateway" as Gateway
|
|
participant "User Service" as UserService
|
|
database "Redis\nCache" as Redis
|
|
database "User DB\n(PostgreSQL)" as UserDB
|
|
participant "국세청 API\n(외부)" as NTSApi
|
|
|
|
== UFR-USER-010: 회원가입 플로우 ==
|
|
|
|
User -> Frontend: 회원가입 화면 접근
|
|
activate Frontend
|
|
|
|
User -> Frontend: 회원 정보 입력\n(이름, 전화번호, 이메일, 비밀번호,\n매장명, 업종, 주소, 사업자번호)
|
|
Frontend -> Frontend: 클라이언트 측 유효성 검증\n(이메일 형식, 비밀번호 8자 이상 등)
|
|
|
|
Frontend -> Gateway: POST /api/users/register\n(회원 정보)
|
|
activate Gateway
|
|
|
|
Gateway -> Gateway: Request 검증\n(필수 필드, 데이터 타입)
|
|
|
|
Gateway -> UserService: POST /api/users/register\n(회원 정보)
|
|
activate UserService
|
|
|
|
UserService -> UserService: 서버 측 유효성 검증\n(이름 2자 이상, 전화번호 형식 등)
|
|
|
|
UserService -> UserDB: SELECT users\nWHERE phone_number = ?
|
|
activate UserDB
|
|
UserDB --> UserService: 기존 사용자 확인 결과
|
|
deactivate UserDB
|
|
|
|
alt 중복 사용자 존재
|
|
UserService --> Gateway: 400 Bad Request\n(이미 등록된 전화번호)
|
|
Gateway --> Frontend: 400 Bad Request
|
|
Frontend --> User: "이미 가입된 전화번호입니다"
|
|
else 신규 사용자
|
|
|
|
' 사업자번호 검증 (Circuit Breaker 적용)
|
|
UserService -> Redis: GET user:business:{사업자번호}
|
|
activate Redis
|
|
Redis --> UserService: 캐시된 검증 결과 확인
|
|
deactivate Redis
|
|
|
|
alt 캐시 HIT (검증 결과 있음)
|
|
UserService -> UserService: 캐시된 검증 결과 사용\n(응답 시간: 0.1초)
|
|
else 캐시 MISS (검증 필요)
|
|
UserService -> NTSApi: POST /사업자번호_검증\n(사업자번호)\n[Circuit Breaker, Timeout 5초]
|
|
activate NTSApi
|
|
|
|
alt 국세청 API 정상 응답
|
|
NTSApi --> UserService: 200 OK\n(사업자번호 유효, 영업 상태)
|
|
deactivate NTSApi
|
|
|
|
UserService -> Redis: SET user:business:{사업자번호}\n검증 결과 (TTL 7일)
|
|
activate Redis
|
|
Redis --> UserService: 캐싱 완료
|
|
deactivate Redis
|
|
|
|
else 국세청 API 장애 (Circuit Breaker Open)
|
|
NTSApi --> UserService: 500 Internal Server Error\n또는 Timeout
|
|
deactivate NTSApi
|
|
|
|
UserService -> UserService: Fallback 실행:\n사업자번호 검증 스킵\n(수동 확인 안내)
|
|
|
|
note right of UserService
|
|
**Resilience 패턴 적용**
|
|
- Circuit Breaker: 실패율 50% 초과 시 Open
|
|
- Retry: 최대 3회 재시도 (지수 백오프: 1초, 2초, 4초)
|
|
- Timeout: 5초
|
|
- Fallback: 검증 스킵 (수동 확인 안내)
|
|
end note
|
|
end
|
|
end
|
|
|
|
alt 사업자번호 검증 실패 (휴폐업 등)
|
|
UserService --> Gateway: 400 Bad Request\n(사업자번호 검증 실패)
|
|
Gateway --> Frontend: 400 Bad Request
|
|
Frontend --> User: "유효하지 않은 사업자번호입니다.\n휴폐업 여부를 확인해주세요."
|
|
else 사업자번호 검증 성공
|
|
|
|
UserService -> UserService: 비밀번호 해싱\n(bcrypt, Cost Factor 10)
|
|
|
|
UserService -> UserService: 사업자번호 암호화\n(AES-256)
|
|
|
|
UserService -> UserDB: BEGIN TRANSACTION
|
|
activate UserDB
|
|
|
|
UserService -> UserDB: INSERT INTO users\n(name, phone_number, email,\npassword_hash, created_at)
|
|
UserDB --> UserService: user_id 반환
|
|
|
|
UserService -> UserDB: INSERT INTO stores\n(user_id, store_name, industry,\naddress, business_number_encrypted,\nbusiness_hours)
|
|
UserDB --> UserService: store_id 반환
|
|
|
|
UserService -> UserDB: COMMIT TRANSACTION
|
|
deactivate UserDB
|
|
|
|
UserService -> UserService: JWT 토큰 생성\n(user_id, role=OWNER,\nexp=7일)
|
|
|
|
UserService -> Redis: SET user:session:{token}\n(user_id, role, TTL 7일)
|
|
activate Redis
|
|
Redis --> UserService: 세션 저장 완료
|
|
deactivate Redis
|
|
|
|
UserService --> Gateway: 201 Created\n(JWT 토큰, 사용자 정보)
|
|
deactivate UserService
|
|
|
|
Gateway --> Frontend: 201 Created\n(JWT 토큰, 사용자 정보)
|
|
deactivate Gateway
|
|
|
|
Frontend -> Frontend: JWT 토큰 저장\n(LocalStorage 또는 Cookie)
|
|
|
|
Frontend --> User: "회원가입이 완료되었습니다"
|
|
|
|
Frontend -> Gateway: 대시보드 화면으로 이동
|
|
deactivate Frontend
|
|
end
|
|
end
|
|
|
|
== UFR-USER-020: 로그인 플로우 ==
|
|
|
|
User -> Frontend: 로그인 화면 접근
|
|
activate Frontend
|
|
|
|
User -> Frontend: 전화번호, 비밀번호 입력
|
|
|
|
Frontend -> Frontend: 클라이언트 측 유효성 검증\n(필수 필드 확인)
|
|
|
|
Frontend -> Gateway: POST /api/users/login\n(전화번호, 비밀번호)
|
|
activate Gateway
|
|
|
|
Gateway -> Gateway: Request 검증
|
|
|
|
Gateway -> UserService: POST /api/users/login\n(전화번호, 비밀번호)
|
|
activate UserService
|
|
|
|
UserService -> UserDB: SELECT users\nWHERE phone_number = ?
|
|
activate UserDB
|
|
UserDB --> UserService: 사용자 정보\n(user_id, password_hash, role)
|
|
deactivate UserDB
|
|
|
|
alt 사용자 없음
|
|
UserService --> Gateway: 401 Unauthorized\n(인증 실패)
|
|
Gateway --> Frontend: 401 Unauthorized
|
|
Frontend --> User: "전화번호 또는 비밀번호를\n확인해주세요"
|
|
else 사용자 존재
|
|
|
|
UserService -> UserService: 비밀번호 검증\n(bcrypt compare)
|
|
|
|
alt 비밀번호 불일치
|
|
UserService --> Gateway: 401 Unauthorized\n(인증 실패)
|
|
Gateway --> Frontend: 401 Unauthorized
|
|
Frontend --> User: "전화번호 또는 비밀번호를\n확인해주세요"
|
|
else 비밀번호 일치
|
|
|
|
UserService -> UserService: JWT 토큰 생성\n(user_id, role=OWNER,\nexp=7일)
|
|
|
|
UserService -> Redis: SET user:session:{token}\n(user_id, role, TTL 7일)
|
|
activate Redis
|
|
Redis --> UserService: 세션 저장 완료
|
|
deactivate Redis
|
|
|
|
UserService -> UserDB: UPDATE users\nSET last_login_at = NOW()\nWHERE user_id = ?
|
|
activate UserDB
|
|
UserDB --> UserService: 업데이트 완료
|
|
deactivate UserDB
|
|
|
|
UserService --> Gateway: 200 OK\n(JWT 토큰, 사용자 정보)
|
|
deactivate UserService
|
|
|
|
Gateway --> Frontend: 200 OK\n(JWT 토큰, 사용자 정보)
|
|
deactivate Gateway
|
|
|
|
Frontend -> Frontend: JWT 토큰 저장\n(LocalStorage 또는 Cookie)
|
|
|
|
Frontend --> User: 로그인 성공
|
|
|
|
Frontend -> Gateway: 대시보드 화면으로 이동
|
|
deactivate Frontend
|
|
end
|
|
end
|
|
|
|
== UFR-USER-040: 로그아웃 플로우 ==
|
|
|
|
User -> Frontend: 프로필 탭 접근
|
|
activate Frontend
|
|
|
|
User -> Frontend: "로그아웃" 버튼 클릭
|
|
|
|
Frontend -> Frontend: 확인 다이얼로그 표시\n"로그아웃 하시겠습니까?"
|
|
|
|
User -> Frontend: "확인" 클릭
|
|
|
|
Frontend -> Gateway: POST /api/users/logout\nAuthorization: Bearer {JWT}
|
|
activate Gateway
|
|
|
|
Gateway -> Gateway: JWT 토큰 검증
|
|
|
|
Gateway -> UserService: POST /api/users/logout\n(JWT 토큰)
|
|
activate UserService
|
|
|
|
UserService -> Redis: DEL user:session:{token}
|
|
activate Redis
|
|
Redis --> UserService: 세션 삭제 완료
|
|
deactivate Redis
|
|
|
|
UserService --> Gateway: 200 OK\n(로그아웃 성공)
|
|
deactivate UserService
|
|
|
|
Gateway --> Frontend: 200 OK
|
|
deactivate Gateway
|
|
|
|
Frontend -> Frontend: JWT 토큰 삭제\n(LocalStorage 또는 Cookie)
|
|
|
|
Frontend --> User: "안전하게 로그아웃되었습니다"
|
|
|
|
Frontend -> Gateway: 로그인 화면으로 이동
|
|
deactivate Frontend
|
|
|
|
note over User, NTSApi
|
|
**Resilience 패턴 적용 요약**
|
|
|
|
**Circuit Breaker (국세청 API)**:
|
|
- 실패율 50% 초과 시 Open
|
|
- 30초 후 Half-Open 상태로 전환
|
|
- 3개 요청 테스트 후 상태 결정
|
|
|
|
**Retry Pattern**:
|
|
- 최대 3회 재시도
|
|
- 지수 백오프: 1초, 2초, 4초
|
|
- 재시도 대상: SocketTimeoutException, ConnectException
|
|
|
|
**Timeout Pattern**:
|
|
- 국세청 API: 5초
|
|
|
|
**Fallback Pattern**:
|
|
- 국세청 API 장애 시: 사업자번호 검증 스킵 (수동 확인 안내)
|
|
|
|
**Cache-Aside Pattern**:
|
|
- 사업자번호 검증 결과 캐싱 (TTL 7일)
|
|
- 캐시 HIT: 0.1초, MISS: 5초 (외부 API 호출)
|
|
end note
|
|
|
|
@enduml
|