ํ ์ผ ๊ด๋ฆฌ์ ์ปค์คํฐ๋ง์ด์ง์ ํจ๊ป, Planu ์ฑ์ ๋ฐฑ์๋ API ์๋ฒ
- Todo: ๋ ์ง๋ณ ํ ์ผ ์์ฑ, ์์ , ์ญ์ , ์กฐํ
- Someday: ์ธ์ ๊ฐ ํ ์ผ ๊ด๋ฆฌ
- Category: ์นดํ ๊ณ ๋ฆฌ๋ณ ํ ์ผ ๋ถ๋ฅ
- Sticker Shop: ๋ค์ํ ์คํฐ์ปค ํ๋งค ๋ฐ ๊ตฌ๋งค
- Color Shop: ์ฑ ํ ๋ง ์ปฌ๋ฌ ํ๋งค ๋ฐ ๊ตฌ๋งค
- ํ๋งค๋ ๊ธฐ๋ฐ ์ธ๊ธฐ ์์ดํ ์กฐํ
- ์ฟ ํฐ ๋ฐ๊ธ ๋ฐ ์ฌ์ฉ
- ์ฌ์ฉ ๋ด์ญ ๊ด๋ฆฌ
- JWT ๊ธฐ๋ฐ ์ธ์ฆ
- Spring Security ์ ์ฉ
- Firebase Authentication ์ฐ๋
- Framework: Spring Boot 3.x
- Language: Java 17
- Build Tool: Gradle
- Database: MySQL (JPA/Hibernate)
- Cache: Redis
- JWT: Token ๊ธฐ๋ฐ ์ธ์ฆ
- Spring Security: ๋ณด์ ์ค์
- Firebase: ์์ ๋ก๊ทธ์ธ ์ฐ๋
- Swagger/OpenAPI: API ๋ฌธ์ ์๋ํ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Controller Layer โ โ REST API ์๋ํฌ์ธํธ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Service Layer โ โ ๋น์ฆ๋์ค ๋ก์ง
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Repository Layer โ โ ๋ฐ์ดํฐ ์ ๊ทผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Database (MySQL) โ โ ์์์ฑ ๊ณ์ธต
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- DTO Pattern: ๊ณ์ธต ๊ฐ ๋ฐ์ดํฐ ์ ์ก
- Repository Pattern: ๋ฐ์ดํฐ ์ ๊ทผ ์ถ์ํ
- Dependency Injection: Spring IoC ์ปจํ ์ด๋ ํ์ฉ
- Builder Pattern: ์ํฐํฐ ๋ฐ DTO ์์ฑ
- Exception Handling: ์ ์ญ ์์ธ ์ฒ๋ฆฌ (@ControllerAdvice)
1. ์ฌ์ฉ์ ๋ก๊ทธ์ธ ์์ฒญ
2. ์๋ฒ์์ ์๊ฒฉ์ฆ๋ช
๊ฒ์ฆ
3. JWT Access Token + Refresh Token ๋ฐ๊ธ
4. ํด๋ผ์ด์ธํธ๋ ์์ฒญ ์ Authorization Header์ ํ ํฐ ํฌํจ
5. JwtRequestFilter์์ ํ ํฐ ๊ฒ์ฆ ๋ฐ ์ธ์ฆ ์ฒ๋ฆฌ
- JWT Token: Access Token (๋จ๊ธฐ) + Refresh Token (์ฅ๊ธฐ) ์ ๋ต
- Spring Security: ์๋ํฌ์ธํธ๋ณ ์ ๊ทผ ์ ์ด
- Password Encryption: BCrypt ํด์ฑ ์๊ณ ๋ฆฌ์ฆ
- CORS ์ค์ : ํฌ๋ก์ค ๋๋ฉ์ธ ์์ฒญ ์ ์ด
- Custom Exception Handling: ๋ณด์ ์์ธ ์ํฉ ์ฒ๋ฆฌ
- JwtUtil: JWT ํ ํฐ ์์ฑ, ํ์ฑ, ๊ฒ์ฆ
- JwtRequestFilter: ์์ฒญ๋ง๋ค ํ ํฐ ๊ฒ์ฆ (OncePerRequestFilter)
- SecurityConfig: Spring Security ์ค์ - Firebase Admin SDK ์ด๊ธฐํ
- Firebase Authentication ํ ํฐ ๊ฒ์ฆ
- ์์
๋ก๊ทธ์ธ (Google, Apple ๋ฑ) ์ง์- Redis Template ์ค์
- ์ธ์
๊ด๋ฆฌ ๋ฐ ์์ ๋ฐ์ดํฐ ์ ์ฅ
- Refresh Token ์ ์ฅ์- CustomException: ๋น์ฆ๋์ค ์์ธ ์ ์
- ErrorCode: ์๋ฌ ์ฝ๋ ๋ฐ ๋ฉ์์ง enum
- CustomExceptionHandler: @RestControllerAdvice๋ก ์ ์ญ ์์ธ ์ฒ๋ฆฌ
- ErrorResponseEntity: ์ผ๊ด๋ ์๋ฌ ์๋ต ํ์- Swagger/OpenAPI 3.0 ์ฌ์ฉ
- @Operation, @ApiResponse ์ด๋
ธํ
์ด์
์ผ๋ก ์์ธ ๋ฌธ์ํ
- JWT ์ธ์ฆ ํฌํจํ Try-it-out ๊ธฐ๋ฅ- User: ์ฌ์ฉ์ ์ ๋ณด (OAuth ์ ๋ณด ํฌํจ)
- Category: ํ ์ผ ์นดํ ๊ณ ๋ฆฌ
- Todo: ๋ ์ง๋ณ ํ ์ผ
- TodoSomeday: ์ธ์ ๊ฐ ํ ์ผ
- Sticker: ์ฌ์ฉ์ ์คํฐ์ปค
- ShopSticker/ShopColor: ์์ ์์ดํ
- PurchaseSticker/PurchaseColor: ๊ตฌ๋งค ๋ด์ญ
- Coupon: ์ฟ ํฐ ์ ๋ณด
- CouponUsage: ์ฟ ํฐ ์ฌ์ฉ ๋ด์ญ
- User โ Category: 1:N
- Category โ Todo: 1:N
- User โ Todo: 1:N
- User โ PurchaseSticker/Color: 1:N
- User โ CouponUsage: 1:N
- JPA N+1 ๋ฌธ์ ํด๊ฒฐ: Fetch Join ์ฌ์ฉ
- ์ธ๋ฑ์ค ์ค์ : ์์ฃผ ์กฐํ๋๋ ์ปฌ๋ผ์ ์ธ๋ฑ์ค ์ ์ฉ
- Lazy Loading: ์ฐ๊ด๊ด๊ณ ์ง์ฐ ๋ก๋ฉ ์ ๋ต
- Redis ์บ์: ์์ฃผ ์กฐํ๋๋ ๋ฐ์ดํฐ ์บ์ฑ
- ๋ก์ปฌ ์บ์: Spring Cache ํ์ฉ
- DTO ๋ณํ: ํ์ํ ๋ฐ์ดํฐ๋ง ์๋ต
- ํ์ด์ง๋ค์ด์ : ๋๋ ๋ฐ์ดํฐ ์กฐํ ์ ํ์ด์ง ์ฒ๋ฆฌ
src/main/java/planu/app/
โโโ api/ # API ์คํ ์ธํฐํ์ด์ค
โโโ config/ # ์ค์ ํด๋์ค (Security, Swagger, Firebase, Redis ๋ฑ)
โโโ controller/ # REST API ์ปจํธ๋กค๋ฌ
โโโ dto/ # ์์ฒญ/์๋ต DTO
โ โโโ request/ # ์์ฒญ ๊ฐ์ฒด
โ โโโ response/ # ์๋ต ๊ฐ์ฒด
โโโ entity/ # JPA ์ํฐํฐ
โโโ exception/ # ์์ธ ์ฒ๋ฆฌ
โโโ interceptor/ # ์ธํฐ์
ํฐ
โโโ repository/ # JPA ๋ ํฌ์งํ ๋ฆฌ
โโโ security/ # ๋ณด์ ์ค์
โโโ service/ # ๋น์ฆ๋์ค ๋ก์ง
โโโ util/ # ์ ํธ๋ฆฌํฐ (JWT ๋ฑ)
- Java 17 ์ด์
- MySQL 8.0 ์ด์
- Redis
- Gradle
- ์ ์ฅ์ ํด๋ก
git clone https://github.com/jungyuminn/planu-backend.git
cd planu-backend- ํ๊ฒฝ ์ค์
# application-local.yml ํ์ผ ์์ฑ (gitignore์ ํฌํจ๋จ)
cp src/main/resources/application.yml src/main/resources/application-local.ymlapplication-local.yml์ ๋ค์ ์ ๋ณด๋ฅผ ์ค์ :
- Database ์ฐ๊ฒฐ ์ ๋ณด
- Redis ์ฐ๊ฒฐ ์ ๋ณด
- JWT Secret Key
- Firebase ์ค์
- ๋น๋ ๋ฐ ์คํ
# Gradle ๋น๋
./gradlew build
# ์ ํ๋ฆฌ์ผ์ด์
์คํ
./gradlew bootRun- API ๋ฌธ์ ํ์ธ
http://localhost:8080/swagger-ui.html
POST /api/auth/register- ํ์๊ฐ์POST /api/auth/login- ๋ก๊ทธ์ธPOST /api/auth/refresh- ํ ํฐ ๊ฐฑ์
GET /api/todos- Todo ๋ชฉ๋ก ์กฐํPOST /api/todos- Todo ์์ฑPUT /api/todos/{id}- Todo ์์ DELETE /api/todos/{id}- Todo ์ญ์
GET /api/todos/someday- Someday ๋ชฉ๋ก ์กฐํPOST /api/todos/someday- Someday ์์ฑPUT /api/todos/someday/{id}- Someday ์์ DELETE /api/todos/someday/{id}- Someday ์ญ์
GET /api/categories- ์นดํ ๊ณ ๋ฆฌ ๋ชฉ๋ก ์กฐํPOST /api/categories- ์นดํ ๊ณ ๋ฆฌ ์์ฑPUT /api/categories/{id}- ์นดํ ๊ณ ๋ฆฌ ์์ DELETE /api/categories/{id}- ์นดํ ๊ณ ๋ฆฌ ์ญ์
GET /api/shop/stickers- ์คํฐ์ปค ์์ ๋ชฉ๋กGET /api/shop/colors- ์ปฌ๋ฌ ์์ ๋ชฉ๋กPOST /api/purchase/stickers- ์คํฐ์ปค ๊ตฌ๋งคPOST /api/purchase/colors- ์ปฌ๋ฌ ๊ตฌ๋งค
GET /api/coupons- ์ฟ ํฐ ๋ชฉ๋ก ์กฐํPOST /api/coupons/use- ์ฟ ํฐ ์ฌ์ฉ
์์ธํ API ๋ช ์ธ๋ Swagger ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์.
- IntelliJ IDEA ๊ถ์ฅ
- Lombok ํ๋ฌ๊ทธ์ธ ์ค์น ํ์
- Java Code Convention ์ค์
- 4 spaces ๋ค์ฌ์ฐ๊ธฐ
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'feat: Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
feat: ์๋ก์ด ๊ธฐ๋ฅ ์ถ๊ฐfix: ๋ฒ๊ทธ ์์ docs: ๋ฌธ์ ์์ style: ์ฝ๋ ํฌ๋งทํ , ์ธ๋ฏธ์ฝ๋ก ๋๋ฝ ๋ฑrefactor: ์ฝ๋ ๋ฆฌํฉํ ๋งtest: ํ ์คํธ ์ฝ๋chore: ๋น๋ ์ ๋ฌด ์์ , ํจํค์ง ๋งค๋์ ์์
This project is licensed under the MIT License - see the LICENSE file for details
JungYumin
- GitHub: @jungyuminn
ํ๋ก์ ํธ์ ๋ํ ์ง๋ฌธ์ด๋ ์ ์์ฌํญ์ด ์์ผ์๋ฉด Issue๋ฅผ ๋ฑ๋กํด์ฃผ์ธ์.
โญ๏ธ ์ด ํ๋ก์ ํธ๊ฐ ๋์์ด ๋์๋ค๋ฉด Star๋ฅผ ๋๋ฌ์ฃผ์ธ์!