@startuml participation-이벤트참여 !theme mono title Participation Service - 이벤트 참여 내부 시퀀스 actor "고객" as Customer participant "API Gateway" as Gateway participant "ParticipationController" as Controller participant "ParticipationService" as Service participant "ParticipantRepository" as Repo database "Participation DB" as DB participant "KafkaProducer" as Kafka database "Redis Cache<>" as Cache == UFR-PART-010: 이벤트 참여 == Customer -> Gateway: POST /api/v1/participations\n{name, phone, eventId, entryPath, consent} activate Gateway note right of Gateway 비회원 참여 가능 JWT 검증 불필요 end note Gateway -> Controller: POST /participations/register\n{name, phone, eventId, entryPath, consent} activate Controller Controller -> Controller: 요청 데이터 유효성 검증\n- 이름 2자 이상\n- 전화번호 형식 (정규식)\n- 개인정보 동의 필수 alt 유효성 검증 실패 Controller --> Gateway: 400 Bad Request\n{message: "유효성 오류"} Gateway --> Customer: 400 Bad Request deactivate Controller deactivate Gateway else 유효성 검증 성공 Controller -> Service: registerParticipant(request) activate Service Service -> Cache: GET duplicate_check:{eventId}:{phone} activate Cache Cache --> Service: 캐시 확인 결과 deactivate Cache alt 캐시 HIT: 중복 참여 Service --> Controller: DuplicateParticipationException Controller --> Gateway: 409 Conflict\n{message: "이미 참여하신 이벤트입니다"} Gateway --> Customer: 409 Conflict deactivate Service deactivate Controller deactivate Gateway else 캐시 MISS: DB 조회 Service -> Repo: findByEventIdAndPhoneNumber(eventId, phone) activate Repo Repo -> DB: SELECT * FROM participants\nWHERE event_id = ? AND phone_number = ? activate DB DB --> Repo: 조회 결과 deactivate DB Repo --> Service: Optional deactivate Repo alt DB에 중복 참여 존재 Service -> Cache: SET duplicate_check:{eventId}:{phone} = true\nTTL: 7일 activate Cache Cache --> Service: 캐시 저장 완료 deactivate Cache Service --> Controller: DuplicateParticipationException Controller --> Gateway: 409 Conflict\n{message: "이미 참여하신 이벤트입니다"} Gateway --> Customer: 409 Conflict deactivate Service deactivate Controller deactivate Gateway else 신규 참여: 저장 진행 Service -> Service: 응모 번호 생성\n- UUID 기반\n- 형식: EVT-{timestamp}-{random} Service -> Service: Participant 엔티티 생성\n- participantId (UUID)\n- eventId\n- name, phoneNumber\n- entryPath\n- applicationNumber (응모번호)\n- participatedAt (현재시각) Service -> Repo: save(participant) activate Repo Repo -> DB: INSERT INTO participants\n(participant_id, event_id, name, phone_number,\nentry_path, application_number, participated_at,\nconsent_marketing) activate DB DB --> Repo: 저장 완료 deactivate DB Repo --> Service: Participant 엔티티 반환 deactivate Repo note right of Service 참여자 등록 완료 후 캐싱 및 이벤트 발행 end note Service -> Cache: SET duplicate_check:{eventId}:{phone} = true\nTTL: 7일 activate Cache Cache --> Service: 캐시 저장 완료 deactivate Cache Service -> Kafka: Publish Event\n"ParticipantRegistered"\nTopic: participant-events activate Kafka note right of Kafka Event Payload: { "participantId": "UUID", "eventId": "UUID", "phoneNumber": "010-1234-5678", "entryPath": "SNS", "registeredAt": "2025-10-22T10:30:00Z" } end note Kafka --> Service: 이벤트 발행 완료 deactivate Kafka Service -> Service: 당첨 발표일 계산\n- 이벤트 종료일 + 3일 Service --> Controller: ParticipationResponse\n{응모번호, 당첨발표일, 참여완료메시지} deactivate Service Controller --> Gateway: 201 Created\n{applicationNumber, drawDate, message} deactivate Controller Gateway --> Customer: 201 Created\n참여 완료 화면 표시 deactivate Gateway end end end @enduml