Skip to content

seheonnn/ticketflow

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TicketFlow

티켓팅 시스템. 동시 100명 예매에서 초과판매 0건을 보장합니다. Redis Lua Script로 재고를 원자적으로 제어하고, Kafka 비동기 처리로 DB 부하를 분산합니다.

기능 설명
회원가입 / 로그인 JWT (Access 30분 + Refresh 7일)
공연 목록 / 검색 Elasticsearch nori 형태소 분석 한국어 검색
공연 상세 이벤트 조회 + 좌석 선택
실시간 재고 표시 SSE로 잔여석 즉시 반영
좌석 예매 Redis Lua Script 원자 감소 → Kafka 비동기 DB 저장 (202)
예매 상태 폴링 202 후 자동 폴링 → 완료/실패 토스트 알림
예매 취소 DB 상태 변경 + Redis 재고 복구

기술 스택

영역 스택
Backend Java 21, Spring Boot 3.x, Gradle 멀티모듈
Database MySQL 8.x, Redis 7.2
Search Elasticsearch 8.x, nori 한국어 분석기
Messaging Apache Kafka (Confluent 7.5)
Security Spring Security, JWT
Frontend Next.js 14 (App Router), TypeScript, Tailwind CSS
Infra Docker Compose

아키텍처

전체 구조

┌─────────────────────────────────────────────────┐
│              Next.js 14  (Frontend)             │
└──────────────────────┬──────────┬───────────────┘
                       │ HTTP     │ SSE
                       │ /REST    │ (실시간 재고)
┌──────────────────────▼──────────▼───────────────┐
│           Spring Boot API  (api module)         │
│   Auth · Event · Reservation · SSE Controller   │
└──────┬──────────────────┬────────────┬──────────┘
       │ JPA              │ Lua Script │ Kafka Produce
  ┌────▼─────┐     ┌──────▼──────┐  ┌─▼────────────────┐
  │ MySQL 8  │     │  Redis 7.2  │  │  Kafka Consumer  │
  │ 영속 데이터 │     │  재고 관리   │  │   DB 비동기 저장  │
  └──────────┘     └─────────────┘  └──────────────────┘
       │ Kafka (event-created)
  ┌────▼──────────────┐
  │  Elasticsearch    │
  │  한국어 검색 인덱스  │
  └───────────────────┘

멀티모듈 구조

backend/
├── api                       (bootJar=true)
│    ├── depends → core-domain
│    ├── depends → core-infra-redis
│    ├── depends → core-infra-kafka
│    ├── depends → core-infra-security
│    └── depends → core-infra-elasticsearch
│
└── core/
     ├── core-domain              Entity, Repository interface
     │    └── (외부 의존 없음 — 순수 도메인)
     ├── core-infra-redis         Redis Lua Script 재고 처리
     │    └── depends → core-domain
     ├── core-infra-kafka         Kafka Producer / Consumer
     │    └── depends → core-domain
     ├── core-infra-security      JWT, Spring Security
     │    └── depends → core-domain
     └── core-infra-elasticsearch Elasticsearch 문서/리포지토리
          └── depends → core-domain

의존 방향: api → core-infra-* → core-domain  (역방향 금지)

로컬 실행

사전 준비: Docker Desktop, Java 21, Node.js 20+

# 1. 인프라 (MySQL + Redis + Kafka + Elasticsearch)
docker compose up -d

# 2. 백엔드
cd backend && ./gradlew :api:bootRun
# → http://localhost:8080
# → http://localhost:8080/swagger-ui/index.html

# 3. 프론트엔드
cd frontend && npm install && npm run dev
# → http://localhost:3000

프론트엔드 .env.local 생성:

NEXT_PUBLIC_API_URL=http://localhost:8080
NEXT_PUBLIC_SSE_URL=http://localhost:8080

테스트

단위 / 통합 테스트

cd backend && ./gradlew :api:test
레이어 도구 케이스
Service JUnit5 + Mockito 예매·취소·상태조회·검색 비즈니스 로직
Repository @DataJpaTest JPA 쿼리 검증
Redis @EmbeddedRedis Lua Script 원자적 재고 감소
Kafka @EmbeddedKafka 예매 이벤트 Consumer / ES 동기화 Consumer
Controller MockMvc 전 엔드포인트 E2E

동시성 / 부하 테스트 (k6)

목표: 동시 100명 예매에서 초과판매 0건

# JWT 토큰 발급 후 실행
k6 run -e TOKEN=<jwt> -e SEAT_ID=1 load-test/reservation.js
시나리오 VUs 시간 검증 기준
동시 예매 100 10s 202 + 409만 허용, 5xx = 0

결과 해석:

  • reservations_accepted: 예매 성공 (202) 건수 → DB 실제 저장 건수와 일치해야 함
  • reservations_sold_out: 재고 소진 (409) 건수
  • 합계 = accepted + sold_out ≤ 총 좌석 수 → 초과판매 0건 보장

검색 성능 테스트

Elasticsearch 기동 후 수동 확인:

# 1. 공연 데이터 생성 (POST /events)
# 2. Kafka를 통해 ES 인덱싱 확인 (2초 이내)
curl http://localhost:9200/events/_search?q=콘서트

# 3. 검색 API 응답 시간 확인
curl -w "\n응답시간: %{time_total}s\n" \
  "http://localhost:8080/events?q=콘서트"
# 목표: 200ms 이하

주요 API

Method Path 설명 인증
POST /auth/signup 회원가입 -
POST /auth/login 로그인 (JWT 발급) -
GET /events 공연 목록 (페이징) -
GET /events?q={keyword} 공연 한국어 검색 (ES) -
GET /events/{id} 공연 상세 + 좌석 -
POST /reservations/{seatId} 좌석 예매 (202) Bearer
GET /reservations/{id}/status 예매 상태 조회 (폴링용) Bearer
GET /reservations/my 내 예매 목록 Bearer
DELETE /reservations/{id} 예매 취소 Bearer
GET /sse/inventory/{eventId} 실시간 재고 구독 -

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors