Skip to content

Commit aed6d1f

Browse files
docs: README 섹션 추가 및 구현 기능 상세화, 구조도 삽입
* README 섹션 추가 및 구현 기능 상세화, 구조도 삽입
1 parent 63a1968 commit aed6d1f

1 file changed

Lines changed: 297 additions & 47 deletions

File tree

README.md

Lines changed: 297 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,163 @@
1-
# WEB7_9_B2ST_BE
2-
> **TT(Ticket & Trade)** — 공연 예매(대기열/좌석 선점/추첨·신청 예매)와 교환·양도(거래), 결제 흐름을 지원하는 백엔드 서버입니다.
1+
# TT (Ticket & Trade) - Backend
32

4-
## 🎯 프로젝트 소개
5-
<img width="1408" height="633" alt="image" src="https://github.com/user-attachments/assets/23181df2-a498-4e96-9f33-7a71cb2848fc" />
3+
> 공연 예매(대기열/좌석 선점/추첨·신청 예매)와 티켓 거래(교환/양도), 결제 흐름을 지원하는 Spring Boot 기반 백엔드 서버
64
7-
(작성)
5+
<p align="center">
6+
<img src="https://img.shields.io/badge/Java-21-ED8B00?logo=openjdk&logoColor=white" alt="Java 21"/>
7+
<img src="https://img.shields.io/badge/Spring%20Boot-4.0.0-6DB33F?logo=springboot&logoColor=white" alt="Spring Boot 4.0.0"/>
8+
<img src="https://img.shields.io/badge/PostgreSQL-16-4169E1?logo=postgresql&logoColor=white" alt="PostgreSQL"/>
9+
<img src="https://img.shields.io/badge/Redis%20Cluster-7-DC382D?logo=redis&logoColor=white" alt="Redis Cluster"/>
10+
<img src="https://img.shields.io/badge/Docker-Compose-2496ED?logo=docker&logoColor=white" alt="Docker"/>
11+
</p>
812

9-
## 👥 팀 구성 & 링크
10-
- 팀 구성: (작성)
11-
- 배포 링크: https://doncrytt.vercel.app/
12-
- Frontend Github: https://github.com/prgrms-web-devcourse-final-project/WEB7_9_B2ST_FE
13-
- Backend Github: https://github.com/prgrms-web-devcourse-final-project/WEB7_9_B2ST_BE
13+
## 📋 목차
1414

