|
| 1 | +# GoTogether |
| 2 | + |
| 3 | +이 문서는 Spring Boot 기반의 이벤트 티켓팅 플랫폼 백엔드 서버의 개발 및 배포 환경을 설명합니다. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Table of Contents |
| 8 | + |
| 9 | +* 시스템 개요 |
| 10 | +* 주요 기능 |
| 11 | +* 코드베이스 구조 |
| 12 | +* 로컬 개발 가이드 |
| 13 | +* Docker 배포 |
| 14 | +* 커밋 컨벤션 |
| 15 | +* 기술 스택 |
| 16 | +* API 응답 구조 |
| 17 | + |
| 18 | +--- |
| 19 | + |
| 20 | +## System Overview |
| 21 | + |
| 22 | +| 구성요소 | 설명 | |
| 23 | +|---------|---------------------------------------| |
| 24 | +| 백엔드 서버 | Spring Boot 3.2.11 (Gradle) + Java 17 | |
| 25 | +| 데이터베이스 | MySQL 8.0+ | |
| 26 | +| 인증 | JWT + OAuth2 (Google, Kakao) | |
| 27 | +| 캐싱 | Redis | |
| 28 | +| 파일 저장소 | AWS S3 | |
| 29 | +| 스케줄링 | Quartz Scheduler | |
| 30 | +| 모니터링 | Prometheus + Micrometer | |
| 31 | +| 문서화 | Swagger (SpringDoc OpenAPI) | |
| 32 | +| 테스트 커버리지 | JaCoCo | |
| 33 | + |
| 34 | +--- |
| 35 | + |
| 36 | +## Features |
| 37 | + |
| 38 | +### Main Service Flow |
| 39 | + |
| 40 | +``` |
| 41 | +사용자 인증 → 이벤트 생성/조회 → 티켓 예매 → QR코드 발급 → 입장 관리 |
| 42 | +``` |
| 43 | + |
| 44 | +--- |
| 45 | + |
| 46 | +### 인증 및 보안 |
| 47 | +- OAuth2 소셜 로그인 (Google, Kakao) |
| 48 | +- JWT 토큰 기반 인증 |
| 49 | +- Spring Security 적용 |
| 50 | + |
| 51 | +### 이벤트 관리 |
| 52 | +- 이벤트 관리 |
| 53 | +- 태그별 이벤트 목록 (최신/인기/마감임박) |
| 54 | +- 키워드 검색 기능 |
| 55 | +- 카테고리별 이벤트 필터 |
| 56 | + |
| 57 | +### 티켓 예매 시스템 |
| 58 | +- 티켓 옵션 관리 (사용자 질문, 응답) |
| 59 | +- 실시간 재고 관리 |
| 60 | +- 주문 및 결제 처리 |
| 61 | +- QR코드 기반 입장 관리 |
| 62 | + |
| 63 | +### 추가 기능 |
| 64 | +- 북마크 기능 |
| 65 | +- 이메일 예약 알림 |
| 66 | +- SMS 인증 |
| 67 | +- Excel 데이터 내보내기 |
| 68 | +- 스케줄링 (Quartz) |
| 69 | + |
| 70 | +--- |
| 71 | + |
| 72 | +## Codebase Structure |
| 73 | + |
| 74 | +``` |
| 75 | +src/main/java/com/gotogether/ |
| 76 | +├── domain/ |
| 77 | +│ ├── user/ |
| 78 | +│ │ ├── controller/ |
| 79 | +│ │ ├── service/ |
| 80 | +│ │ ├── repository/ |
| 81 | +│ │ ├── entity/ |
| 82 | +│ │ ├── dto/ |
| 83 | +│ │ └── converter/ |
| 84 | +│ ├── event/ |
| 85 | +│ ├── hostchannel/ |
| 86 | +│ ├── ticket/ |
| 87 | +│ ├── order/ |
| 88 | +│ ├── bookmark/ |
| 89 | +│ ├── hashtag/ |
| 90 | +│ ├── ticketoption/ |
| 91 | +│ ├── ticketoptionanswer/ |
| 92 | +│ ├── ticketoptionassignment/ |
| 93 | +│ ├── ticketqrcode/ |
| 94 | +│ ├── reservationemail/ |
| 95 | +│ ├── term/ |
| 96 | +│ ├── referencelink/ |
| 97 | +├── global/ |
| 98 | +│ ├── config/ |
| 99 | +│ ├── oauth/ |
| 100 | +│ ├── scheduler/ |
| 101 | +│ ├── util/ |
| 102 | +│ ├── annotation/ |
| 103 | +│ ├── apipayload/ |
| 104 | +│ ├── aspect/ |
| 105 | +│ ├── common/ |
| 106 | +│ ├── constants/ |
| 107 | +│ ├── filter/ |
| 108 | +│ └── interceptor/ |
| 109 | +└── GoTogetherApplication.java |
| 110 | +``` |
| 111 | + |
| 112 | +### Package Structure |
| 113 | + |
| 114 | +- `controller/`: REST API 컨트롤러 |
| 115 | +- `service/`: 비즈니스 로직 |
| 116 | +- `repository/`: 데이터 접근 계층 |
| 117 | +- `entity/`: JPA 엔티티 |
| 118 | +- `dto/`: 데이터 전송 객체 |
| 119 | +- `converter/`: DTO 변환 유틸리티 |
| 120 | + |
| 121 | +--- |
| 122 | + |
| 123 | +## Local Development Guide |
| 124 | + |
| 125 | +### 1. Run with Gradle |
| 126 | + |
| 127 | +```bash |
| 128 | +cd backend |
| 129 | +./gradlew clean build # 의존성 설치 및 빌드 |
| 130 | +./gradlew bootRun # Spring Boot 서버 실행 |
| 131 | +``` |
| 132 | + |
| 133 | +실행 후 API는 `http://localhost:8080`에서 접근 가능합니다. |
| 134 | + |
| 135 | +### 2. API Documentation |
| 136 | + |
| 137 | +Swagger UI를 통해 API 문서를 확인할 수 있습니다: |
| 138 | +- URL: `http://localhost:8080/swagger-ui/index.html` |
| 139 | + |
| 140 | +--- |
| 141 | + |
| 142 | +## Docker Deployment |
| 143 | + |
| 144 | +### Docker Image Build and Deployment |
| 145 | + |
| 146 | +```bash |
| 147 | +# Jib을 사용한 Docker 이미지 빌드 |
| 148 | +./gradlew jib |
| 149 | + |
| 150 | +# 또는 Docker 빌드 |
| 151 | +docker build -t gotogether:latest . |
| 152 | +``` |
| 153 | + |
| 154 | +### Container Execution |
| 155 | + |
| 156 | +```bash |
| 157 | +# Docker Compose로 실행 (설정 파일 필요) |
| 158 | +docker-compose up -d |
| 159 | + |
| 160 | +# 단일 컨테이너 실행 |
| 161 | +docker run -p 8080:8080 gotogether:latest |
| 162 | +``` |
| 163 | + |
| 164 | +--- |
| 165 | + |
| 166 | +## Commit Convention |
| 167 | + |
| 168 | +``` |
| 169 | +<type>: <description> |
| 170 | +
|
| 171 | +[optional body] |
| 172 | +
|
| 173 | +[optional footer] |
| 174 | +``` |
| 175 | + |
| 176 | +### Type (필수) |
| 177 | +| Type | Description | |
| 178 | +|------|----------| |
| 179 | +| `feat` | 새로운 기능 추가 | |
| 180 | +| `fix` | 버그 수정 | |
| 181 | +| `docs` | 문서 수정 | |
| 182 | +| `style` | 코드 스타일 변경 | |
| 183 | +| `refactor` | 코드 리팩토링 | |
| 184 | +| `test` | 테스트 추가 또는 수정 | |
| 185 | +| `chore` | 빌드 또는 기타 작업 | |
| 186 | + |
| 187 | +### Description (필수) |
| 188 | +- 마침표(.) 사용하지 않음 |
| 189 | +- 50자 이내로 간결하게 |
| 190 | + |
| 191 | +--- |
| 192 | + |
| 193 | +## Tech Stack |
| 194 | + |
| 195 | +### Backend |
| 196 | +- **Framework**: Spring Boot 3.2.11 |
| 197 | +- **Language**: Java 17 |
| 198 | +- **Build Tool**: Gradle |
| 199 | +- **Database**: MySQL |
| 200 | +- **ORM**: Spring Data JPA + QueryDSL |
| 201 | +- **Security**: Spring Security + JWT |
| 202 | +- **OAuth2**: Spring OAuth2 Client |
| 203 | + |
| 204 | +### Infrastructure & Tools |
| 205 | +- **Caching**: Redis |
| 206 | +- **File Storage**: AWS S3 |
| 207 | +- **Scheduling**: Quartz Scheduler |
| 208 | +- **Monitoring**: Prometheus + Micrometer |
| 209 | +- **API Documentation**: SpringDoc OpenAPI (Swagger) |
| 210 | +- **Testing**: JUnit 5 + Mockito |
| 211 | +- **Code Coverage**: JaCoCo |
| 212 | +- **Container**: Docker + Jib |
| 213 | + |
| 214 | +### External Services |
| 215 | +- **SMS**: CoolSMS |
| 216 | +- **Email**: JavaMailSender |
| 217 | +- **QR Code**: ZXing |
| 218 | +- **Excel**: Apache POI |
| 219 | + |
| 220 | +--- |
| 221 | + |
| 222 | +## API Response Structure |
| 223 | + |
| 224 | +### Success Response |
| 225 | +```json |
| 226 | +{ |
| 227 | + "isSuccess": true, |
| 228 | + "code": "200", |
| 229 | + "message": "OK", |
| 230 | + "result": { |
| 231 | + // 실제 데이터 |
| 232 | + } |
| 233 | +} |
| 234 | +``` |
| 235 | + |
| 236 | +### Error Response |
| 237 | +```json |
| 238 | +{ |
| 239 | + "isSuccess": false, |
| 240 | + "code": "COMMON4000", |
| 241 | + "message": "잘못된 요청입니다.", |
| 242 | + "result": null |
| 243 | + } |
| 244 | + |
| 245 | + ``` |
| 246 | + |
| 247 | +--- |
| 248 | + |
| 249 | +### Error Code Definition |
| 250 | +```java |
| 251 | +@Getter |
| 252 | +@AllArgsConstructor |
| 253 | +public enum ErrorStatus implements BaseErrorCode { |
| 254 | + // 공통 에러 |
| 255 | + _INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "COMMON5000", "서버 에러. 관리자에게 문의하세요."), |
| 256 | + _BAD_REQUEST(HttpStatus.BAD_REQUEST, "COMMON4000", "잘못된 요청입니다."), |
| 257 | + |
| 258 | + // 사용자 관련 에러 |
| 259 | + _USER_NOT_FOUND(HttpStatus.NOT_FOUND, "USER4001", "사용자가 없습니다."), |
| 260 | + _USER_EMAIL_ALREADY_EXISTS(HttpStatus.BAD_REQUEST, "USER4003", "이미 등록된 이메일입니다."), |
| 261 | + |
| 262 | + // 이벤트 관련 에러 |
| 263 | + _EVENT_NOT_FOUND(HttpStatus.NOT_FOUND, "EVENT4001", "이벤트가 없습니다."), |
| 264 | + _EVENT_DELETE_FAILED_ORDERS_EXIST(HttpStatus.BAD_REQUEST, "EVENT4002", "구매자가 있는 이벤트는 삭제할 수 없습니다."); |
| 265 | + |
| 266 | + private final HttpStatus httpStatus; |
| 267 | + private final String code; |
| 268 | + private final String message; |
| 269 | + |
| 270 | + @Override |
| 271 | + public ErrorReasonDTO getReasonHttpStatus() { |
| 272 | + return ErrorReasonDTO.builder() |
| 273 | + .message(message) |
| 274 | + .code(code) |
| 275 | + .isSuccess(false) |
| 276 | + .httpStatus(httpStatus) |
| 277 | + .build(); |
| 278 | + } |
| 279 | +} |
| 280 | +``` |
| 281 | + |
| 282 | +### Usage Example |
| 283 | +```java |
| 284 | +// 예외 발생 |
| 285 | +throw new GeneralException(ErrorStatus._USER_NOT_FOUND); |
| 286 | + |
| 287 | +// 응답 예시 |
| 288 | +{ |
| 289 | + "isSuccess": false, |
| 290 | + "code": "USER4001", |
| 291 | + "message": "사용자가 없습니다.", |
| 292 | + "result": null |
| 293 | +} |
| 294 | +``` |
| 295 | + |
0 commit comments