์ฝ๋ค ๋ฎ์ด ๋ ์ข ์ด์ฑ ๋ค, ์ด๋๊น์ง ์ฝ์๋์ง ๊ธฐ์ตํ์๋์?
- ์ฑ ์ ์ฝ๊ธฐ ์์ํ๋ฉด ์๊ฒฐ์ ์ ๋ชปํ๋ค. ๊ทธ๋ฌ๋ฉด์ ์ฝ๊ณ ์ถ์ ์ฑ ์ ๋ง๋ค. ์ฑ ๊ฐํผ๋ง ๋์ด๋๋ ์ค..
- ์ด๋ฐ ์์ผ๋ก ๋ ์๋ฅผ ํ๋ค๋ณด๋ ์ด์ฉ ๋ ๋ด๊ฐ ์ด๋ค ์ฑ ์ ์ฝ์๋์ง, ๋ ์ฝ์๋์ง ํ์ ํ๊ธฐ ์ด๋ ต๋ค.
- ์ฌ์ง์ด ์ฑ ์ ๋ฆฌํ๋ฉด์ ์ค๊ฐ์ ์ฑ ๊ฐํผ ๊ฝํ๊ฑฐ๋ณด๊ณ ์ ์ ์ด ์ฑ ์ ์ฝ๋ค ๋ง์๊ตฌ๋ ์ถ์๋ ์ ๋ ์๋ค.
- ํ์ฌ ๋ด๊ฐ ์ด๋ค ์ฑ ๋ค์ ์ด๋์ ๋ ์ฝ์๋์ง ํ ๋์ ํ์ ํ ์ ์๋ค๋ฉด?
- eBook ์ ํ๋ฆฌ์ผ์ด์ ์ eBook๋ง ์ง๋์จ ํธ๋ํนํ ์ ์๋ค โ ๊ทธ๋ผ ์ข ์ด์ฑ ์ ๋์์ผ๋ก ์ง๋์จ์ ์ถ์ ํด๋ณด์!
๋ณธ ํ๋ก์ ํธ๋ reading-tracker ๋ฐฑ์๋ API ์๋ฒ์ ๋๋ค.
- ๋ค์ด๋ฒ ๊ณ์ ๊ฐํธ ๋ก๊ทธ์ธ
- ๋ค์ด๋ฒ ๋์ ๊ฒ์ ๊ธฐ๋ฐ ์ฑ ์ถ๊ฐ
- ํ์ฌ ํ์ด์ง ์ ๋ ฅ ์ ์๋ ์ง๋์จ ๊ณ์ฐ ๋ฐ ์ํ ๋ณ๊ฒฝ
- ์ฝ๋์ค/์๋ฃ/๋ณด๊ด ์ค์ธ ๋์ ๊ฐ์ ์์ฝ
- Redis ๊ธฐ๋ฐ ๋ถ์ฐ๋ฝ์ผ๋ก ๋์ ์ค๋ณต ๋ฑ๋ก ๋ฐฉ์ง
- OAuth2 ๊ธฐ๋ฐ ๋ก๊ทธ์ธ + ์์ฒด JWT Cookie ๋ฐ๊ธ
- Redis ์ฅ์ ์ DB fallback ์ฒ๋ฆฌ
- JWT HttpOnlyยทSecure ์ฟ ํค ๊ธฐ๋ฐ ์ธ์ฆ
- ์บ์ ๊ธฐ๋ฐ ์ฑ๋ฅ ์ต์ ํ
graph TB
Client[Web Client<br/>JWT Cookie]
subgraph App[Spring Boot Application]
Security[Security Layer]
API[API Layer]
Business[Business Layer]
Data[Data Layer]
end
subgraph External
NaverOAuth[Naver OAuth]
NaverAPI[Naver Book API]
Redis[(Redis / Redisson)]
MySQL[(MySQL)]
end
Client --> Security --> API --> Business --> Data
Security <-->|OAuth ์ฐ๋| NaverOAuth
Business --> NaverAPI
Business --> Redis
Data --> MySQL
style App fill: #4c6ef5, color: #fff, stroke: #364fc7, stroke-width: 3px
style Security fill: #7950f2, color: #fff
style API fill: #5c7cfa, color: #fff
style Business fill: #f59f00, color: #fff
style Data fill: #12b886, color: #fff
style External fill: #495057, color: #fff
style Redis fill: #ff6b6b, color: #fff
style MySQL fill: #4dabf7, color: #fff
style NaverAPI fill: #51cf66, color: #fff
style NaverOAuth fill: #9775fa, color: #fff
- Java 21, Spring Boot 3(Web, Security, OAuth2, JPA, Cache), RestClient
- MySQL(RDS), Redis(ElastiCache), Redisson
- Gradle, Docker, GitHub Actions, AWS ECR ยท EC2 ยท SSM ยท ALB
๋จ์ ๊ฒ์ฆ์ MockMvcยทDataJpaTest๋ก, ํต์ฌ ์๋๋ฆฌ์ค SpringBootTest + Testcontainers๋ก ํตํฉ ๊ฒ์ฆํฉ๋๋ค.
- MockMvc ๊ธฐ๋ฐ Controller ํ ์คํธ
- @DataJpaTest ๊ธฐ๋ฐ Repository/JPA ๋งคํ ๊ฒ์ฆ
- Service ๋จ์ ๋น์ฆ๋์ค ๋ก์ง ํ ์คํธ
- Testcontainers Redis๋ก OAuth ๋ก๊ทธ์ธ ํ๋ฆ ๊ฒ์ฆ
- ๋์ ๋ฑ๋ก 30๊ฐ ๋์์ฑ ํ๊ฒฝ์์ ๋ถ์ฐ๋ฝ ์ฒ๋ฆฌ ๊ฒ์ฆ
GET /api/books?state=: ์ํ ๊ธฐ๋ฐ ๋์ ๋ชฉ๋ก ๋ฐ ์ํ๋ณ ํต๊ณ ๋ฐํ
Request
GET /api/books?state=IN_PROGRESS
Cookie: rt_token=eyJh...
Response
{
"summary": {
"inProgress": 2,
"completed": 5,
"archived": 1
},
"books": [
{
"id": 1,
"title": "๋ฆฌํฉํ ๋ง 2ํ",
"author": "๋งํด ํ์ธ๋ฌ",
"publisher": "ํ๋น๋ฏธ๋์ด",
"currentPage": 120,
"totalPages": 450,
"progress": 26,
"state": "IN_PROGRESS"
}
]
}GET /api/books/search: ๋ค์ด๋ฒ ๋์ API ๊ธฐ๋ฐ ๋์ ๊ฒ์
Request
GET /api/books/search?query=ํด๋ฆฐ%20์ฝ๋
Cookie: rt_token=eyJh...
Response
{
"total": 1,
"display": 1,
"items": [
{
"isbn": "9788970503489",
"title": "ํด๋ฆฐ ์ฝ๋",
"author": "๋ก๋ฒํธ C. ๋งํด",
"publisher": "์ธ์ฌ์ดํธ",
"link": "https://book.naver.com/bookdb/book_detail.nhn?bid=12345"
}
]
}POST /api/books: ๊ฒ์ํ ๋์๋ฅผ ์ฌ์ฉ์ ์์ฌ์ ์ถ๊ฐ
Request
{
"isbn": "9788966263158",
"title": "ํด๋ฆฐ ์ํคํ
์ฒ",
"author": "๋ก๋ฒํธ C. ๋งํด",
"publisher": "์ธ์ฌ์ดํธ",
"totalPages": 400
}Response
{
"id": 42,
"title": "ํด๋ฆฐ ์ํคํ
์ฒ",
"author": "๋ก๋ฒํธ C. ๋งํด",
"publisher": "์ธ์ฌ์ดํธ",
"state": "IN_PROGRESS",
"currentPage": 1,
"totalPages": 400
}export NAVER_CLIENT_ID=
export NAVER_CLIENT_SECRET=
export JWT_SECRET_KEY=
./gradlew bootRun --args='--spring.profiles.active=dev'- ๊ฐํธ ๋ก๊ทธ์ธ ํ์ฅ: ๊ตฌ๊ธ, ์นด์นด์ค
- ๋์ ๊ฒ์ ํ์ด์ง๋ค์ด์
- ๋ชฉํ ๋ฆฌ๋ง์ธ๋/ํธ์ ์๋ฆผ