Participation Service 백엔드 개발 완료

주요 구현 사항:
- 이벤트 참여 등록 및 중복 검증 (Redis Cache + DB)
- 참여자 목록 조회 (필터링, 검색, 페이징)
- 당첨자 추첨 (Fisher-Yates Shuffle 알고리즘)
- Kafka 이벤트 발행 (ParticipantRegistered)
- Redis 캐싱으로 성능 최적화
- 전화번호 마스킹 (개인정보 보호)
- 전역 예외 처리 및 검증

기술 스택:
- Spring Boot 3.x + JPA
- MySQL (참여자, 추첨 로그)
- Redis (캐싱, 중복 검증)
- Kafka (이벤트 발행)

API 엔드포인트:
- POST /events/{eventId}/participate
- GET /events/{eventId}/participants
- GET /events/{eventId}/participants/search
- POST /events/{eventId}/draw-winners
- GET /events/{eventId}/winners

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
doyeon
2025-10-24 09:21:39 +09:00
parent ea82ff4748
commit 5c8aced043
45 changed files with 2908 additions and 1 deletions
@@ -0,0 +1,88 @@
spring:
application:
name: participation-service
datasource:
url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:participation_db}?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8
username: ${DB_USER:root}
password: ${DB_PASSWORD:password}
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: ${DB_POOL_SIZE:10}
minimum-idle: ${DB_MIN_IDLE:5}
connection-timeout: ${DB_CONN_TIMEOUT:30000}
idle-timeout: ${DB_IDLE_TIMEOUT:600000}
max-lifetime: ${DB_MAX_LIFETIME:1800000}
jpa:
hibernate:
ddl-auto: ${JPA_DDL_AUTO:validate}
show-sql: ${JPA_SHOW_SQL:false}
properties:
hibernate:
format_sql: true
use_sql_comments: true
dialect: org.hibernate.dialect.MySQL8Dialect
# Redis Configuration
data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD:}
timeout: ${REDIS_TIMEOUT:3000}
lettuce:
pool:
max-active: ${REDIS_POOL_MAX_ACTIVE:8}
max-idle: ${REDIS_POOL_MAX_IDLE:8}
min-idle: ${REDIS_POOL_MIN_IDLE:2}
max-wait: ${REDIS_POOL_MAX_WAIT:3000}
# Kafka Configuration
kafka:
bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:localhost:9092}
producer:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
acks: ${KAFKA_PRODUCER_ACKS:all}
retries: ${KAFKA_PRODUCER_RETRIES:3}
properties:
max.in.flight.requests.per.connection: 1
enable.idempotence: true
# Topic Names
topics:
participant-registered: participant-events
server:
port: ${SERVER_PORT:8084}
servlet:
context-path: /
error:
include-message: always
include-binding-errors: always
# Logging
logging:
level:
root: ${LOG_LEVEL_ROOT:INFO}
com.kt.event.participation: ${LOG_LEVEL_APP:DEBUG}
org.springframework.data.redis: ${LOG_LEVEL_REDIS:INFO}
org.springframework.kafka: ${LOG_LEVEL_KAFKA:INFO}
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file:
name: ${LOG_FILE_PATH:./logs}/participation-service.log
max-size: ${LOG_FILE_MAX_SIZE:10MB}
max-history: ${LOG_FILE_MAX_HISTORY:30}
# Application-specific Configuration
app:
cache:
duplicate-check-ttl: ${CACHE_DUPLICATE_TTL:604800} # 7 days in seconds
participant-list-ttl: ${CACHE_PARTICIPANT_TTL:600} # 10 minutes in seconds
lottery:
algorithm: FISHER_YATES_SHUFFLE
visit-bonus-weight: ${LOTTERY_VISIT_BONUS:2.0} # 매장 방문 고객 가중치
security:
phone-mask-pattern: "***-****-***" # 전화번호 마스킹 패턴