μΈμ’ λνκ΅ ν΄μ»€ν€μ μν Spring Boot κΈ°λ° REST API μλ²μ λλ€.
- Java 21
- Spring Boot 3.5.5
- Spring Security - JWT κΈ°λ° μΈμ¦/μΈκ°
- Spring Data JPA + QueryDSL - λ°μ΄ν°λ² μ΄μ€ μ κ·Ό
- PostgreSQL - λ©μΈ λ°μ΄ν°λ² μ΄μ€
- Redis - μΈμ κ΄λ¦¬ (μμ )
- Docker + Docker Compose - 컨ν μ΄λν
- AWS ECR - Docker μ΄λ―Έμ§ μ μ₯μ
- AWS EC2 - μλ² νΈμ€ν
- GitHub Actions - CI/CD νμ΄νλΌμΈ
- Swagger/OpenAPI - API λ¬Έμν
- Lombok - μ½λ κ°μν
- P6Spy - SQL 쿼리 λ‘κΉ
- Sejong Portal Login - μΈμ’ λ ν¬νΈ λ‘κ·ΈμΈ μ°λ
- μΈμ’
λνκ΅ ν¬νΈ λ‘κ·ΈμΈ μ°λ
- μΈμ’ λ ν¬νΈ κ³μ μΌλ‘ κ°νΈ λ‘κ·ΈμΈ
- μ΅μ΄ λ‘κ·ΈμΈ μ νμ μ 보 μλ μμ±
- JWT κΈ°λ° μΈμ¦
- Access Token / Refresh Token
- Stateless μΈμ¦ λ°©μ
- λ΄ μ 보 μ‘°ν
- νμ μ 보 μλ λκΈ°ν (ν¬νΈ μ°λ)
- νμ μν κ΄λ¦¬ (ACTIVE, INACTIVE, BANNED)
- Spring Security κΈ°λ° λ³΄μ μ€μ
- JWT ν ν° μΈμ¦/μΈκ°
- CORS μ€μ
- λΉλ°λ²νΈ μνΈν (BCrypt)
- Java 21
- Docker & Docker Compose
- PostgreSQL 14+
- Redis (μ ν)
- λ ν¬μ§ν 리 ν΄λ‘
git clone https://github.com/2025-Sejong-Hackathon/hackathon-backend.git
cd hackathon-backend- νκ²½ λ³μ μ€μ
# src/main/resources/application-dev.yml μ°Έκ³
# λλ νκ²½ λ³μλ‘ μ€μ
export DATASOURCE_URL=jdbc:postgresql://localhost:5432/hackathon
export DATASOURCE_USERNAME=your_username
export DATASOURCE_PASSWORD=your_password
export REDIS_HOST=localhost
export REDIS_PORT=6379
export JWT_SECRET=your-secret-key-min-32-characters
export JWT_ACCESS_TOKEN_EXPIRATION=3600000
export JWT_REFRESH_TOKEN_EXPIRATION=604800000- λ°μ΄ν°λ² μ΄μ€ μ€λΉ
# Dockerλ‘ PostgreSQL μ€ν
docker run -d \
--name hackathon-postgres \
-e POSTGRES_DB=hackathon \
-e POSTGRES_USER=hackathon \
-e POSTGRES_PASSWORD=password \
-p 5432:5432 \
postgres:14- μ ν리μΌμ΄μ μ€ν
# Gradle λΉλ λ° μ€ν
./gradlew bootRun --args='--spring.profiles.active=dev'- API λ¬Έμ νμΈ
http://localhost:8080/swagger-ui.html
κ°λ° νκ²½μμλ Swagger UIλ₯Ό ν΅ν΄ APIλ₯Ό ν μ€νΈν μ μμ΅λλ€.
- URL:
http://localhost:8080/swagger-ui.html - OpenAPI Spec:
http://localhost:8080/api-docs
POST /api/v1/auth/login # μΈμ’
λ ν¬νΈ λ‘κ·ΈμΈ
POST /api/v1/auth/refresh # ν ν° κ°±μ
GET /api/v1/members/me # λ΄ μ 보 μ‘°ν
GET /actuator/health # μλ² μν νμΈ
μΈλΆ μμ² β Nginx (80/443) β Docker (8082:8080) β Spring Boot (8080)
- Nginx: 리λ²μ€ νλ‘μ, λ‘λλ°Έλ°μ±
- Docker: 컨ν μ΄λ 격리 νκ²½
- Spring Boot: μ ν리μΌμ΄μ μλ²
# νκ²½ λ³μ μ€μ
export ECR_REGISTRY=your-account.dkr.ecr.ap-northeast-2.amazonaws.com
export ECR_REPO=hackathon-backend
# .env νμΌ μμ± (docker-compose.ymlκ³Ό κ°μ μμΉ)
cat > .env << EOF
SPRING_PROFILES_ACTIVE=prod
DATASOURCE_URL=jdbc:postgresql://your-db-host:5432/hackathon
DATASOURCE_USERNAME=your_username
DATASOURCE_PASSWORD=your_password
REDIS_HOST=your-redis-host
REDIS_PORT=6379
JWT_SECRET=your-secret-key
JWT_ACCESS_EXPIRATION=3600000
JWT_REFRESH_EXPIRATION=604800000
EOF
# 컨ν
μ΄λ μ€ν
docker-compose up -d# μ΄λ―Έμ§ λΉλ
docker build -t hackathon-backend .
# 컨ν
μ΄λ μ€ν
docker run -d \
-p 8082:8080 \
--env-file .env \
--name hackathon-backend \
hackathon-backendμλ λ°°ν¬ νμ΄νλΌμΈμ΄ ꡬμ±λμ΄ μμ΅λλ€.
mainλΈλμΉμ Push β μλ λ°°ν¬ μμ- λΉλ β Docker μ΄λ―Έμ§ μμ±
- Push to ECR β AWS ECRμ μ΄λ―Έμ§ μ λ‘λ
- Deploy to EC2 β SSHλ‘ EC2 μ μνμ¬ λ°°ν¬
GitHub Repository β Settings β Secrets and variables β Actionsμ λ±λ‘:
AWS_ACCOUNT_ID # AWS κ³μ ID
EC2_HOST # EC2 μΈμ€ν΄μ€ IP/λλ©μΈ
EC2_USER # SSH μ¬μ©μλͺ
(ubuntu)
EC2_KEY # SSH νλΌμ΄λΉ ν€ (PEM νμΌ λ΄μ©)
# 1. μ΄λ―Έμ§ λΉλ
./gradlew clean build -x test
docker build -t hackathon-backend .
# 2. ECRμ Push
aws ecr get-login-password --region ap-northeast-2 | \
docker login --username AWS --password-stdin ${ECR_REGISTRY}
docker tag hackathon-backend:latest ${ECR_REGISTRY}/hackathon-backend:latest
docker push ${ECR_REGISTRY}/hackathon-backend:latest
# 3. EC2μμ Pull & μ€ν
ssh ubuntu@your-ec2-host
docker pull ${ECR_REGISTRY}/hackathon-backend:latest
docker-compose up -dμμΈν λ°°ν¬ κ°μ΄λλ DEPLOYMENT_NOTES.mdλ₯Ό μ°Έκ³ νμΈμ.
hackathon-backend/
βββ src/
β βββ main/
β β βββ java/com/hackathon/backend/
β β β βββ api/ # API Layer (Controller, DTO)
β β β β βββ auth/ # μΈμ¦ API
β β β β βββ member/ # νμ API
β β β βββ domain/ # Domain Layer (Service, Entity, Repository)
β β β β βββ auth/ # μΈμ¦ λλ©μΈ
β β β β βββ member/ # νμ λλ©μΈ
β β β βββ global/ # Global μ€μ λ° μ νΈλ¦¬ν°
β β β β βββ aop/ # AOP (λ‘κΉ
λ±)
β β β β βββ config/ # μ€μ ν΄λμ€
β β β β βββ entity/ # BaseEntity λ±
β β β β βββ exception/ # μμΈ μ²λ¦¬
β β β β βββ jwt/ # JWT μ νΈλ¦¬ν°
β β β β βββ response/ # κ³΅ν΅ μλ΅ νμ
β β β β βββ security/ # Spring Security μ€μ
β β β βββ config/ # λ©μΈ μ€μ νμΌ
β β β βββ JwtProperties.java
β β β βββ SecurityConfig.java
β β β βββ SwaggerConfig.java
β β β βββ WebMvcConfig.java
β β βββ resources/
β β βββ application.yml # κ³΅ν΅ μ€μ
β β βββ application-dev.yml # κ°λ° νκ²½
β β βββ application-prod.yml # μ΄μ νκ²½
β β βββ spy.properties # P6Spy μ€μ
β βββ test/ # ν
μ€νΈ μ½λ
βββ infra/ # μΈνλΌ μ€μ
β βββ nginx/ # Nginx 리λ²μ€ νλ‘μ μ€μ
β β βββ hackathon-backend.conf # Nginx μ€μ νμΌ
β β βββ README.md # Nginx μ€μ κ°μ΄λ
β βββ postgres/ # PostgreSQL μ€μ
β βββ docker-compose.yml
βββ .github/
β βββ workflows/
β βββ deploy.yml # CI/CD νμ΄νλΌμΈ
βββ Dockerfile
βββ docker-compose.yml
βββ README.md
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ν΄λΌμ΄μΈνΈ β
βββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β HTTP/HTTPS
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Nginx (리λ²μ€ νλ‘μ & λ‘λλ°Έλ°μ±) β
β - ν¬νΈ: 80 (HTTP), 443 (HTTPS) β
β - λ‘λλ°Έλ°μ± μκ³ λ¦¬μ¦: least_conn β
βββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β 8082
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Docker Container (격리λ νκ²½) β
β - μΈλΆ: 8082 / λ΄λΆ: 8080 β
β βββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Spring Boot Application β β
β β - ν¬νΈ: 8080 β β
β β - Spring Security + JWT β β
β βββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β
βββββββββββ΄ββββββββββ
β β
βββββββββββββββββββ βββββββββββββββββββ
β PostgreSQL β β Redis β
β (Database) β β (Cache/Session)β
βββββββββββββββββββ βββββββββββββββββββ
βββββββββββββββββββββββββββββββββββ
β API Layer (Controller) β β HTTP μμ²/μλ΅ μ²λ¦¬
βββββββββββββββββββββββββββββββββββ€
β Domain Layer (Service) β β λΉμ¦λμ€ λ‘μ§
βββββββββββββββββββββββββββββββββββ€
β Infrastructure Layer (Repository)β β λ°μ΄ν° μ κ·Ό
βββββββββββββββββββββββββββββββββββ
Client β Controller β Security Filter β JWT Validation
β β
Response β Service β Repository β Load User Data
μμΈν κ°μ΄λ: infra/nginx/README.md
# 1. Nginx μ€μΉ
sudo apt install nginx -y
# 2. μ€μ νμΌ λ³΅μ¬
sudo cp infra/nginx/hackathon-backend.conf /etc/nginx/sites-available/
sudo ln -s /etc/nginx/sites-available/hackathon-backend.conf /etc/nginx/sites-enabled/
# 3. μ€μ ν
μ€νΈ
sudo nginx -t
# 4. Nginx μ¬μμ
sudo systemctl restart nginxλ¨μΌ μλ²μμ μμνμ§λ§, νΈλν½μ΄ μ¦κ°νλ©΄ λ€μκ³Ό κ°μ΄ νμ₯ κ°λ₯:
upstream hackathon_backend {
least_conn; # μ°κ²° μκ° μ μ μλ²λ‘ λΆμ°
server localhost:8082 weight=1;
server localhost:8083 weight=1;
server localhost:8084 weight=1;
}- β 리λ²μ€ νλ‘μ: μΈλΆ μμ²μ λ°±μλλ‘ μ λ¬
- β λ‘λλ°Έλ°μ±: λ€μ€ μλ² λΆν λΆμ° (νμ₯ μ)
- β SSL/TLS: HTTPS μ§μ (Let's Encrypt)
- β Rate Limiting: DDoS λ°©μ΄
- β μΊμ±: API μλ΅ μΊμ± (μ νμ )
- β Gzip μμΆ: μλ΅ ν¬κΈ° μ΅μ ν
- κ³΅ν΅ μ€μ : λͺ¨λ νλ‘νμΌμ μ μ©
- JWT μ€μ : ν ν° λ§λ£ μκ° λ±
- Logging μ€μ : λ‘κ·Έ λ 벨
- κ°λ° νκ²½ μ€μ
ddl-auto: update- μ€ν€λ§ μλ μ λ°μ΄νΈshow-sql: true- SQL 쿼리 λ‘κΉ- Swagger UI νμ±ν
- μ΄μ νκ²½ μ€μ
ddl-auto: validate- μ€ν€λ§ κ²μ¦λ§ μνshow-sql: false- SQL 쿼리 λ‘κΉ λΉνμ±ν- Swagger UI λΉνμ±ν
- Connection Pool μ΅μ ν
# μ 체 ν
μ€νΈ μ€ν
./gradlew test
# νΉμ ν
μ€νΈ μ€ν
./gradlew test --tests com.hackathon.backend.domain.auth.service.AuthServiceTest
# ν
μ€νΈ 리ν¬νΈ νμΈ
open build/reports/tests/test/index.html- Lombok νμ©μΌλ‘ 보μΌλ¬νλ μ΄νΈ μ½λ μ΅μν
- Builder ν¨ν΄ μ¬μ© (Entity μμ±)
- LayeredArchitecture μ€μ
- RESTful API μ€κ³ μμΉ μ€μ
main: μ΄μ νκ²½ (μλ λ°°ν¬)develop: κ°λ° νκ²½feature/*: κΈ°λ₯ κ°λ°hotfix/*: κΈ΄κΈ μμ
feat: μλ‘μ΄ κΈ°λ₯ μΆκ°
fix: λ²κ·Έ μμ
docs: λ¬Έμ μμ
refactor: μ½λ 리ν©ν λ§
test: ν
μ€νΈ μ½λ μΆκ°
chore: λΉλ μ€μ , ν¨ν€μ§ λ§€λμ μμ
-
λ°μ΄ν°λ² μ΄μ€ μ°κ²° μ€ν¨
- PostgreSQLμ΄ μ€ν μ€μΈμ§ νμΈ
DATASOURCE_URLνκ²½ λ³μ νμΈ
-
JWT ν ν° μ€λ₯
JWT_SECRETμ΄ μ΅μ 32μ μ΄μμΈμ§ νμΈ- ν ν° λ§λ£ μκ° νμΈ
-
μΈμ’ λ ν¬νΈ λ‘κ·ΈμΈ μ€ν¨
- μΈμ’ λ ν¬νΈ μλ² μν νμΈ
- νλ²/λΉλ°λ²νΈ μ νμ± νμΈ
μμΈν λ¬Έμ ν΄κ²°μ DEPLOYMENT_NOTES.mdλ₯Ό μ°Έκ³ νμΈμ.
2025 μΈμ’ λνκ΅ ν΄μ»€ν€ λ°±μλ ν
This project is licensed under the MIT License.
Made with β€οΈ by Sejong Hackathon Team