Playball Logo

Command Palette

Search for a command to run...

목차 열기

프론트 시스템 아키텍처

프론트엔드는 Next.js App Router를 라우팅/렌더링의 중심으로 두고, UI 컴포넌트, Zustand 기반 클라이언트 상태, 서비스/API 계층, 인증 복구를 분리해 유지보수성과 운영 안정성을 확보한 구조입니다.


전체 구조

프론트엔드 이미지

서비스별 역할

계층핵심 책임
App RouterURL과 페이지 진입점 관리
Layout / Provider공통 레이아웃, 인증 초기화, 전역 환경 구성
Components재사용 가능한 UI와 도메인 화면 조각 구성
Stores로그인, 사용자, 온보딩 등 클라이언트 전역 상태 관리
Services / API백엔드 API 호출과 인증 요청 처리
Config / Security배포, 이미지, 보안 헤더, CDN 설정 관리

백엔드 시스템 아키텍처 (이너)

사용자 요청은 CDN → NLB → Istio를 통과한 뒤 API Gateway에 도달합니다. Gateway에서 JWT를 중앙 검증하고 X-User-Id 헤더를 주입하여 하위 서비스로 라우팅합니다. 하위 서비스는 JWT를 직접 파싱하지 않고 헤더만 신뢰합니다.

PlayBall 백엔드는 5개 마이크로서비스1개 공통 라이브러리로 구성되며, 서비스 간 직접 REST 호출 없이 Redis / Kafka를 통한 간접 데이터 공유만 존재합니다. 현재 DB는 단일 PostgreSQL 인스턴스에 테이블 소유권만 분리된 상태이며, 향후Payment 서비스 분리DB 스키마 분리를 대비해 EDA(Event-Driven Architecture)로 전환했습니다. 상세 내용은 MSA · EDA 전환 문서 참고.


전체 구조

flowchart TD
    U[사용자] --> CDN[Vercel CDN DDOS 방어]
    CDN --> NLB[NLB 접근 제한]
    NLB --> ISTIO[Istio Gateway WAF + mTLS]
    ISTIO --> G[API-Gateway :8085]
    G --> AG[Auth-Guard :8080]
    G --> Q[Queue :8081]
    G --> S[Seat :8082]
    G --> O[Order-Core :8083]

    AG -.-> RC[공용 Redis :6379]
    S -.-> RC
    O -.-> RC
    G -.-> RC
    Q -.-> RQ[Queue 전용 Redis :6380]
    S -.-> RQ

    AG --> DB[(PostgreSQL :5432)]
    S --> DB
    O --> DB

    AG -->|publish| KF[Kafka :9092]
    O -->|publish| KF
    S -->|consume| KF
    O -->|consume| KF

서비스별 역할

서비스포트프레임워크핵심 책임
API-Gateway8085Spring Cloud Gateway (WebFlux)JWT 중앙 검증, 라우팅, CORS, Rate Limiting, 봇 차단
Auth-Guard8080Spring Boot MVCKakao OAuth, JWT 발급/갱신(RTR), 로그아웃/블랙리스트, 유저 차단/해제
Queue8081Spring Boot MVCRedis ZSET 대기열, Admission Token 발급, Pre-Queue 검증
Seat8082Spring Boot MVC좌석 추천/배정, Redisson 분산 락, Hold 관리
Order-Core8083Spring Boot MVC주문 생성, 결제, 이메일 발송, 마이페이지
common-core공유 라이브러리도메인 엔티티, Kafka 설정, 암호화, 전역 예외

데이터 인프라

PostgreSQL

단일 PostgreSQL 16 인스턴스에서 테이블 소유권을 서비스별로 명확히 분리합니다. 각 서비스는 자신의 테이블만 쓰기하고, 다른 서비스 테이블은 읽기만 합니다. AES-256-GCM 필드 암호화가 email, nickname, phone에 적용됩니다.

서비스소유 테이블
Auth-Guardusers, user_sns, dev_users, withdrawal_requests
Seatseats, match_seats, seat_holds, blocks, sections, areas, price_policies
Order-Coreorders, order_seats, payments, cash_receipts, cancellation_fee_policies, inquiries
공유 (common-core)matches, clubs, stadiums, onboarding_preferences, onboarding_preferred_blocks

Redis 2대 분리

Redis는 Queue 전용(:6380)공용(:6379)으로 두 인스턴스를 분리합니다. 티켓 오픈 시 대기열 트래픽이 폭발하더라도 인증이나 좌석 분산 락에 영향을 주지 않도록 설계했습니다.

Kafka 이벤트 메시징 (Apache Kafka 3.7.1)

토픽ProducerConsumer용도
payment-completedOrder-CoreSeat결제 완료 시 좌석 BLOCKED → SOLD 전환
order-cancelledOrder-CoreSeat주문 취소 시 좌석 SOLD → AVAILABLE 복원
bank-transfer-expiredOrder-CoreSeat무통장 입금 기한 만료 시 좌석 복원
user-blockedAuth-GuardOrder-Core유저 차단 시 활성 주문 UNDER_REVIEW 처리

파티션 3 / Acks all / 3회 재시도 후 실패 시 {토픽}.DLT(Dead Letter Topic)로 전송됩니다.


캐싱 전략

Caffeine 로컬 캐시 (JVM 인-메모리)

W-TinyLFU 교체 알고리즘을 사용하는 고성능 로컬 캐시. 네트워크 홉 없이 sub-microsecond 접근이 가능하며, 거의 불변 데이터(Match, Section, Block)에 적용되어 DB 커넥션 부하를 크게 낮췄습니다.

서비스캐시최대 크기TTL대상 데이터
Seatmatch-exists1,00010분Match 존재 검증
Seatmatch-detail1,00010분Match 메타데이터 (JOIN FETCH)
Seatsection-all161시간스타디움 섹션 구조 (영구 불변)
Seatblocks-by-section-ids5121시간스타디움 블럭 매핑
Queuematch-for-queue1,0001분Match saleStatus 검증
Order-Corematch-detail1,00010분주문서용 Match 메타데이터

Redis 분산 캐시

인스턴스 간 공유가 필요한 변동 데이터(User, 응답 캐시)는 Redis 분산 캐시를 사용합니다.

서비스캐시TTL목적
Auth-Guarduser-by-id10분User DTO 스냅샷 (Pod 간 즉시 전파)
Auth-Guardauth-me30초/me 엔드포인트 응답
Seatseat-groups-response5초좌석맵 API 응답 (유저 독립적)
Order-Corematches-list-response30초경기 목록 API 응답

스케줄러 (백그라운드 작업)

서비스스케줄러주기역할
QueueQueuePromotionScheduler1초대기열 → Ready 승격 (배치 100명)
SeatMatchSeatScheduler매일 00:00 KST경기 7일 전 좌석 데이터 자동 생성
SeatSeatHoldCleanupScheduler60초만료된 Hold 정리 + 좌석 AVAILABLE 복원
Order-CoreMatchStatusScheduler10:59 / 00:00 KST경기 판매 개시(ON_SALE) / 종료(CLOSED)
Order-CoreBankTransferExpirationScheduler5분입금 기한 초과 무통장 주문 자동 취소