kt-event-marketing-fe/design/backend/sequence/inner/participation-당첨자추첨.puml
cherry2250 3f6e005026 초기 프로젝트 설정 및 설계 문서 추가
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 10:10:16 +09:00

165 lines
6.5 KiB
Plaintext

@startuml participation-당첨자추첨
!theme mono
title Participation Service - 당첨자 추첨 내부 시퀀스
actor "사장님" as Owner
participant "API Gateway" as Gateway
participant "ParticipationController" as Controller
participant "ParticipationService" as Service
participant "LotteryAlgorithm" as Lottery
participant "ParticipantRepository" as Repo
participant "DrawLogRepository" as LogRepo
database "Participation DB" as DB
== UFR-PART-030: 당첨자 추첨 ==
Owner -> Gateway: POST /api/v1/events/{eventId}/draw-winners\n{winnerCount, visitBonus, algorithm}
activate Gateway
Gateway -> Gateway: JWT 토큰 검증\n- 토큰 유효성 확인\n- 사장님 권한 확인
alt JWT 검증 실패
Gateway --> Owner: 401 Unauthorized
deactivate Gateway
else JWT 검증 성공
Gateway -> Controller: POST /participations/draw-winners\n{eventId, winnerCount, visitBonus}
activate Controller
Controller -> Controller: 요청 데이터 유효성 검증\n- eventId 필수\n- winnerCount > 0\n- winnerCount <= 참여자 수
alt 유효성 검증 실패
Controller --> Gateway: 400 Bad Request
Gateway --> Owner: 400 Bad Request
deactivate Controller
deactivate Gateway
else 유효성 검증 성공
Controller -> Service: drawWinners(eventId, winnerCount, visitBonus)
activate Service
Service -> Service: 이벤트 상태 확인\n- 이벤트 종료 여부\n- 이미 추첨 완료 여부
Service -> LogRepo: findByEventId(eventId)
activate LogRepo
LogRepo -> DB: 추첨 로그 조회\n(이벤트ID로 조회)
activate DB
DB --> LogRepo: 추첨 로그 조회
deactivate DB
LogRepo --> Service: Optional<DrawLog>
deactivate LogRepo
alt 이미 추첨 완료
Service --> Controller: AlreadyDrawnException
Controller --> Gateway: 409 Conflict\n{message: "이미 추첨이 완료된 이벤트입니다"}
Gateway --> Owner: 409 Conflict
deactivate Service
deactivate Controller
deactivate Gateway
else 추첨 가능 상태
Service -> Repo: findAllByEventIdAndIsWinner(eventId, false)
activate Repo
Repo -> DB: 미당첨 참여자 목록 조회\n(이벤트ID로 당첨되지 않은\n참여자 전체 조회,\n참여일시 오름차순 정렬)
activate DB
DB --> Repo: 전체 참여자 목록
deactivate DB
Repo --> Service: List<Participant>
deactivate Repo
alt 참여자 수 부족
Service --> Controller: InsufficientParticipantsException
Controller --> Gateway: 400 Bad Request\n{message: "참여자 수가 부족합니다"}
Gateway --> Owner: 400 Bad Request
deactivate Service
deactivate Controller
deactivate Gateway
else 추첨 진행
Service -> Lottery: executeLottery(participants, winnerCount, visitBonus)
activate Lottery
note right of Lottery
추첨 알고리즘:
시간 복잡도: O(n log n)
공간 복잡도: O(n)
1. 난수 생성 (Crypto.randomBytes)
2. 매장 방문 가산점 적용 (옵션)
- 방문 고객: 가중치 2배
- 비방문 고객: 가중치 1배
3. Fisher-Yates Shuffle
- 가중치 기반 확률 분포
- 무작위 섞기
4. 상위 N명 선정
end note
Lottery -> Lottery: Step 1: 난수 시드 생성\n- Crypto.randomBytes(32)\n- 예측 불가능한 난수 보장
Lottery -> Lottery: Step 2: 가산점 적용\n- visitBonus = true일 경우\n- 매장 방문 경로 참여자 가중치 증가
Lottery -> Lottery: Step 3: Fisher-Yates Shuffle\n- 가중치 기반 확률 분포\n- O(n) 시간 복잡도
Lottery -> Lottery: Step 4: 당첨자 선정\n- 상위 winnerCount명 추출
Lottery --> Service: List<Participant> 당첨자 목록
deactivate Lottery
Service -> Service: DB 트랜잭션 시작
alt DB 저장 실패 시
note right of Service
트랜잭션 롤백 처리:
- 당첨자 업데이트 취소
- 추첨 로그 저장 취소
- 재시도 가능 상태 유지
end note
end
Service -> Repo: updateWinners(winnerIds)
activate Repo
Repo -> DB: 당첨자 정보 업데이트\n(당첨 여부를 true로,\n당첨 일시를 현재 시각으로 설정,\n대상: 선정된 참여자ID 목록)
activate DB
DB --> Repo: 업데이트 완료
deactivate DB
Repo --> Service: 업데이트 건수
deactivate Repo
Service -> Service: DrawLog 엔티티 생성\n- drawLogId (UUID)\n- eventId\n- drawMethod: "RANDOM"\n- algorithm: "FISHER_YATES_SHUFFLE"\n- visitBonusApplied\n- winnerCount\n- drawnAt (현재시각)
Service -> LogRepo: save(drawLog)
activate LogRepo
LogRepo -> DB: 추첨 로그 저장\n(추첨로그ID, 이벤트ID,\n추첨방법, 알고리즘,\n가산점적용여부, 당첨인원,\n추첨일시 저장)
activate DB
note right of DB
추첨 로그 저장:
- 추첨 일시 기록
- 알고리즘 버전 기록
- 가산점 적용 여부
- 감사 추적 목적
end note
DB --> LogRepo: 로그 저장 완료
deactivate DB
LogRepo --> Service: DrawLog 엔티티
deactivate LogRepo
Service -> Service: DB 트랜잭션 커밋
Service --> Controller: DrawWinnersResponse\n{당첨자목록, 추첨로그ID}
deactivate Service
Controller --> Gateway: 200 OK\n{winners[], drawLogId, message}
deactivate Controller
Gateway --> Owner: 200 OK
deactivate Gateway
Owner -> Owner: 당첨자 목록 화면 표시\n- 당첨자 정보 테이블\n- 재추첨 버튼\n- 추첨 완료 메시지
end
end
end
end
@enduml