- 2025.09.26 ~ 2025.10.20 (4์ฃผ)
- ์ด 6๋ช (๋ฐฑ์๋ 6๋ช )
๊ณง๊ฐ(GoatGam)์ ์์ ๋ฐฐ๋ฌ ๋ฐฑ์๋ ์๋น์ค๋ก Spring Boot ๊ธฐ๋ฐ์ ๋ฐฑ์๋ ์๋ฒ๋ก ์ค๊ณ๋์์ต๋๋ค. ์ค๊ณ ๊ณผ์ ์์ ๋ฐฐ๋ฌ ์์ ์ฃผ๋ฌธ ๊ณผ์ ์ ๋ถํธํจ์ ์ค์ด๊ณ , ์ฌ์ฉ์์๊ฒ ์ง๊ด์ ์ด๊ณ ๊ฐ๊ฒฐํ ์ฃผ๋ฌธ ๊ฒฝํ์ ์ ๊ณตํ๋ ๊ฒ์ ๋ชฉํ๋ก ํ๋ก์ ํธ๋ฅผ ์งํ ํ์์ต๋๋ค.
๊ณณ๊ฐ์ ์ด๋ฉ์ผ์ ํตํ ๊ฐ์ ์ ์ง์ํ๋ฉฐ ๊ฐ์ ์ Customer, Owner ๋ฑ ์ฌ์ฉ์ ์ ํ์ ์ ํํ์ฌ ๊ฐ์ ํ ์ ์์ต๋๋ค.
'Owner' ์ฌ์ฉ์์ ๊ฒฝ์ฐ ์์ ์ ๊ฐ๊ฒ๋ฅผ ๋ฑ๋กํ๊ณ ์ฌ๋ฌ ๋ฉ๋ด์ ์ฃผ๋ฌธ ์ต์ ๋ฑ์ ๋ฑ๋กํ ์ ์๊ณ , 'Customer' ์ฌ์ฉ์์ ์ฃผ๋ฌธ์ ์๋ฝ, ์ทจ์, ํ๋ถ ํ๋ ๋ฑ ์์ ์ ๊ฐ๊ฒ์ ์ฃผ๋ฌธ์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค. ์ด ํ๋ก์ ํธ๋ ์ฌ์ฉ์์ ์ฃผ์๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ฐฐ๋ฌ ๊ฐ๋ฅํ ์์์ ์ ํ์ํ๊ณ , ๋ฉ๋ด ์ ํ๋ถํฐ ์ฃผ๋ฌธ, ๊ฒฐ์ ๊น์ง์ ์ ๊ณผ์ ์ ํตํฉํ์ฌ ๊ด๋ฆฌํฉ๋๋ค. 'Customer' ์ฌ์ฉ์๋ ์์ ์ ์ฃผ์๋ฅผ ๋ฑ๋กํ๊ณ ๋ฉ๋ด๋ฅผ ์ ํํ์ฌ ์ฃผ๋ฌธํ ์ ์๊ณ , ์ฃผ๋ฌธ์ ์ทจ์ํ ์ ์์ต๋๋ค. ๋ํ, 'Customer' ์ฌ์ฉ์๊ฐ ์ฃผ๋ฌธ์ ๋ฃ์ผ๋ฉด ๋ฐฐ๋ฌ ์งํ์ํฉ์ ๋ฐ๋ผ 'Owner' ์ฌ์ฉ์๋ ๋ฐฐ๋ฌ ์งํ์ํฉ์ ์ ๋ฐ์ดํธ ํ ์ ์์ต๋๋ค.
'Master' ์ฌ์ฉ์์ ๊ฒฝ์ฐ 'Manager'๋ฅผ ์ง์ ํ๊ณ ๊ด๋ฆฌํ ์ ์์ผ๋ฉฐ ์ง์ ๋ 'Manager'๋ 'Customer'๊ณผ 'Owner' ์ฌ์ฉ์๋ฅผ ๊ด๋ฆฌํ๊ณ ์ฌ์ฉ์์ ์ฃผ๋ฌธ์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค. ๋ํ, ์ญ์ ๋ ์๋น์ ๋ค์ ๋ฑ๋กํ๊ฑฐ๋ ์ญ์ ๋ ์ฌ์ฉ์๋ฅผ ๋ค์ ๊ฐ์ ์์ผ์ฃผ๋ ๋ฑ ์ญ์ ๋ ๋ฐ์ดํฐ์ ๋ํ ๊ด๋ฆฌ ๊ธฐ๋ฅ์ ์ํํ ์ ์์ต๋๋ค.
- Swagger (๋ก์ปฌ์ฉ)
- Swagger (๋ฐฐํฌ์ฉ)
MVP ๊ธฐ๋ฅ ๊ตฌํ ์ฅ๋ฐ๊ตฌ๋ ์ฃผ๋ฌธ ๋ด์ญ ๊ณตํต์์ธ ์ฒ๋ฆฌ ํธ๋ค๋ฌ ๊ทธ ์ธ๊ธฐ๋ฅ ๊ฒ์ฆ ๋ฐ ๋ณด์ |
์๋น์๋น API ๊ฐ๋ฐ ํ ์คํธ ์ฝ๋ ์์ฑ ์นดํธ ํ ์คํธ ๊ณตํต์ฝ๋ ๋ฆฌ๋ทฐ |
ํ๋ก์ฐ & ๋ฆฌ๋ทฐ ํ๋ก์ฐ API ๊ฐ๋ฐ ๋ฆฌ๋ทฐ API ๊ฐ๋ฐ ERD ์ฐ๊ด๊ด๊ณ ์ ์ ํ
์คํธํ ์คํธ ์ฝ๋ ์์ฑ |
์๋น์๋น API ๊ฐ๋ฐ ํ ์คํธ ์ฝ๋ ์์ฑ ๊ณตํต์์ธ ์ฒ๋ฆฌ ๋ฌธ์ํ |
์ธ์ฆ/์ธ๊ฐJWT ์ธ์ฆ ๊ตฌํ Spring Security ์ธํ๋ผAWS EC2/RDS/IAM ์ฃผ์/์ง์ญ ๊ด๋ฆฌ |
์์/์ต์
์์, ์ต์ API ๊ฐ๋ฐ ์ฃผ๋ฌธ์ฒ๋ฆฌ์ฃผ๋ฌธ์ฒ๋ฆฌ ๊ตฌํ AIAI์๋น์ค ๊ตฌํ ๊ฒฐ์ ๊ฒฐ์ ์์คํ ๊ตฌํ ๋ฐฐํฌDocker GitHub Actions |
| Category | Stack |
|---|---|
| Language | |
| IDE | |
| Framework | |
| Build Tool | |
| Database | |
| Library | |
| API | |
| DevOps | |
| Tools |
๐ฃ๊ธฐ์ & ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ์ ์ด์
1๏ธโฃ Spring Boot 3.5.6
1. ์๋ ์ค์ ๊ธฐ๋ฅ์ผ๋ก ๊ฐ๋ฐ ์์ฐ์ฑ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
2. ์คํํฐ ํจํค์ง๋ฅผ ํตํด ์์กด์ฑ ๊ด๋ฆฌ๊ฐ ์ฉ์ดํฉ๋๋ค.
3. ๋ด์ฅ ์๋ฒ๋ฅผ ์ ๊ณตํ์ฌ ๋ณ๋์ WAS ์ค์ ์์ด ๋ฐ๋ก ์คํ ๊ฐ๋ฅํฉ๋๋ค.
4. ์ต์ ๋ฒ์ ์ผ๋ก ๋ณด์ ํจ์น์ ์ฑ๋ฅ ๊ฐ์ ์ด ๋ฐ์๋์ด ์์ต๋๋ค.
2๏ธโฃ PostgreSQL
1. ๋ฌด๋ฃ๋ก ์ ๊ณต๋๋ ์คํ์์ค RDBMS์
๋๋ค.
2. ์์ ์ฑ๊ณผ ํ์ฅ์ฑ์ด ๋ฐ์ด๋๋ฉฐ ๋์ฉ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ์ ์ ํฉํฉ๋๋ค.
3. JSON ํ์
์ง์ ๋ฑ ๋ค์ํ ๋ฐ์ดํฐ ํ์
์ ์ ๊ณตํฉ๋๋ค.
4. ACID ํน์ฑ์ ์๋ฒฝํ๊ฒ ์ง์ํ์ฌ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํฉ๋๋ค.
3๏ธโฃ JWT & Spring Security
1. Statelessํ ์ธ์ฆ ๋ฐฉ์์ผ๋ก ์๋ฒ ํ์ฅ์ฑ์ด ์ข์ต๋๋ค.
2. Spring Security์์ ์๋ฒฝํ ํตํฉ์ผ๋ก ๋ณด์ ๊ตฌํ์ด ์ฉ์ดํฉ๋๋ค.
3. ํ ํฐ ๊ธฐ๋ฐ ์ธ์ฆ์ผ๋ก ์ธ์
๊ด๋ฆฌ ๋ถ๋ด์ด ์์ต๋๋ค.
4. ์ญํ ๊ธฐ๋ฐ ์ ๊ทผ ์ ์ด(RBAC)๋ฅผ ์ฝ๊ฒ ๊ตฌํํ ์ ์์ต๋๋ค.
4๏ธโฃ Docker
1. ๊ฐ๋ฐ ํ๊ฒฝ๊ณผ ์ด์ ํ๊ฒฝ์ ์ผ๊ด์ฑ์ ์ ์งํ ์ ์์ต๋๋ค.
2. ๊ฒฉ๋ฆฌ๋ ํ๊ฒฝ์์ ํ
์คํธ๊ฐ ๊ฐ๋ฅํ์ฌ ์์คํ
์ํฅ์ ์ต์ํํฉ๋๋ค.
3. ์ด๋ฏธ์ง ๊ธฐ๋ฐ์ผ๋ก ๋น ๋ฅธ ๋ฐฐํฌ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
4. ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ
์ฒ๋ก์ ํ์ฅ์ด ์ฉ์ดํฉ๋๋ค.
5๏ธโฃ GitHub Actions
1. GitHub์ ์๋ฒฝํ๊ฒ ํตํฉ๋์ด ๋ณ๋์ CI/CD ๋๊ตฌ ์ค์ ์ด ๋ถํ์ํฉ๋๋ค.
2. YAML ํ์ผ๋ก ๊ฐ๋จํ๊ฒ ์ํฌํ๋ก์ฐ๋ฅผ ์ ์ํ ์ ์์ต๋๋ค.
3. ์๋ํ๋ ํ
์คํธ์ ๋ฐฐํฌ๋ก ๊ฐ๋ฐ ํจ์จ์ฑ์ ๋์ผ ์ ์์ต๋๋ค.
4. ๋ฌด๋ฃ ํฐ์ด์์๋ ์ถฉ๋ถํ ๋น๋ ์๊ฐ์ ์ ๊ณตํฉ๋๋ค.
6๏ธโฃ RestClient
1. RestTemplate์ ํ์ ๋ฒ์ ์ผ๋ก ๋ ๋์ ์ฑ๋ฅ๊ณผ ์ ์ง๋ณด์์ฑ์ ์ ๊ณตํฉ๋๋ค.
2. ๋๊ธฐ ๋ฐฉ์์ผ๋ก ๊ตฌํ์ด ๊ฐ๋จํ๊ณ ํ์ต ๊ณก์ ์ด ๋ฎ์ต๋๋ค.
3. ์์ธ ์ฒ๋ฆฌ๊ฐ ๋ช
ํํ๊ณ ์ง๊ด์ ์
๋๋ค.
4. ํ์ฌ ํ๋ก์ ํธ ๊ท๋ชจ์์๋ ๋น๋๊ธฐ๋ณด๋ค ๋๊ธฐ ๋ฐฉ์์ด ๋ ์ ํฉํฉ๋๋ค.
7๏ธโฃ Google Gemini API
1. ๋ฉ๋ด ์ค๋ช
์๋ ์์ฑ์ผ๋ก ์ฌ์ฅ๋์ ์
๋ฌด ๋ถ๋ด์ ์ค์ผ ์ ์์ต๋๋ค.
2. ์์ฐ์ค๋ฌ์ด ํ๊ตญ์ด ์์ฑ์ด ๊ฐ๋ฅํฉ๋๋ค.
3. API ํธ์ถ์ด ๊ฐ๋จํ์ฌ ๋น ๋ฅด๊ฒ ํตํฉํ ์ ์์ต๋๋ค.
4. ๋ฌด๋ฃ ํฐ์ด๋ก ํ๋ก์ ํธ ํ
์คํธ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
8๏ธโฃ JUnit5 & Mockito
1. ๋จ์ ํ
์คํธ ์์ฑ์ผ๋ก ์ฝ๋ ํ์ง์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
2. Mock ๊ฐ์ฒด๋ฅผ ํตํด ์์กด์ฑ์ ๊ฒฉ๋ฆฌํ์ฌ ํ
์คํธํ ์ ์์ต๋๋ค.
3. ํ
์คํธ ์๋ํ๋ก ๋ฆฌํฉํ ๋ง ์ ์์ ์ฑ์ ํ๋ณดํ ์ ์์ต๋๋ค.
4. Spring Boot์์ ํตํฉ์ด ์ฐ์ํฉ๋๋ค.
๊ณง๊ฐ ์ํคํ
์ฒ๋ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌ์ฑ๋ฉ๋๋ค:
- GitHub Actions๋ฅผ ํตํ ์๋ ๋น๋ ๋ฐ ํ
์คํธ
- Docker ์ปจํ
์ด๋ํ๋ก ์ผ๊ด๋ ์คํ ํ๊ฒฝ ์ ๊ณต
- AWS EC2์ ์๋ ๋ฐฐํฌ
- PostgreSQL RDS๋ก ๋ฐ์ดํฐ ๊ด๋ฆฌ
- EC2 ์ธ๋ฐ์ด๋ ๊ท์น์ ํตํ ์ ๊ทผ ์ ์ด
์์ธ ํ ์ด๋ธ ๊ตฌ์กฐ
- ์ ์ (Users)
- ์ฃผ์ (Address)
- ์ง์ญ (Region)
- ์ฐ (Favorite)
- ์๋น (Restaurant)
- ์๋น ๋ถ๋ฅ ์นดํ ๊ณ ๋ฆฌ (Category)
- ๋ฉ๋ด (Menu)
- ์์ (Food)
- ์ถ๊ฐ ์ต์ (FoodOption)
- ๋ฆฌ๋ทฐ (Review)
- ์ฅ๋ฐ๊ตฌ๋ (Cart)
- ์ฅ๋ฐ๊ตฌ๋ ๋ณ ์์ ์ ๋ณด (CartFood)
- ์ฅ๋ฐ๊ตฌ๋ ๋ด ์์ ๋ณ ์ต์ ์ ๋ณด (CartFoodOption)
- ์ฃผ๋ฌธ ๋ด์ญ (Order)
- ์ฃผ๋ฌธ ๋ด์ญ ๋ณ ์์ ์ ๋ณด (OrderFood)
- ๊ฒฐ์ (Payment)
- AI ๋ก๊ทธ (AI)
โ
์ธ์ฆ/์ธ๊ฐ: JWT ๊ธฐ๋ฐ ๋ก๊ทธ์ธ/ํ์๊ฐ์
โ
์ฃผ์ ๊ด๋ฆฌ: ๋ฒ์ ๋ ์ฃผ์ ๋ฐ์ดํฐ ์ฐ๋, ์ฌ์ฉ์ ์ฃผ์ ๊ด๋ฆฌ
โ
์๋น/๋ฉ๋ด: ์กฐํ, ๊ฒ์, ํ์ด์ง, ์ฌ์ฅ๋ ์ ์ฉ ๊ด๋ฆฌ
โ
์ฅ๋ฐ๊ตฌ๋: ๋ด๊ธฐ/์์ /์ญ์ ๋ฐ ํฉ๊ณ ๊ณ์ฐ
โ
์ฃผ๋ฌธ/๊ฒฐ์ : ์ฃผ๋ฌธ ์์ฑ/์ํ ๊ด๋ฆฌ, ๊ฒฐ์ ๋ชจ๋ ์ฐ๋
โ
๋ฆฌ๋ทฐ/ํ๋ก์ฐ: ๊ฐ๊ฒ ๋ฆฌ๋ทฐ ์์ฑ/์กฐํ, ํ๋ก์ฐ ๊ธฐ๋ฐ ํผ๋
โ
AI: Google Gemini API๋ฅผ ํ์ฉํ ๋ฉ๋ด ์ค๋ช
์์ฑ
๐จโ๐ฉโ๐ง ์ ์ : ๋ก๊ทธ์ธ | ํ์๊ฐ์
| JWT ์ธ์ฆ | ๊ถํ ๊ด๋ฆฌ
๐ช ์๋น: ๊ฒ์ | ์กฐํ | ์นดํ
๊ณ ๋ฆฌ๋ณ ํํฐ๋ง | ํ์ด์ง | ์ฌ์ฅ๋ ์ ์ฉ ๊ด๋ฆฌ
๐ฑ ๋ฉ๋ด: ์์ ์กฐํ | ์ต์
์ ํ | AI ์ค๋ช
์์ฑ
๐ ์ฅ๋ฐ๊ตฌ๋: ๋ด๊ธฐ | ์์ | ์ญ์
๐ฆ ์ฃผ๋ฌธ: ์ฃผ๋ฌธ ์์ฑ | ์ํ ๊ด๋ฆฌ | ์ฃผ๋ฌธ ๋ด์ญ ์กฐํ
๐ณ ๊ฒฐ์ : ๊ฒฐ์ ์ฒ๋ฆฌ | ๊ฒฐ์ ๋ด์ญ ๊ด๋ฆฌ
โญ ๋ฆฌ๋ทฐ: ๋ฆฌ๋ทฐ ์์ฑ | ์กฐํ | ํ์ ๊ด๋ฆฌ
โค๏ธ ํ๋ก์ฐ: ์๋น ํ๋ก์ฐ | ํผ๋ ์กฐํ
๐ ์ฃผ์: ์ฃผ์ ๋ฑ๋ก | ๊ด๋ฆฌ | ๋ฒ์ ๋ ์ฃผ์ ์ฐ๋
1๏ธโฃ JWT ์ธ์ฆ/์ธ๊ฐ
- Spring Security์ JWT๋ฅผ ํ์ฉํ Stateless ์ธ์ฆ
- Customer์ Owner ์ญํ ๊ตฌ๋ถ
- ํ ํฐ ๊ธฐ๋ฐ ์ธ์ฆ์ผ๋ก ํ์ฅ์ฑ ํ๋ณด
- @PreAuthorize๋ฅผ ํตํ ์ธ๋ฐํ ๊ถํ ์ ์ด
2๏ธโฃ ์๋น ๊ด๋ฆฌ
- ์นดํ ๊ณ ๋ฆฌ๋ณ ์๋น ์กฐํ
- ๊ฒ์ ๋ฐ ํ์ด์ง ๊ธฐ๋ฅ
- ์ฌ์ฅ๋ ์ ์ฉ ์๋น ๋ฑ๋ก/์์ /์ญ์
- ์๋น ์ํ ๊ด๋ฆฌ (์คํ/๋ง๊ฐ)
3๏ธโฃ ์ฅ๋ฐ๊ตฌ๋ & ์ฃผ๋ฌธ
- ์ฅ๋ฐ๊ตฌ๋์ ์์ ๋ฐ ์ต์ ์ถ๊ฐ
- ์ฅ๋ฐ๊ตฌ๋ ์์ /์ญ์ ๊ธฐ๋ฅ
- ์ฃผ๋ฌธ ์์ฑ ๋ฐ ์ํ ๊ด๋ฆฌ
- ์ฃผ๋ฌธ ๋ด์ญ ์กฐํ ๋ฐ ์์ธ ์ ๋ณด ํ์ธ
4๏ธโฃ AI ๋ฉ๋ด ์ค๋ช
- Google Gemini API ์ฐ๋
- ๋ฉ๋ด๋ช ๊ธฐ๋ฐ ์๋ ์ค๋ช ์์ฑ
- ์ฌ์ฅ๋์ ์ ๋ฌด ํจ์จํ
- AI ํธ์ถ ๋ก๊ทธ ์ ์ฅ
5๏ธโฃ ๋ฆฌ๋ทฐ ์์คํ
- ๋ฐฐ๋ฌ ์๋ฃ๋ ์ฃผ๋ฌธ์ ๋ํ ๋ฆฌ๋ทฐ ์์ฑ
- ๋ฆฌ๋ทฐ ์์ /์ญ์ (Soft Delete)
- ์ฃผ๋ฌธ๋ณ ๋ฆฌ๋ทฐ ๊ด๋ฆฌ
- ๋ฆฌ๋ทฐ ์กฐํ ๊ธฐ๋ฅ
6๏ธโฃ ์ฃผ์ ๊ด๋ฆฌ
- ๋ฒ์ ๋ ์ฃผ์ ๋ฐ์ดํฐ CSV ๋ก๋ฉ
- ์๋/์๊ตฐ๊ตฌ/๋ฒ์ ๋ ๊ณ์ธต ๊ตฌ์กฐ
- ์ฌ์ฉ์๋ณ ์ฃผ์ ๋ฑ๋ก/๊ด๋ฆฌ
- ๊ธฐ๋ณธ ๋ฐฐ์ก์ง ์ค์
7๏ธโฃ ํ๋ก์ฐ
- ์๋น ํ๋ก์ฐ/์ธํ๋ก์ฐ
- ํ๋ก์ฐํ ์๋น ๋ชฉ๋ก ์กฐํ
- ํ๋ก์ฐ ์ํ ํ์ธ
GitHub Actions
```yaml
- ์ฝ๋ ์ฒดํฌ์์
- Gradle ๋น๋ ๋ฐ ํ
์คํธ
- Docker ์ด๋ฏธ์ง ๋น๋
- EC2๋ก ์ด๋ฏธ์ง ์ ์ก
- ์ปจํ
์ด๋ ์คํ
```
โ ํ ์คํธ ํต๊ณผ ํ ์๋ ๋ฐฐํฌ
โ Docker๋ฅผ ํตํ ์ผ๊ด๋ ์คํ ํ๊ฒฝ
โ EC2์์ ์์ ์ ์ธ ์๋น์ค ์ ๊ณต
Docker
```dockerfile
FROM openjdk:17-jdk-slim
COPY build/libs/*.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
```
โ ๊ฐ๋ฐ/์ด์ ํ๊ฒฝ ๋์ผํ
โ ๋น ๋ฅธ ๋ฐฐํฌ์ ๋กค๋ฐฑ
1๏ธโฃ PostgreSQL ์ค์น ์ค๋ฅ ํด๊ฒฐ
๋ฌธ์
- PostgreSQL์ ๋ก์ปฌ์ ์ค์นํ๋ ๊ณผ์ ์์ ์๋ฌ ์ฝ๋ 1 ๋ฐ์
- ์ค์น ๊ฒฝ๋ก์ ํ๊ธ์ด ํฌํจ๋์ด ์ค์น ์คํจ
์์ธ
- ํ๊ธ ๊ฒฝ๋ก๋ก ์ธํ ์ค์น ์ค๋ฅ
ํด๊ฒฐ ๋ฐฉ์
- DBeaver๋ฅผ ์ฌ์ฉํ์ฌ ์๊ฒฉ RDS์ ์ง์ ์ ๊ทผ
- ๋ก์ปฌ ์ค์น ์์ด ๊ฐ๋ฐ ํ๊ฒฝ ๊ตฌ์ฑ
๊ฒฐ๊ณผ
- โ ํ์ ๋ชจ๋ ๋์ผํ DB ํ๊ฒฝ์์ ์์ ๊ฐ๋ฅ
- โ ์ด๊ธฐ ํ๊ฒฝ ๊ตฌ์ถ ์๊ฐ ๋จ์ถ
- โ ๊ฒฝ๋ก ์ค๋ฅ ๊ทผ๋ณธ์ ํด๊ฒฐ
2๏ธโฃ Spring Security ๊ถํ ๊ฑฐ๋ถ ์๋ต ๊ฐ์
๋ฌธ์
@PreAuthorize๋ก ๊ถํ ์ ์ด ์ 403 ์๋ฌ๋ง ๋ฐํ- Swagger์์ ์๋ฌ ์์ธ ์ ๋ณด ํ์ธ ๋ถ๊ฐ
์์ธ
- ๊ธฐ๋ณธ
AccessDeniedHandler๊ฐ HTML ๊ธฐ๋ฐ ์๋ฌ ํ์ด์ง ๋ฐํ - API ํด๋ผ์ด์ธํธ์์๋ ๋จ์ 403๋ง ํ์๋จ
ํด๊ฒฐ ๋ฐฉ์
- ์ปค์คํ ์์ธ ์ฒ๋ฆฌ ํธ๋ค๋ฌ ๊ตฌํ
- JSON ํํ์ ์์ธ ์๋ฌ ์๋ต ๋ฐํ
๊ฒฐ๊ณผ
{
"status": 403,
"error": "Forbidden",
"message": "์ ๊ทผ ๊ถํ์ด ์์ต๋๋ค.",
"path": "/api/v1/user"
}- โ ๋ช ํํ ์๋ฌ ๋ฉ์์ง ์ ๊ณต
- โ ๋๋ฒ๊น ํจ์จ ํฅ์
- โ API ์๋ต ์ผ๊ด์ฑ ํ๋ณด
3๏ธโฃ ์ฃผ๋ฌธ ์์ฑ ์ ๋ค์ค ์ค๋ฅ ํด๊ฒฐ
๋ฌธ์
- POST
/api/ordersํธ์ถ ์ ์์ฐจ์ ์ค๋ฅ ๋ฐ์HttpMediaTypeNotAcceptableExceptionHttpMessageNotReadableException- SQL NOT NULL ์ ์ฝ ์กฐ๊ฑด ์๋ฐ
์์ธ
- DTO์ getter ์์ด JSON ๋ณํ ๋ถ๊ฐ
@RequestBody Stringํ์ ๋ถ์ผ์น- ํด๋์ค ๋ ๋ฒจ
@Transactional(readOnly = true)๋ก INSERT ๋ฌด์ - ์ํฐํฐ์ DB ์คํค๋ง ๋ถ์ผ์น
ํด๊ฒฐ ๋ฐฉ์
- DTO๋ฅผ
record๋ก ๋ณ๊ฒฝํ์ฌ ์๋ getter ์์ฑ - ์์ฒญ DTO ํ์ ์ ์ ์ ํ ๊ฐ์ฒด๋ก ๋ณ๊ฒฝ
- ์ฐ๊ธฐ ๋ฉ์๋์
@Transactional์ค๋ฒ๋ผ์ด๋ - DB ์คํค๋ง์ ์ํฐํฐ ๋๊ธฐํ
๊ฒฐ๊ณผ
- โ JSON ์ง๋ ฌํ/์ญ์ง๋ ฌํ ์ ์ ์๋
- โ ํธ๋์ญ์ ์ ์ ์ปค๋ฐ
- โ ๋ถํ์ํ ์ปฌ๋ผ ์ ๊ฑฐ
- โ ์์ ์ ์ธ ์ฃผ๋ฌธ ์์ฑ ๊ธฐ๋ฅ
4๏ธโฃ ํ์๊ฐ์ ์ ์ธ์ฆ ์ ๋ณด ์ค๋ฅ
๋ฌธ์
- ํ์๊ฐ์
์
UserDetailsImpl์บ์คํ ์ค๋ฅ ๋ฐ์ - SecurityContextHolder๊ฐ ์ธ์ฆ์ ๋ณด๋ฅผ ์ฐพ์ง ๋ชปํจ
์์ธ
- ํ์๊ฐ์ ์ ์ธ์ฆ ์์ด ์ ๊ทผ ๊ฐ๋ฅํ API
- principal์ด "anonymous" ๋ฌธ์์ด์ด๋ผ ์บ์คํ ๋ถ๊ฐ
ํด๊ฒฐ ๋ฐฉ์
if(principal instanceof UserDetailsImpl){
return((UserDetailsImpl)principal).
getUsername();
}
return"SYSTEM";๊ฒฐ๊ณผ
- โ ๋ฏธ์ธ์ฆ ์ฌ์ฉ์ ์์ ์ "SYSTEM" ๊ธฐ๋ก
- โ ์ธ์ฆ๋ ์ฌ์ฉ์๋ ๋๋ค์ ๊ธฐ๋ก
- โ created_by, updated_by ์ถ์ ๊ฐ๋ฅ
5๏ธโฃ Soft Delete ๋ฐ์ดํฐ ์กฐํ ๋ฌธ์
๋ฌธ์
- Cart ์กฐํ ์ ์ญ์ ๋ CartFood์ CartFoodOption๊น์ง ์กฐํ๋จ
- Soft Deleteํ ๋ฐ์ดํฐ๊ฐ ํจ๊ป ๋ฐํ๋จ
์์ธ
- ์ฐ๊ด ์ํฐํฐ์ ์กฐํ ์กฐ๊ฑด์ด ์ ์ฉ๋์ง ์์
is_deleted = true์ธ ๋ฐ์ดํฐ๊น์ง ์ ๋ถ ์กฐํ
ํด๊ฒฐ ๋ฐฉ์
@OneToMany(mappedBy = "cart")
@SQLRestriction("is_deleted = false")
private List<CartFood> cartFoods;๊ฒฐ๊ณผ
- โ ์ญ์ ๋์ง ์์ ๋ฐ์ดํฐ๋ง ์กฐํ
- โ ๋ฐ์ดํฐ ์ ํฉ์ฑ ์ ์ง
- โ ๋ถํ์ํ ํํฐ๋ง ๋ก์ง ์ ๊ฑฐ
6๏ธโฃ ์ฅ๋ฐ๊ตฌ๋ ์์ ์ถ๊ฐ ์ ID ๋ฏธ์์ฑ ์ค๋ฅ
๋ฌธ์
- ์ ์ฅ๋ฐ๊ตฌ๋ ์์ฑ ํ ์์ ์ถ๊ฐ ์ ์ค๋ฅ ๋ฐ์
- ์ธ๋ํค ์ฐธ์กฐ ์คํจ
์์ธ
Cart.create()๋ก ์์ฑํ ์ํฐํฐ๋ฅผ ์ ์ฅํ์ง ์๊ณ ์ฌ์ฉ- ID๊ฐ ์์ฑ๋์ง ์์ ์ํ์์ ์ฐธ์กฐ ์๋
ํด๊ฒฐ ๋ฐฉ์
Cart newCart = Cart.create(user, restaurant);
cartRepository.
save(newCart); // ์ ์ฅ ํ ์ฌ์ฉ๊ฒฐ๊ณผ
- โ ์์ ํ ๋ฐ์ดํฐ ์ ์ฅ ๋ฐ ์กฐํ
- โ ์ธ๋ํค ์ฐธ์กฐ ์ ์ ์๋
- โ ์ฅ๋ฐ๊ตฌ๋ ๊ธฐ๋ฅ ์์ ํ
7๏ธโฃ ์๋น ์ ๋ณด ์ ๊ทผ ๊ถํ ๋ฌธ์
๋ฌธ์
- ์๋น ๋ฑ๋ก/์์ /์ญ์ ์ ๋ณธ์ธ ํ์ธ ์์ด ์ ๊ทผ ๊ฐ๋ฅ
- ๋ค๋ฅธ ์ฌ์ฅ๋์ ์๋น ์ ๋ณด ์์ ๊ฐ๋ฅ
์์ธ
- ๋ณธ์ธ ID ์ฒดํฌ ๋ก์ง ๋ถ์ฌ
- ๊ถํ๋ง ํ์ธํ๊ณ ์์ ๊ถ์ ๋ฏธํ์ธ
ํด๊ฒฐ ๋ฐฉ์
if(!restaurant.getOwnerId().
equals(user.getId())){
throw new
UnauthorizedException("๋ณธ์ธ์ ์๋น๋ง ์์ ๊ฐ๋ฅํฉ๋๋ค");
}๊ฒฐ๊ณผ
- โ ๋ณธ์ธ ์๋น๋ง ๊ด๋ฆฌ ๊ฐ๋ฅ
- โ ๊ถํ๊ณผ ์์ ๊ถ ์ด์ค ๊ฒ์ฆ
- โ ๋ฐ์ดํฐ ๋ณด์ ๊ฐํ
8๏ธโฃ ๋ฆฌ๋ทฐ ์ฌ์์ฑ ์ Unique ์ ์ฝ ์กฐ๊ฑด ์๋ฐ
๋ฌธ์
- ๋ฆฌ๋ทฐ ์์ฑ โ ์ญ์ โ ์ฌ์์ฑ ์ ์ค๋ฅ ๋ฐ์
- Soft Delete๋ก ์ธํด ์ค์ ๋ฐ์ดํฐ๋ ๋จ์์์ด Unique ์ ์ฝ ์๋ฐ
์์ธ
- ์ฃผ๋ฌธ๊ณผ ๋ฆฌ๋ทฐ๊ฐ 1:1 ๊ด๊ณ
- ์ธ๋ํค์ Unique ์ ์ฝ ์กฐ๊ฑด ์กด์ฌ
ํด๊ฒฐ ๋ฐฉ์
- ์ฃผ๋ฌธ๊ณผ ๋ฆฌ๋ทฐ ๊ด๊ณ๋ฅผ 1:N์ผ๋ก ๋ณ๊ฒฝ
- ๋ฆฌ๋ทฐ ์์ฑ ์ ํ์ฑ ์ํ ํ์ธ ๋ก์ง ์ถ๊ฐ
if(reviewRepository.existsByOrderIdAndStatusTrue(orderId))






