add outer/inner sequence
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
@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
|
||||
participant "KafkaProducer" as Kafka
|
||||
|
||||
== 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 -> Repo: findAllByEventIdAndIsWinner(eventId, false)
|
||||
activate Repo
|
||||
Repo -> DB: SELECT * FROM participants\nWHERE event_id = ?\nAND is_winner = false\nORDER BY participated_at ASC
|
||||
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 -> Service: 이벤트 상태 확인\n- 이벤트 종료 여부\n- 이미 추첨 완료 여부
|
||||
|
||||
alt 이벤트가 아직 진행 중
|
||||
Service --> Controller: EventNotEndedException
|
||||
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
|
||||
추첨 알고리즘:
|
||||
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 트랜잭션 시작
|
||||
|
||||
Service -> Repo: updateWinners(winnerIds)
|
||||
activate Repo
|
||||
Repo -> DB: UPDATE participants\nSET is_winner = true,\nwon_at = NOW()\nWHERE participant_id IN (?)
|
||||
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: INSERT INTO draw_logs\n(draw_log_id, event_id, draw_method,\nalgorithm, visit_bonus_applied,\nwinner_count, drawn_at)
|
||||
activate DB
|
||||
note right of DB
|
||||
추첨 로그 저장:
|
||||
- 추첨 일시 기록
|
||||
- 알고리즘 버전 기록
|
||||
- 가산점 적용 여부
|
||||
- 감사 추적 목적
|
||||
end note
|
||||
DB --> LogRepo: 로그 저장 완료
|
||||
deactivate DB
|
||||
LogRepo --> Service: DrawLog 엔티티
|
||||
deactivate LogRepo
|
||||
|
||||
Service -> Service: DB 트랜잭션 커밋
|
||||
|
||||
Service -> Kafka: Publish Event\n"WinnerSelected"\nTopic: participant-events
|
||||
activate Kafka
|
||||
note right of Kafka
|
||||
Event Payload:
|
||||
{
|
||||
"eventId": "UUID",
|
||||
"winners": [
|
||||
{
|
||||
"participantId": "UUID",
|
||||
"name": "홍길동",
|
||||
"phone": "010-1234-5678"
|
||||
}
|
||||
],
|
||||
"timestamp": "2025-10-22T15:00:00Z"
|
||||
}
|
||||
end note
|
||||
Kafka --> Service: 이벤트 발행 완료
|
||||
deactivate Kafka
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user