15+
- [프로젝트 개요](#-프로젝트-개요)
16+
- [팀 구성](#-팀-구성)
17+
- [링크](#-링크)
18+
- [핵심 기능](#️-핵심-기능)
19+
- [기술 스택](#️-기술-스택)
20+
- [시스템 아키텍처](#️-시스템-아키텍처)
21+
- [ERD](#️-erd)
22+
- [프로젝트 구조](#-프로젝트-구조)
23+
- [모니터링 구성](#-모니터링-구성)
24+
- [협업 규칙](#-협업-규칙)
1525

16-
## ⚙️ 핵심 기능
26+
---
27+
28+
## 🎯 프로젝트 개요
29+
30+
**TT(Ticket & Trade)** 는 공연 티켓 예매 및 2차 거래(교환/양도) 플랫폼의 백엔드 서버입니다.
1731

18-
### 🎫 공연/회차
19-
- 공연 생성/조회(관리자/사용자 분리)
20-
- 회차(공연 일정) 생성 및 조회
21-
- 좌석 등급/가격 정책 관리
32+
### 개발 기간
2233

23-
### ⏳ 대기열
24-
- 예매 트래픽 집중 상황에서 대기열 기반 접근 제어
25-
- Redis 기반 상태 관리(환경 설정으로 on/off 가능)
34+
- 2024.12.03 ~ 2025.01.12
2635

27-
### 🪑 좌석 선점/예매
28-
- 좌석 선점(HOLD) → 예매 확정(SOLD) 흐름
29-
- 선점 만료/실패 처리로 좌석 상태 복구
36+
### 주요 도메인
3037

31-
### 🎲 추첨 예매
32-
- 추첨 응모 생성 및 내 응모 내역 조회
33-
- 추첨 결과 처리 및 좌석 배정 흐름 지원
38+
| 도메인 | 설명 |
39+
|:------------|:---------------------------------------|
40+
| **대기열** | Redis 기반 트래픽 분산, 순차 접근 제어 |
41+
| **좌석 예매** | 좌석 선점(HOLD → SOLD), 만료 자동 복구 |
42+
| **추첨 예매** | 등급별 응모, 공정 추첨, 당첨 알림 |
43+
| **사전신청 예매** | 오픈/마감 정책 기반 신청 처리 |
44+
| **거래** | 티켓 소유권 검증, 교환·양도 흐름 |
45+
| **결제** | 도메인별 결제 흐름 분리, 상태 관리 |
46+
| **인증** | JWT + Refresh Token Rotation, 카카오 OIDC |
3447

35-
### 📝 신청 예매(사전신청)
36-
- 신청 예매 오픈/마감 정책
37-
- 신청/예약 생성 및 만료 처리
48+
---
3849

39-
### 💳 결제
40-
- 도메인별 결제 흐름 분리(예매/신청/추첨/거래)
41-
- 결제 상태 관리 및 후처리 구조
50+
## 👥 팀 구성
4251

43-
### 🔁 교환·양도(거래)
44-
- 거래 등록/조회
45-
- 거래 요청/승인 흐름
46-
- 티켓 상태와 소유권 검증
52+
| 이름 | 역할 | GitHub |
53+
|:--------------:|:-------:|:----------------------------------------------------------------------------------------------------------------------------------:|
54+
| whyin | Backend | [![GitHub](https://img.shields.io/badge/-whyin-181717?logo=github&logoColor=white)](https://github.com/whyin) |
55+
| Chehyeon-Kim23 | Backend | [![GitHub](https://img.shields.io/badge/-Chehyeon--Kim23-181717?logo=github&logoColor=white)](https://github.com/Chehyeon-Kim23) |
56+
| Nomi | Backend | [![GitHub](https://img.shields.io/badge/-77r77r-181717?logo=github&logoColor=white)](https://github.com/77r77r) |
57+
| Minhyung Park | Backend | [![GitHub](https://img.shields.io/badge/-minibr-181717?logo=github&logoColor=white)](https://github.com/minibr) |
58+
| WeeRim | Backend | [![GitHub](https://img.shields.io/badge/-weilim0513--tech-181717?logo=github&logoColor=white)](https://github.com/weilim0513-tech) |
4759

48-
### 🧑‍💼 관리자
49-
- 관리자 전용 API(`/api/admin/**`) 권한 분리
50-
- 공연/예매/거래 운영 지원 기능
60+
---
5161

62+
## 🔗 링크
63+
64+
| 구분 | 링크 |
65+
|:-----------:|:--------------------------------------------------------------------------------------:|
66+
| 🌐 배포 | [https://doncrytt.vercel.app](https://doncrytt.vercel.app/) |
67+
| 💻 Frontend | [WEB7_9_B2ST_FE](https://github.com/prgrms-web-devcourse-final-project/WEB7_9_B2ST_FE) |
68+
| 🔧 Backend | [WEB7_9_B2ST_BE](https://github.com/prgrms-web-devcourse-final-project/WEB7_9_B2ST_BE) |
69+
| 📖 API 문서 | [Swagger UI](http://15.165.115.135:8080/swagger-ui/index.html#/) |
70+
71+
---
72+
73+
## ⚙️ 핵심 기능
74+
75+
### 🔐 인증/인가 (Auth)
76+
77+
| 기능 | 구현 상세 |
78+
|:---------------|:-----------------------------------------------------------------------|
79+
| JWT 인증 | Access Token(30분) + Refresh Token(7일, Redis 저장) |
80+
| Token Rotation | 재발급 시 Family/Generation 기반 탈취 감지, 이전 토큰 사용 시 전체 세션 무효화 |
81+
| 카카오 OIDC | ID Token RSA 서명 검증(JWKS 24시간 캐싱), nonce 1회성 검증, 자동 계정 연동 |
82+
| 로그인 보안 | 5회 실패 시 10분 잠금(Redis TTL), Lua Script 원자적 카운팅 |
83+
| 위협 탐지 | Credential Stuffing(IP당 10+ 계정), Brute Force(IP당 50+ 실패) 탐지 → Slack 알림 |
84+
85+
### 👤 회원 (Member)
86+
87+
| 기능 | 구현 상세 |
88+
|:-------|:--------------------------------------------------|
89+
| 회원가입 | BCrypt 암호화, IP별 Rate Limiting(시간당 3회, Lua Script) |
90+
| 이메일 인증 | SecureRandom 6자리 코드, Redis TTL 5분, 시도 횟수 제한(5회) |
91+
| 탈퇴/복구 | Soft Delete + 30일 복구 유예, 복구 토큰(UUID, 24시간 TTL) |
92+
| 감사 로그 | 로그인/가입 이벤트 비동기 저장(@Async + REQUIRES_NEW) |
93+
94+
### ⏳ 대기열 (Queue)
95+
96+
| 기능 | 구현 상세 |
97+
|:-------|:---------------------------------------|
98+
| 대기열 진입 | Redis Sorted Set 기반, 타임스탬프 스코어로 순서 보장 |
99+
| 순번 조회 | ZRANK 명령으로 실시간 대기 순번 반환 |
100+
| 입장 처리 | 순차적 입장 토큰 발급, 유효 시간 제한 |
101+
| 상태 관리 | WAITING → PROCESSING → COMPLETED 상태 전이 |
102+
| 환경 설정 | 대기열 on/off 설정 가능, 트래픽 상황에 따라 유연하게 적용 |
103+
104+
### 🪑 좌석 예매 (Reservation)
105+
106+
| 기능 | 구현 상세 |
107+
|:------|:-------------------------------------------|
108+
| 좌석 선점 | AVAILABLE → HOLD 상태 전이, 5분 TTL 설정 |
109+
| 중복 방지 | 동일 좌석 동시 선점 시도 시 낙관적 락으로 충돌 감지 |
110+
| 예매 확정 | 결제 완료 시 HOLD → SOLD 상태 전이 |
111+
| 선점 만료 | 스케줄러 기반 TTL 만료 좌석 자동 복구 (HOLD → AVAILABLE) |
112+
| 예매 취소 | 예매 취소 시 좌석 상태 원복, 환불 처리 연동 |
113+
114+
### 🎲 추첨 예매 (Lottery)
115+
116+
| 기능 | 구현 상세 |
117+
|:-------|:---------------------------|
118+
| 응모 등록 | 회차/등급별 응모, 중복 응모 검증 |
119+
| 응모 제한 | 1인당 등급별 최대 응모 수량 제한 |
120+
| 추첨 처리 | SecureRandom 기반 공정 추첨 알고리즘 |
121+
| 당첨 처리 | 당첨자 좌석 자동 배정, 결제 기한 설정 |
122+
| 결과 알림 | 당첨/낙첨 이메일 비동기 발송 |
123+
| 미결제 처리 | 결제 기한 초과 시 자동 당첨 취소, 좌석 반환 |
124+
125+
### 📝 사전신청 예매 (Pre-Reservation)
126+
127+
| 기능 | 구현 상세 |
128+
|:------|:------------------------|
129+
| 신청 기간 | 오픈/마감 일시 기반 신청 가능 기간 검증 |
130+
| 신청 등록 | 회차/등급별 사전신청, 수량 지정 |
131+
| 신청 확정 | 신청 → 결제 대기 → 결제 완료 흐름 |
132+
| 만료 처리 | 결제 기한 초과 시 신청 자동 만료 |
133+
| 신청 취소 | 사용자 요청에 의한 신청 취소 처리 |
134+
135+
### 💳 결제 (Payment)
136+
137+
| 기능 | 구현 상세 |
138+
|:--------|:--------------------------------------------------|
139+
| 도메인별 분리 | 좌석예매/추첨/사전신청/거래 각각 독립된 결제 흐름 |
140+
| 상태 관리 | PENDING → PROCESSING → COMPLETED/FAILED/CANCELLED |
141+
| 환불 계좌 | 계좌번호 마스킹 저장, BankCode Enum 매핑 |
142+
143+
### 🔁 거래 (Trade)
144+
145+
| 기능 | 구현 상세 |
146+
|:-------|:-----------------------|
147+
| 거래 등록 | 티켓 소유권 검증, 중복 등록 방지 |
148+
| 거래 요청 | 구매자 거래 요청, 판매자 승인 대기 |
149+
| 거래 승인 | 판매자 승인 시 결제 프로세스 진입 |
150+
| 소유권 이전 | 결제 완료 시 티켓 소유권 구매자로 변경 |
151+
152+
### 🧑‍💼 관리자 (Admin)
153+
154+
| 기능 | 구현 상세 |
155+
|:------|:------------------------------------------------|
156+
| 회원 관리 | 검색/필터링/페이징, 대시보드 통계 |
157+
| 인증 관리 | 로그인/가입 로그 조회, 계정 잠금 해제 |
158+
| 권한 분리 | `/api/admin/**` URL 레벨 + `@PreAuthorize` 메서드 레벨 |
159+
160+
---
52161

53162
## 🛠️ 기술 스택
54163

@@ -60,6 +169,7 @@
60169
![QueryDSL](https://img.shields.io/badge/QueryDSL-000000?style=for-the-badge)
61170
![Gradle](https://img.shields.io/badge/Gradle-02303A?logo=gradle&logoColor=white&style=for-the-badge)
62171
![Swagger](https://img.shields.io/badge/Swagger-85EA2D?logo=swagger&logoColor=black&style=for-the-badge)
172+
63173
### \<DataBase\>
64174
![PostgreSQL](https://img.shields.io/badge/PostgreSQL-4169E1?logo=postgresql&logoColor=white&style=for-the-badge)
65175
![H2 Database](https://img.shields.io/badge/H2%20Database-1A73E8?logo=h2database&logoColor=white&style=for-the-badge)
@@ -88,24 +198,162 @@
88198
![Testcontainers](https://img.shields.io/badge/Testcontainers-000000?logo=testcontainers&logoColor=white&style=for-the-badge)
89199
![JUnit](https://img.shields.io/badge/JUnit-25A162?logo=junit5&logoColor=white&style=for-the-badge)
90200

91-
## 🏗️ 아키텍처
92-
(작성)
201+
---
202+
203+
## 🏗️ 시스템 아키텍처
204+
205+
<img width="2430" height="1386" alt="Image" src="https://github.com/user-attachments/assets/9d08cc5f-a93b-45b5-9fcd-9c9b39275a24" />
206+
207+
---
93208

94209
## 🗂️ ERD
95-
(작성)
96210

97-
## 🎬 시연 영상
98-
(작성)
211+
![Image](https://github.com/user-attachments/assets/3c393c6a-5186-444d-80fc-b69c17f406c1)
212+
213+
---
214+
215+
## 📁 프로젝트 구조
216+
217+
<details>
218+
<summary><b>펼쳐보기</b></summary>
219+
220+
```
221+
src/main/java/com/back/b2st/
222+
├── domain/
223+
│ ├── auth/ # JWT, OAuth, 로그인 보안, 토큰 관리
224+
│ │ ├── client/ # KakaoApiClient, KakaoJwksClient
225+
│ │ ├── controller/ # AuthController, AuthAdminController
226+
│ │ ├── service/ # AuthService, LoginSecurityService, SecurityThreatDetectionService
227+
│ │ ├── entity/ # RefreshToken(Redis), LoginLog, OAuthNonce
228+
│ │ ├── listener/ # LoginEventListener (비동기 로그 저장)
229+
│ │ └── metrics/ # AuthMetrics, SecurityMetrics
230+
│ │
231+
│ ├── member/ # 회원 CRUD, 탈퇴/복구, Rate Limiting
232+
│ ├── email/ # 이메일 인증, 비동기 발송
233+
│ ├── performance/ # 공연 관리
234+
│ ├── performanceschedule/# 공연 회차
235+
│ ├── seat/ # 좌석 관리
236+
│ ├── scheduleseat/ # 회차별 좌석 상태
237+
│ ├── queue/ # 대기열 시스템
238+
│ ├── reservation/ # 좌석 예매
239+
│ ├── prereservation/ # 사전 신청
240+
│ ├── lottery/ # 추첨 예매
241+
│ ├── payment/ # 결제
242+
│ ├── ticket/ # 티켓 관리
243+
│ ├── trade/ # 거래 (교환/양도)
244+
│ ├── venue/ # 공연장
245+
│ └── bank/ # 은행 코드 Enum
246+
247+
├── global/
248+
│ ├── alert/ # SlackAlertService (Webhook 연동)
249+
│ ├── config/ # Redis, S3, Redisson, Alert 설정
250+
│ ├── error/ # GlobalExceptionHandler, ErrorCode
251+
│ ├── jwt/ # JwtTokenProvider, JwtAuthenticationFilter
252+
│ ├── jpa/ # BaseEntity, QueryDslConfig, AuditorAware
253+
│ ├── s3/ # S3Service, PresignedUrl
254+
│ ├── util/ # MaskingUtil, CookieUtils, SecurityUtils
255+
│ └── metrics/ # MetricsConfig
256+
257+
└── security/ # Spring Security 설정
258+
├── SecurityConfig.java
259+
├── CustomUserDetails.java
260+
├── CustomUserDetailsService.java
261+
├── JwtAuthenticationEntryPoint.java
262+
└── JwtAccessDeniedHandler.java
263+
264+
docker/
265+
├── docker-compose.yml # 전체 스택 (App, DB, Redis Cluster, Monitoring)
266+
├── monitoring/
267+
│ ├── prometheus/
268+
│ │ ├── prometheus.yml
269+
│ │ └── rules/auth-alerts.yml
270+
│ ├── grafana/
271+
│ │ ├── provisioning/
272+
│ │ └── dashboards/
273+
│ └── alertmanager/
274+
│ └── alertmanager.yml
275+
└── init-*.sh # Redis Cluster 초기화 스크립트
276+
```
277+
278+
</details>
279+
280+
---
281+
282+
## 📊 모니터링 구성
283+
284+
<details>
285+
<summary><b>Grafana 대시보드</b></summary>
286+
287+
| 계층 | 대시보드 | 주요 메트릭 |
288+
|:------------|:-------------------------|:----------------------------------------------------------------------------|
289+
| **Service** | tt-service-overview | 요청 수, 에러율, 응답 시간 분포 |
290+
| **Domain** | tt-auth-dashboard | `auth_login_total`, `auth_account_locked_total`, `auth_token_reissue_total` |
291+
| | tt-email-dashboard | `email_sent_total`, `email_verification_total` |
292+
| | tt-queue-dashboard | 대기열 상태, 처리량 |
293+
| | tt-reservation-dashboard | 예매 생성, 좌석 선점/취소 |
294+
| | tt-lottery-dashboard | 응모 수, 당첨 처리 |
295+
| | tt-payment-dashboard | 결제 요청/완료/실패 |
296+
| | tt-trade-dashboard | 거래 등록/완료 |
297+
| **Infra** | tt-jvm-dashboard | 힙 메모리, GC, 스레드 풀 |
298+
| | tt-database-dashboard | 커넥션 풀, 쿼리 성능 |
299+
| | tt-redis-dashboard | 메모리, 커맨드/sec, 키 상태 |
300+
301+
</details>
302+
303+
<details>
304+
<summary><b>Alertmanager 규칙</b></summary>
305+
306+
```yaml
307+
// 예시
308+
groups:
309+
- name: auth-alerts
310+
rules:
311+
- alert: HighLoginFailureRate
312+
expr: rate(auth_login_total{result="failure"}[5m]) > 0.1
313+
for: 2m
314+
labels:
315+
severity: warning
316+
annotations:
317+
summary: "로그인 실패율 증가"
318+
319+
- alert: AccountLockDetected
320+
expr: increase(auth_account_locked_total[5m]) > 0
321+
labels:
322+
severity: critical
323+
annotations:
324+
summary: "계정 잠금 발생"
325+
```
326+
327+
</details>
328+
329+
---
330+
99331
## 🧩 협업 규칙
100332
101-
### 💬 코드 컨벤션
333+
<details>
334+
<summary><b>펼쳐보기</b></summary>
335+
336+
### 코드 컨벤션
337+
102338
- **Naver Java Convention** 기반
103-
- **기본 원칙**
104-
- 가독성 최우선
105-
- 특별한 이유가 없는 경우 **IntelliJ IDEA 자동 서식** 준수
339+
- IntelliJ IDEA 자동 서식 준수
340+
341+
### Git 브랜치 전략
342+
343+
- `main`: 프로덕션
344+
- `develop`: 개발 통합
345+
- `feature/*`: 기능 개발
346+
- 머지 조건: 최소 1명 리뷰 승인
347+
348+
</details>
349+
350+
---
106351

107352
### 🏷️ 네이밍 & 작성 규칙
108353

354+
<details>
355+
<summary><b>펼쳐보기</b></summary>
356+
109357
#### 이슈(Issue)
110358
- **제목 규칙**: `[타입] 작업내용`
111359
- 예시: `[feat] 로그인 기능 추가`
@@ -134,6 +382,8 @@
134382
| `refactor` | 코드 리팩토링(동작 변화 없음) |
135383
| `test` | 테스트 코드 추가/수정 |
136384

385+
</details>
137386

387+
## 📄 라이선스
138388

139-
389+
프로그래머스 K-Digital Training 파이널 프로젝트

0 commit comments

Comments
 (0)