νλ‘μ νΈλͺ : KRX λ°°μΉ λ§μ€ν° (next-krx-lds-bat-mst)
μμ± κΈ°μ€μΌ: 2026-04-01
λμ λ μ: μ κ· κ°λ°μ / μ΄μ λ΄λΉμ
- νλ‘μ νΈ κ°μ
- κΈ°μ μ€ν
- μ 체 μμ€ν μν€ν μ²
- λ μ΄μ΄ μν€ν μ²
- Spring Security μΈμ¦/μΈκ° ꡬ쑰
- Redisλ₯Ό νμ©ν μΈμ κ΄λ¦¬
- λ°°μΉ λ§μ€ν°(Master-Agent) λμ ꡬ쑰
- μ£Όμ νλ©΄ λ° κΈ°λ₯ μ€λͺ
- νκ²½λ³ κ΅¬μ±
- μ΄μ κ΄λ¦¬ 체ν¬λ¦¬μ€νΈ
λ°°μΉ λ§μ€ν° μμ€ν μ κΈμ΅ μ 무μμ μ¬μ©λλ λ°°μΉ(μΌκ΄μ²λ¦¬) μμ λ€μ μ€μμμ κ΄λ¦¬νλ νλ«νΌμ λλ€.
μ½κ² λ§νλ©΄: "μΈμ , μ΄λ€ λ°°μΉ μμ
μ, μ΄λ»κ² μ€νν μ§" λ₯Ό κ΄λ¦¬νλ κ΄μ μμ€ν
| μν | μ€λͺ |
|---|---|
| Job κ΄λ¦¬ | λ°°μΉ μμ λ±λ‘/μμ /μμ /μ‘°ν |
| μ€μΌμ€ κ΄λ¦¬ | μμ μ μΈμ μ€νν μ§ μΌμ κ΄λ¦¬ (μΊλ¦°λ/Cron λ°©μ) |
| μ€ν κ²°κ³Ό μ‘°ν | κ° μμ μ μ€ν μ΄λ ₯ λ° μ±κ³΅/μ€ν¨ κ²°κ³Ό νμΈ |
| μ€μκ° μλ¦Ό | μμ μλ£/μ€λ₯ λ°μ μ μ€μκ° νλ©΄ νΈμ |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β KRX μ 체 μμ€ν
β
β β
β ββββββββββββββββββββ ββββββββββββββββββββββββββββββββ β
β β λ°°μΉ λ§μ€ν° β Kafka β μ€μ λ°°μΉ μμ
μ²λ¦¬ μμ€ν
β β
β β (μ΄ μμ€ν
) βββββββββΆβ (Worker μλ²λ€) β β
β β β β β β
β β Β· Job λ±λ‘ β β Β· μ€μ λ°μ΄ν° μ²λ¦¬ β β
β β Β· μ€μΌμ€ μ€μ β β Β· νμΌ μ²λ¦¬ β β
β β Β· κ²°κ³Ό μ‘°ν β β Β· DB λ°°μΉ μ²λ¦¬ β β
β ββββββββββββββββββββ ββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| λΆλ₯ | κΈ°μ | λ²μ | μ©λ |
|---|---|---|---|
| νλ μμν¬ | Spring Boot | 3.5.11 | μ 체 μ ν리μΌμ΄μ κΈ°λ° |
| μΈμ΄ | Java | 21 | λ©μΈ κ°λ° μΈμ΄ |
| λΉλ | Gradle | 9.3.0 | λΉλ/μμ‘΄μ± κ΄λ¦¬ |
| 보μ | Spring Security | 3.5.11 | μΈμ¦/μΈκ° μ²λ¦¬ |
| μΈμ¦ ν ν° | JWT (JJWT) | 0.12.6 | μ¬μ©μ μΈμ¦ ν ν° |
| λ°μ΄ν° μ κ·Ό | MyBatis | 3.0.3 | DB 쿼리 μ²λ¦¬ |
| λ°μ΄ν°λ² μ΄μ€ | Oracle (AWS RDS) | 23.3.0 | λ©μΈ λ°μ΄ν° μ μ₯μ |
| μΈμ μ μ₯μ | Redis + Spring Session | 3.5.11 | λΆμ° μΈμ κ΄λ¦¬ |
| μ€μΌμ€λ¬ | Quartz | 3.5.11 | λ°°μΉ μμ μΌμ κ΄λ¦¬ |
| λ°°μΉ | Spring Batch | 3.5.11 | λ°°μΉ μμ μ€ν κ΄λ¦¬ |
| λ©μμ§ | Apache Kafka | - | λΉλκΈ° μμ λ©μμ§ μ λ¬ |
| λΆμ° λ½ | ShedLock | 4.39.0 | λ€μ€ μλ² μ€λ³΅ μ€ν λ°©μ§ |
| μΊμ | Caffeine | - | λ©λͺ¨λ¦¬ μΊμ |
| νλ©΄ ν νλ¦Ώ | Thymeleaf | - | μλ²μ¬μ΄λ HTML λ λλ§ |
| API λ¬Έμ | Swagger (SpringDoc) | 2.8.13 | API λͺ μΈ μλ μμ± |
| XSS λ°©μ΄ | Lucy XSS Filter | 2.0.1 | μΉ λ³΄μ (XSS 곡격 μ°¨λ¨) |
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β νλ μ ν
μ΄μ
κ³μΈ΅ β
β Thymeleaf (HTML/CSS/JS) β REST API (JSON) β Swagger UI β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ-β
β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 보μ κ³μΈ΅ β
β Spring Security β JWT β Redis Session β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β λΉμ¦λμ€ λ‘μ§ κ³μΈ΅ β
β Spring MVC (Controller/Service) β AOP (κΆν체ν¬/μ€νμκ°) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β λ°μ΄ν° μ κ·Ό κ³μΈ΅ β
β MyBatis (Mapper + XML) β HikariCP β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β μΈνλΌ κ³μΈ΅ β
β Oracle DB β Redis β Kafka β Caffeine Cache β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββ
β μ¬μ©μ λΈλΌμ°μ β
ββββββββββ¬βββββββββ
β HTTP μμ²
βΌ
βββββββββββββββββββββββββββ
β Spring Boot WAS β
β (next-krx-lds-bat-mst) β
β β
β ββββββββββββββββββββββ β
β β Spring Security β ββββ λͺ¨λ μμ²μ 첫 λ²μ§Έ κ΄λ¬Έ
β β (보μ νν° μ²΄μΈ) β β
β ββββββββββ¬ββββββββββββ β
β β β
β ββββββββββΌββββββββββββ β
β β Controller β ββββ URL λΌμ°ν
β β (REST / Web UI) β β
β ββββββββββ¬ββββββββββββ β
β β β
β ββββββββββΌββββββββββββ β
β β Service β ββββ λΉμ¦λμ€ λ‘μ§
β ββββββββββ¬ββββββββββββ β
β β β
β ββββββββββΌββββββββββββ β
β β Mapper (MyBatis) β ββββ DB 쿼리
β ββββββββββ¬ββββββββββββ β
β β β
βββββββββββββΌββββββββββββββ
β
ββββββββββββββββββΌβββββββββββββββββββ
βΌ βΌ βΌ
ββββββββββββββββ βββββββββββββ ββββββββββββββββββββ
β Oracle DB β β Redis β β Kafka β
β (AWS RDS) β β (μΈμ
) β β (λ©μμ§ λΈλ‘컀) β
ββββββββββββββββ βββββββββββββ ββββββββββ¬ββββββββββ
β
ββββββββββΌββββββββββ
β Worker μλ²λ€ β
β (λ°°μΉ μ€ν) β
ββββββββββββββββββββ
μ¬μ©μ μμ²
β
ββ /api/** β [1μμ] ApiSecurityConfig β REST Controller β JSON μλ΅
ββ /common/api/** β [1μμ] ApiSecurityConfig β REST Controller β JSON μλ΅
β
ββ /common/auth/** β [2μμ] WebSecurityConfig β Web Controller β HTML μλ΅
ββ /job/** β [2μμ] WebSecurityConfig β Web Controller β HTML μλ΅
ββ /calendar/** β [2μμ] WebSecurityConfig β Web Controller β HTML μλ΅
ββ /result/** β [2μμ] WebSecurityConfig β Web Controller β HTML μλ΅
β
ββ /apidoc β μΈμ¦ μμ΄ μ κ·Ό (Swagger λ¬Έμ)
ββ /swagger-ui/** β μΈμ¦ μμ΄ μ κ·Ό (Swagger UI)
ββ /resources/** β μΈμ¦ μμ΄ μ κ·Ό (CSS, JS, μ΄λ―Έμ§)
ldsframework/
β
ββ common/ β μ μ¬ κ³΅ν΅ (보μ, μ€μ , μ νΈ)
β ββ config/security/ β Spring Security ν΅μ¬
β ββ config/jwt/ β JWT ν ν° κ΄λ¦¬
β ββ config/redis/ β Redis μΈμ
μ€μ
β ββ config/kafka/ β Kafka λ©μμ§ μ€μ
β ββ config/batch/ β μ€μΌμ€λ¬/λ°°μΉ μ€μ
β ββ aop/ β κΆν μ²΄ν¬ AOP
β ββ advice/ β μλ΅ λν, μμΈ μ²λ¦¬
β ββ utils/ β κ³΅ν΅ μ νΈ
β
ββ batmst/ β μ
무 λ‘μ§ (λ°°μΉ λ§μ€ν°)
ββ api/job/ β Job κ΄λ¦¬ API
ββ api/calendar/ β μΊλ¦°λ κ΄λ¦¬ API
ββ api/result/ β μ€ν κ²°κ³Ό API
ββ api/scheduler/ β Quartz μ€μΌμ€λ¬ API
ββ web/ β νλ©΄ λΌμ°ν
(UI Controller)
[HTTP μμ²]
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Controller κ³μΈ΅ β
β - @RestController : REST API μλ΅ (JSON) β
β - @Controller : μΉ νλ©΄ μλ΅ (HTML) β
β - URL λ§€ν μ²λ¦¬, μμ² νλΌλ―Έν° μμ β
β - λΉμ¦λμ€ λ‘μ§μ μκ³ Serviceμ μμλ§ ν¨ β
ββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ
β μμ
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Service κ³μΈ΅ β
β - μ€μ λΉμ¦λμ€ λ‘μ§ μ²λ¦¬ (μ€λ³΅ 체ν¬, μ ν¨μ± κ²μ¦ λ±) β
β - νΈλμμ
κ΄λ¦¬ (@Transactional) β
β - μ¬λ¬ Mapperλ₯Ό μ‘°ν©νμ¬ λ³΅μ‘ν λ‘μ§ μ²λ¦¬ β
ββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ
β DB μ‘°ν μμ
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Mapper κ³μΈ΅ (MyBatis) β
β - DBμμ μ§μ ν΅μ λ΄λΉ β
β - Java μΈν°νμ΄μ€ + XMLλ‘ μΏΌλ¦¬ λΆλ¦¬ β
β - λμ 쿼리(if, choose, foreach λ±)λ XMLμμ μ²λ¦¬ β
ββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββ
β Oracle DB β
βββββββββββββββββββ
λͺ¨λ REST API μλ΅μ CommonResponseDtoλ‘ μλ λνλ©λλ€.
{
"statusCode": "200",
"statusMsg": "μ±κ³΅",
"data": {
/* μ€μ λ°μ΄ν° */
}
}μ°Έκ³ :
@NoWrapμ΄λ Έν μ΄μ μ΄ λΆμ 컨νΈλ‘€λ¬/λ©μλλ λνμμ μ μΈλ©λλ€.
μ΄ μμ€ν μ λ κ°μ§ 보μ 체κ³λ₯Ό λμμ μ΄μν©λλ€.
βββββββββββββββββββββββββββββββββββββββββββββββ
β λͺ¨λ HTTP μμ² β
βββββββββββββββββββ¬ββββββββββββββββββββββββββββ
β
βββββββββββββββββββΌββββββββββββββββββββββββββββ
β URL ν¨ν΄μΌλ‘ 보μ μ²΄κ³ μ ν β
ββββββββββββ¬βββββββββββββββββββββ¬ββββββββββββββ
β β
/api/** β β κ·Έ μΈ URL
/common/api/** β β
βΌ βΌ
βββββββββββββββββββββββββ ββββββββββββββββββββββββββ
β ApiSecurityConfig β β WebSecurityConfig β
β [Order=1] β β [Order=2] β
β β β β
β Β· JWT ν ν° κΈ°λ° μΈμ¦ β β Β· μΈμ
κΈ°λ° μΈμ¦ β
β Β· STATELESS (무μν) β β Β· λμ λ‘κ·ΈμΈ μ ν(1) β
β Β· CSRF λΉνμ±ν β β Β· μΈμ
ID κ³ μ λ°©μ§ β
βββββββββββββββββββββββββ ββββββββββββββββββββββββββ
| νλͺ© | API 보μ (ApiSecurityConfig) | μΉ λ³΄μ (WebSecurityConfig) |
|---|---|---|
| μ μ© URL | /api/**, /common/api/** |
λλ¨Έμ§ λͺ¨λ URL |
| μΈμ¦ λ°©μ | JWT ν ν° (ν€λ) | μΈμ (μΏ ν€) |
| μν κ΄λ¦¬ | Stateless (μν μμ) | μΈμ μ μ§ |
| λμ λ‘κ·ΈμΈ | μ ν μμ | 1κ°λ§ νμ© |
| μ²λ¦¬ μμ | 1μμ | 2μμ |
[ν΄λΌμ΄μΈνΈ]
β
β POST /common/api/auth/login-processing
β Body: { "id": "user01", "password": "pass" }
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ApiJsonLoginAuthenticationFilter β
β μν : JSON Bodyμμ μμ΄λ/ν¨μ€μλλ₯Ό κΊΌλ΄μ μΈμ¦ μμ² μμ± β
ββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β authenticate()
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β AuthenticationManager (ProviderManager) β
β μν : μ΄λ€ Providerμκ² κ²μ¦μ λ§‘κΈΈμ§ κ²°μ β
ββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CustomUserDetailsService β
β μν : DBμμ ν΄λΉ μμ΄λμ μ¬μ©μ μ 보(ν¨μ€μλ, κΆν λ±) μ‘°ν β
ββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββ΄βββββββββββββββ
βΌ βΌ
[μΈμ¦ μ±κ³΅] [μΈμ¦ μ€ν¨]
β β
βΌ βΌ
ββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββ
β ApiJsonLogin β β ApiJsonLogin β
β AuthenticationSuccess β β AuthenticationFailure β
β Handler β β Handler β
β β β β
β Β· Access Token λ°κΈ β β Β· 401 μλ¬ μλ΅ β
β Β· Refresh Token λ°κΈ β β Β· μ€λ₯ λ©μμ§ JSON λ°ν β
β Β· JSONμΌλ‘ ν ν° μλ΅ β ββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββ
β
βΌ
[ν΄λΌμ΄μΈνΈμκ² JWT ν ν° λ°ν]
{
"accessToken": "eyJ...", β 1μκ° μ ν¨
"refreshToken": "eyJ..." β 24μκ° μ ν¨
}
[ν΄λΌμ΄μΈνΈ]
β
β GET /api/read/jobs
β Header: Authorization: Bearer eyJ...
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ApiJwtAuthenticationFilter (JWT κ²μ¦ νν°) β
β β
β 1λ¨κ³: ν€λμμ JWT ν ν° μΆμΆ β
β ββ ν ν° μμ β λ€μ νν°λ‘ ν΅κ³Ό (νμ μΈκ° λ¨κ³μμ μ°¨λ¨) β
β ββ ν ν° μμ β 2λ¨κ³λ‘ β
β β
β 2λ¨κ³: ν ν° μ ν¨μ± κ²μ¦ β
β ββ λ§λ£λ ν ν° β 401 μλ΅ (ν ν° λ§λ£ μλ΄) β
β ββ μμ‘°λ ν ν° β 401 μλ΅ (μλͺ»λ ν ν° μλ΄) β
β ββ μ ν¨ν ν ν° β SecurityContextHolderμ μΈμ¦μ 보 μ μ₯ β
ββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ
β μΈμ¦ μ±κ³΅
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ApiAuthorizationManager (μΈκ° μ²λ¦¬) β
β β
β Β· SecurityContextμμ μΈμ¦ μ 보 κΊΌλ΄κΈ° β
β Β· JWT ν ν°μμ μ¬μ©μ κΆν(ROLE) νμΈ β
β Β· μμ² URLμ λν μ κ·Ό κΆν νλ¨ β
β ββ μ κ·Ό νμ© β Controllerλ‘ μ λ¬ β
β ββ μ κ·Ό κ±°λΆ β 403 μλ΅ (ApiAccessDeniedHandler) β
ββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ
β
βΌ
[Controller μ€ν]
[λΈλΌμ°μ ]
β
β POST /common/auth/login-processing
β Form: id=user01&password=pass
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WebIdPasswordLoginAuthenticationFilter β
β μν : form νλΌλ―Έν°(id, password)λ₯Ό κΊΌλ΄μ μΈμ¦ ν ν° μμ± β
ββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β authenticate()
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β webAuthenticationManager (ProviderManager) β
β β WebIdPasswordLoginAuthenticationProviderμκ² κ²μ¦ μμ β
ββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WebIdPasswordLoginAuthenticationProvider β
β β
β 1. CustomUserDetailsServiceλ‘ DBμμ μ¬μ©μ μ‘°ν β
β 2. PasswordEncoderλ‘ μ
λ ₯λ ν¨μ€μλμ DB ν¨μ€μλ λΉκ΅ β
β 3. κ³μ μν νμΈ (μ κΉ/λ§λ£/λΉνμ±ν μ¬λΆ) β
ββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββ΄βββββββββββββββ
βΌ βΌ
[μΈμ¦ μ±κ³΅] [μΈμ¦ μ€ν¨]
β β
βΌ βΌ
ββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββ
β CompositeSession β β WebIdPasswordLogin β
β AuthenticationStrategy β β AuthenticationFailure β
β (3λ¨κ³ μΈμ
μ λ΅ μμ μ€ν) β β Handler β
β β β Β· λ‘κ·ΈμΈ νμ΄μ§λ‘ 리λ€μ΄λ νΈ β
β 1. λμ λ‘κ·ΈμΈ μ ν μ²΄ν¬ β β Β· μλ¬ λ©μμ§ μ λ¬ β
β (κΈ°μ‘΄ μΈμ
λ§λ£ μ²λ¦¬) β ββββββββββββββββββββββββββββββββ
β β
β 2. μΈμ
ID κ΅μ²΄ β
β (μΈμ
κ³ μ 곡격 λ°©μ§) β
β β
β 3. μ μΈμ
μ β
β SessionRegistryμ λ±λ‘ β
ββββββββββββββββββββββββ¬ββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WebIdPasswordLoginAuthenticationSuccessHandler β
β β
β 1. Access Token μμ± (μ ν¨κΈ°κ°: 1μκ°) β
β 2. Refresh Token μμ± (μ ν¨κΈ°κ°: 24μκ°) β
β 3. Refresh Tokenμ DBμ μ μ₯ (κ°±μ μ©) β
β 4. JWT Tokenμ μΈμ
μ μ μ₯ β
β session.setAttribute("jwtToken", jwtToken) β
β 5. κΈ°λ³Έ μ΄λ URLλ‘ λ¦¬λ€μ΄λ νΈ β /result β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[λ‘κ·ΈμΈ μ΄ν νλ©΄ μμ²]
β
β GET /job
β Cookie: JSESSIONID=abc123 β λΈλΌμ°μ κ° μλμΌλ‘ μ μ‘
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Session μ μ₯μ (Redis) β
β Β· JSESSIONIDλ‘ μΈμ
κ²μ β
β Β· μΈμ
μμ SecurityContext 볡μ β
β Β· μΈμ
μμ jwtToken 볡μ β
ββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ
β μΈμ
μ ν¨
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WebAuthorizationManager (μΈκ° μ²λ¦¬) β
β Β· μ¬μ©μ κΆν(ROLE) νμΈ β
β Β· μμ² URL μ κ·Ό κ°λ₯ μ¬λΆ νλ¨ β
ββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ
β μ κ·Ό νμ©
βΌ
[Controller μ€ν]
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Spring Security μ»΄ν¬λνΈ μ§λ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β [μ€μ ν΄λμ€] β
β βββββββββββββββββββββββ βββββββββββββββββββββββββββββββββββββββ β
β β ApiSecurityConfig β β WebSecurityConfig β β
β β Order=1 β β Order=2 β β
β β /api/**, /common/ β β λλ¨Έμ§ λͺ¨λ URL β β
β β api/** β β β β
β βββββββββββββββββββββββ βββββββββββββββββββββββββββββββββββββββ β
β β
β [νν° - μΈμ¦ μ²λ¦¬] β
β βββββββββββββββββββββββββββββββββββββ β
β β ApiJwtAuthentication β JWT ν ν° κ²μ¦ β
β β Filter β (API μμ²λ§λ€ μ€ν) β
β βββββββββββββββββββββββββββββββββββββ β
β βββββββββββββββββββββββββββββββββββββ β
β β ApiJsonLoginAuthentication β API λ‘κ·ΈμΈ μ²λ¦¬ β
β β Filter β (POST /common/api/auth/...) β
β βββββββββββββββββββββββββββββββββββββ β
β βββββββββββββββββββββββββββββββββββββ β
β β WebIdPasswordLoginAuthentication β μΉ λ‘κ·ΈμΈ μ²λ¦¬ β
β β Filter β (POST /common/auth/...) β
β βββββββββββββββββββββββββββββββββββββ β
β β
β [Provider - ν¨μ€μλ κ²μ¦] β
β βββββββββββββββββββββββββββββββββββββ β
β β WebIdPasswordLoginAuthentication β μμ΄λ/ν¨μ€μλ κ²μ¦ β
β β Provider β (μΉ λ‘κ·ΈμΈ μ μ©) β
β βββββββββββββββββββββββββββββββββββββ β
β β
β [UserDetails - μ¬μ©μ μ 보] β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β CustomUserDetailsService β CustomUserDetails β β
β β (DBμμ μ¬μ©μ μ‘°ν) (id, name, role, password) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β [Handler - μ±κ³΅/μ€ν¨ μ²λ¦¬] β
β ββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββ β
β β API μ±κ³΅ νΈλ€λ¬ β β Web μ±κ³΅ νΈλ€λ¬ β β
β β Β· JWT ν ν° λ°κΈ β β Β· JWT λ°κΈ + μΈμ
μ μ₯ β β
β β Β· JSON μλ΅ β β Β· /result 리λ€μ΄λ νΈ β β
β ββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββ β
β ββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββ β
β β API μ€ν¨ νΈλ€λ¬ β β Web μ€ν¨ νΈλ€λ¬ β β
β β Β· 401 JSON μλ΅ β β Β· λ‘κ·ΈμΈ νμ΄μ§ 리λ€μ΄λ νΈ β β
β ββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββ β
β β
β [Authorization - μ κ·Ό κΆν νλ¨] β
β βββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββββββ β
β β ApiAuthorizationManagerβ β WebAuthorizationManager β β
β β Β· JWT ν ν° μ ν¨μ± νμΈ β β Β· μΈμ
/κΆν νμΈ β β
β β Β· ROLE κΆν μ²΄ν¬ β β Β· ROLE κΆν μ²΄ν¬ β β
β βββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββββββ β
β β
β [EntryPoint/Handler - μμΈ μ²λ¦¬] β
β ββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββ β
β β ApiAuthentication β β WebAuthentication β β
β β EntryPoint (401) β β EntryPoint (401) β β
β β Β· λ―ΈμΈμ¦ JSON μλ΅ β β Β· λ‘κ·ΈμΈ νμ΄μ§ 리λ€μ΄λ νΈ β β
β ββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββ β
β ββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββ β
β β ApiAccessDenied β β WebAccessDenied β β
β β Handler (403) β β Handler (403) β β
β β Β· κΆνμμ JSON μλ΅ β β Β· 403 μλ¬ νμ΄μ§ β β
β ββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β JWT ν ν° κ΅¬μ‘° β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Access Token (μ ν¨κΈ°κ°: 1μκ°) β
β ββββββββββββ ββββββββββββββββββββββββββ βββββββββββββββββββ β
β β Header β . β Payload β . β Signature β β
β β alg, typ β β id, role, exp, iat ... β β (λΉλ°ν€λ‘ μλͺ
) β β
β ββββββββββββ ββββββββββββββββββββββββββ βββββββββββββββββββ β
β β
β Refresh Token (μ ν¨κΈ°κ°: 24μκ°) β
β Β· Access Token λ§λ£ μ μλ‘μ΄ Access Token λ°κΈμ μ¬μ© β
β Β· DBμ μ μ₯λμ΄ κ΄λ¦¬λ¨ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[ν ν° κ°±μ νλ¦]
ν΄λΌμ΄μΈνΈ μλ²
β β
βββββ API μμ² (λ§λ£λ ν ν°) βββββββββΆβ
β β
βββββ 401 (ν ν° λ§λ£) ββββββββββββββββ
β β
βββββ POST /common/api/auth/refreshβββΆβ
β Refresh Token μ μ‘ β Β· DBμμ Refresh Token κ²μ¦
β β Β· μ ν¨νλ©΄ μ Access Token λ°κΈ
βββββ μ Access Token λ°ν βββββββββββ
β β
βββββ μ ν ν°μΌλ‘ API μ¬μμ² ββββββββββΆβ
[λ¨μΌ μλ² νκ²½ (Redis μμ)]
ββββββββββββββββββββ
β WAS μλ² β
β λ©λͺ¨λ¦¬μ μΈμ
μ μ₯ ββββ μ¬μ©μ λ‘κ·ΈμΈ
β Session: {abc} β
ββββββββββββββββββββ
β μλ² 1λμΌ λλ λ¬Έμ μμ
[λ€μ€ μλ² νκ²½ (Redis μμΌλ©΄ λ¬Έμ λ°μ)]
βββββββββββββββ βββββββββββββββ
β WAS μλ²1 β β WAS μλ²2 β
β Session:{abc}β β μΈμ
μμ! ββββ κ°μ μ¬μ©μκ° μλ²2λ‘ μ°κ²°λλ©΄
βββββββββββββββ βββββββββββββββ μΈμ
μ μ°Ύμ§ λͺ»ν΄ λ‘κ·Έμμλ¨!
[λ€μ€ μλ² νκ²½ (Redis μ¬μ© - μ΄ μμ€ν
)]
βββββββββββββββ βββββββββββββββ
β WAS μλ²1 β β WAS μλ²2 β
ββββββββ¬βββββββ ββββββββ¬βββββββ
ββββββββββββ¬βββββββββ
βΌ
βββββββββββββββ
β Redis ββββ μΈμ
μ μ€μ μ μ₯μμ μ μ₯
β Session:{abc}β μ΄λ μλ²λ‘ μ°κ²°λλ λμΌν μΈμ
μ¬μ©
βββββββββββββββ
| μ€μ νλͺ© | κ° | μ€λͺ |
|---|---|---|
| μΈμ μ ν¨ μκ° | 6,000μ΄ (μ½ 100λΆ) | λ§μ§λ§ νλ ν μλ λ§λ£ |
| μ μ© νκ²½ | real, dr, dev, test | μ΄μ/κ°λ° νκ²½μμλ§ μ μ© |
| λ‘컬 νκ²½ | λ―Έμ μ© | λ‘컬 κ°λ° μ JVM λ©λͺ¨λ¦¬ μΈμ μ¬μ© |
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β μΈμ
μλͺ
μ£ΌκΈ° β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[λ‘κ·ΈμΈ]
λΈλΌμ°μ β μλ²
μλ²: μΈμ
μμ± (JSESSIONID λ°κΈ)
μλ²: JWT ν ν°μ μΈμ
μ μ μ₯
μλ² β λΈλΌμ°μ : JSESSIONID μΏ ν€ μ λ¬
β
[μ΄ν μμ²λ€]
λΈλΌμ°μ β μλ² (μΏ ν€μ JSESSIONID μλ ν¬ν¨)
μλ²: Redisμμ μΈμ
μ‘°ν
μλ²: μΈμ
μμ JWT ν ν° κΊΌλ΄κΈ°
μλ²: μΈμ¦λ μ¬μ©μλ‘ μ²λ¦¬
β
[λμ λ‘κ·ΈμΈ μλ]
λ€λ₯Έ λΈλΌμ°μ μμ κ°μ κ³μ μΌλ‘ λ‘κ·ΈμΈ
β κΈ°μ‘΄ μΈμ
λ§λ£ μ²λ¦¬
β κΈ°μ‘΄ λΈλΌμ°μ : λ€μ μμ² μ /common/auth/login?expired λ‘ μ΄λ
β
[λ‘κ·Έμμ]
λΈλΌμ°μ β POST /common/auth/logout-processing
μλ²: μΈμ
μμ (Redisμμ μ κ±°)
μλ²: JSESSIONID μΏ ν€ μμ
μλ² β λΈλΌμ°μ : λ‘κ·ΈμΈ νμ΄μ§ 리λ€μ΄λ νΈ
β
[μΈμ
λ§λ£ (νμμμ)]
λ§μ§λ§ μμ² ν 6,000μ΄ κ²½κ³Ό
Redisμμ μλ μμ
λ€μ μμ² μ β λ‘κ·ΈμΈ νμ΄μ§ μ΄λ
[User A: PCμμ λ‘κ·ΈμΈ μ€]
Session: "session_A" β Redisμ μ μ₯λ¨
SessionRegistryμ "session_A" λ±λ‘λ¨
[User A: λͺ¨λ°μΌμμ λμΌ κ³μ μΌλ‘ λ‘κ·ΈμΈ μλ]
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ConcurrentSessionControlAuthenticationStrategy β
β Β· SessionRegistryμμ νμ¬ "user_A"μ μΈμ
λͺ©λ‘ νμΈ β
β Β· κΈ°μ‘΄ μΈμ
"session_A"κ° μμΌλ―λ‘ β λ§λ£ νμ β
β (session_A.expireNow() νΈμΆ) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SessionFixationProtectionStrategy β
β Β· λͺ¨λ°μΌ λ‘κ·ΈμΈμ© μ μΈμ
ID μμ± ("session_B") β
β Β· μΈμ
κ³ μ 곡격 λ°©μ§ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
λͺ¨λ°μΌ: λ‘κ·ΈμΈ μ±κ³΅, "session_B" μ¬μ©
PC: λ€μ μμ² μ "session_A"κ° λ§λ£λ¨ β /common/auth/login?expired μ΄λ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β λ°°μΉ λ§μ€ν° Job μ€ν μν€ν
μ² β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[μ΄μμ/κ΄λ¦¬μ]
β
β Job λ±λ‘ / μ€μΌμ€ μ€μ (νλ©΄μμ)
βΌ
ββββββββββββββββββββββββββββββββββββββββββββ
β λ°°μΉ λ§μ€ν° μμ€ν
β
β β
β ββββββββββββββββββββββββββββββββββββ β
β β DB (Oracle) β β
β β Β· JOB ν
μ΄λΈ (μμ
μ 보) β β
β β Β· CALENDAR ν
μ΄λΈ (μΊλ¦°λ) β β
β β Β· RESULT ν
μ΄λΈ (μ€ν κ²°κ³Ό) β β
β ββββββββββββ¬ββββββββββββββββββββββββ β
β β μ± μμ μ μ 체 λ‘λ β
β βΌ β
β ββββββββββββββββββββββββββββββββββββ β
β β SchedulerService β β
β β registerAllJobsToScheduler() β β
β β Β· DBμμ λͺ¨λ Job μ‘°ν β β
β β Β· κ° Jobμ Quartzμ λ±λ‘ β β
β ββββββββββββ¬ββββββββββββββββββββββββ β
β β β
β ββββββββββ΄ββββββββββ β
β βΌ βΌ β
β βββββββββββββββ βββββββββββββββ β
β β Calendar β β Cron β β
β β JobHandler β β JobHandler β β
β β (νΉμ λ μ§) β β (λ°λ³΅ μ€ν) β β
β ββββββββ¬βββββββ ββββββββ¬βββββββ β
β ββββββββββ¬βββββββββ β
β βΌ β
β ββββββββββββββββββββββββββββββββββββ β
β β Quartz Scheduler β β
β β ThreadPool: 10κ° β β
β β ShedLock: μ€λ³΅ μ€ν λ°©μ§ β β
β ββββββββββββββββββββ¬ββββββββββββββββ β
β β νΈλ¦¬κ±° λ°λ β
β ββββββββββββ΄βββββββββββ β
β βΌ βΌ β
β ββββββββββββββββ βββββββββββββββββββ β
β β CalendarJob β β CronJob β β
β β Executor β β Executor β β
β β execute() β β execute() β β
β ββββββββ¬ββββββββ ββββββββββ¬βββββββββ β
β ββββββββββββ¬ββββββββββ β
β βΌ β
β βββββββββββββββββββββββββββββββββββ β
β β SchedulerProducer β β
β β sendJobMessage() β β
β β β Kafka ν ν½μΌλ‘ λ©μμ§ λ°ν β β
β βββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββ¬ββββββββββββββββββββ
β
β Kafka λ©μμ§
βΌ
βββββββββββββββββββββββββββββββ
β Kafka Broker β
β Topic: execute-cron-job β
β Topic: execute-calendar-jobβ
ββββββββββββββββ¬βββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββ
β Worker μλ² (Consumer) β
β μ€μ λ°°μΉ μμ
μν β
β (νμΌ μ²λ¦¬, DB μ²λ¦¬ λ±) β
ββββββββββββββββ¬βββββββββββββββ
β κ²°κ³Ό μ μ₯
βΌ
βββββββββββββ
β Oracle β
β RESULT β
β ν
μ΄λΈ β
βββββββββββββ
[κ°λ
] νΉμ λ μ§μ μ€ννλ Job
μ) λ§€μ λ§μΌ, 곡ν΄μΌ μ μΈν μμ
μΌ, νΉμ λ μ§λ€
[λ±λ‘ λ°©μ]
1. μΊλ¦°λμ μ€νν λ μ§λ€ λ±λ‘
2. Jobμ ν΄λΉ μΊλ¦°λ μ°κ²°
3. Quartz: CalendarIntervalTrigger λλ CustomCalendarλ‘ μ€μΌμ€ λ±λ‘
[μ€ν νλ¦]
DBμ μΊλ¦°λ λ μ§ λͺ©λ‘
β
CalendarJobHandler.registerJob()
β
Quartz Scheduler λ±λ‘
β
ν΄λΉ λ μ§ λλ¬ μ CalendarJobExecutor.execute() νΈμΆ
β
Kafka λ©μμ§ λ°ν (execute-calendar-job ν ν½)
[κ°λ
] Cron ννμμΌλ‘ λ°λ³΅ μ€ννλ Job
μ) λ§€μΌ μ€μ 2μ, λ§€μ£Ό μμμΌ μ€μ 9μ, λ§€μκ° μ κ°
[Cron ννμ νμ]
βββββββββββ μ΄ (0-59)
β βββββββββ λΆ (0-59)
β β βββββββ μ (0-23)
β β β βββββ μΌ (1-31)
β β β β βββ μ (1-12)
β β β β β β μμΌ (0-7, 0κ³Ό 7μ μΌμμΌ)
β β β β β β
0 2 * * * * β λ§€μΌ μ€μ 2μ 0λΆ 0μ΄ μ€ν
[μ€ν νλ¦]
DBμ Cron ννμ
β
CronJobHandler.registerJob()
β
Quartz Schedulerμ CronTrigger λ±λ‘
β
νΈλ¦¬κ±° λ°λ μ CronJobExecutor.execute() νΈμΆ
β
Kafka λ©μμ§ λ°ν (execute-cron-job ν ν½)
[λ¬Έμ μν©: ShedLock μμ λ]
μλ² A: Quartz Trigger λ°λ β Job μ€ν μμ
μλ² B: Quartz Trigger λ°λ β Job μ€ν μμ β κ°μ Jobμ΄ λμμ 2λ² μ€ν!
[ν΄κ²°: ShedLock μ¬μ©]
μλ² A: Quartz Trigger λ°λ
ββ ShedLock: DBμ Lock νλ μλ
ββ μ±κ³΅ β Job μ€ν (μ΅λ 10λΆ Lock μ μ§)
ββ μ€ν¨ β Job 건λλ
μλ² B: Quartz Trigger λ°λ
ββ ShedLock: DBμ Lock νλ μλ
ββ μ€ν¨ (Aκ° μ΄λ―Έ Lock 보μ ) β Job 건λλ
κ²°κ³Ό: μ΄λ νκ²½μ΄λ Jobμ λ± 1λ²λ§ μ€νλ¨
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Kafka λ©μμ§ νλ¦ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Producer (μ΄ μμ€ν
) Consumer (Worker μλ²λ€)
β β
β Topic: execute-cron-job β
ββββ {"jobId":"J001", "params":{...}} βββΆβ
β β Job μ€ν
β Topic: execute-calendar-job β
ββββ {"jobId":"J002", "params":{...}} βββΆβ
β β
β Topic: file-upload β
ββββ {"fileId":"F001", "path":"..."} ββββΆβ
β β
β Topic: push-message β
ββββ {"type":"complete", "msg":"..."} ββββ μμ
μλ£ μλ¦Ό
β β
βΌ β
SSE (Server-Sent Events) β
β λΈλΌμ°μ λ‘ μ€μκ° νΈμ β
[Kafka μ€μ ]
Β· μλ 컀λ°: OFF (μλ 컀λ°μΌλ‘ λ©μμ§ μ μ€ λ°©μ§)
Β· μ΅λ ν΄λ§: 10건 (ν λ²μ μ΅λ 10κ° λ©μμ§ μ²λ¦¬)
Β· μ€νμ
μ΄κΈ°ν: latest (κ°μ₯ μ΅μ λ©μμ§λΆν°)
[SSE μ°κ²° μ립]
λΈλΌμ°μ β GET /common/sse/subscribe
μλ²: SSE μ°κ²° μμ±, SseEmitter λ±λ‘
[μ΄λ²€νΈ λ°μ μ]
Worker μλ² β Kafka push-message ν ν½μ λ©μμ§ λ°ν
β
PushMessageKafkaConsumer λ©μμ§ μμ
β
SseEmitterService.sendMessageToClient()
β
λΈλΌμ°μ : μ€μκ°μΌλ‘ μλ¦Ό μμ (νμ΄μ§ μλ‘κ³ μΉ¨ μμ΄)
ββββββββββββββββββββββββββββββββββββββββββββββββ
β νλ©΄ ꡬ쑰 β
β β
β ββββββββββββββββββββββββββββββββββββββββββ β
β β μλ¨ λ€λΉκ²μ΄μ
(topbar) β β
β ββββββββββββββββββββββββββββββββββββββββββ β
β βββββββββββββ ββββββββββββββββββββββββββββ β
β β β β β β
β β μ¬μ΄λλ° β β λ©μΈ 컨ν
μΈ μμ β β
β β (sidebar) β β β β
β β β β Β· Job λͺ©λ‘ β β
β β Β· κ²°κ³Ό β β Β· κ²μ νν° β β
β β Β· Job β β Β· λ°μ΄ν° ν
μ΄λΈ β β
β β Β· μΊλ¦°λ β β Β· λͺ¨λ¬ μ°½ β β
β β β β β β
β βββββββββββββ ββββββββββββββββββββββββββββ β
β ββββββββββββββββββββββββββββββββββββββββββ β
β β footer β β
β ββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββ
| νλ©΄ | URL | μ£Όμ κΈ°λ₯ |
|---|---|---|
| λ‘κ·ΈμΈ | /common/auth/login |
μμ΄λ/ν¨μ€μλ λ‘κ·ΈμΈ |
| λ©μΈ | / |
μμ€ν λ©μΈ νλ©΄ |
| κ²°κ³Ό μ‘°ν | /result |
λ°°μΉ μ€ν κ²°κ³Ό λͺ©λ‘/μμΈ |
| Job κ΄λ¦¬ | /job |
Job λ±λ‘/μμ /μμ /μ‘°ν |
| μΊλ¦°λ κ΄λ¦¬ | /calendar |
μ€ν λ μ§ μΊλ¦°λ κ΄λ¦¬ |
[Job κ΄λ¦¬ νλ©΄ (/job)]
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β κ²μ 쑰건 β
β [Jobλͺ
] [μν] [μ€μΌμ€νμ
] [κ²μ] β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Job λͺ©λ‘ [+ λ±λ‘] β
β ββββββββββ¬ββββββββββββ¬βββββββββββ¬βββββββββ¬βββββββββββββββββββ β
β β Job ID β Jobλͺ
β μ€μΌμ€ β μν β μμ
β β
β ββββββββββΌββββββββββββΌβββββββββββΌβββββββββΌβββββββββββββββββββ€ β
β β J001 β μΌμΌμ μ° β CRON β νμ± β [μμΈ] [μμ ] [μμ ] β
β β J002 β μλ§μ μ° β CALENDAR β νμ± β [μμΈ] [μμ ] [μμ ] β
β ββββββββββ΄ββββββββββββ΄βββββββββββ΄βββββββββ΄βββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[Job λ±λ‘ λͺ¨λ¬]
Β· Job ID, Jobλͺ
μ
λ ₯
Β· μ€μΌμ€ νμ
μ ν (CRON / CALENDAR)
Β· CRON μ ν μ: Cron ννμ μ
λ ₯ (κ°μ΄λ λͺ¨λ¬ μ 곡)
Β· CALENDAR μ ν μ: μΊλ¦°λ μ ν
Β· μ€ν κ²½λ‘, νλΌλ―Έν° μ€μ
| νκ²½ | Profile | μ©λ | Redis | ν¬νΈ |
|---|---|---|---|---|
| λ‘컬 | local |
κ°λ°μ λ‘컬 κ°λ° | λ―Έμ¬μ© (JVM μΈμ ) | 80 |
| κ°λ° | dev |
ν΅ν© κ°λ° νκ²½ | μ¬μ© | - |
| ν μ€νΈ | test |
QA/ν μ€νΈ νκ²½ | μ¬μ© | - |
| DR | dr |
μ¬ν΄λ³΅κ΅¬ μλ² | μ¬μ© | - |
| μ΄μ | real |
μ€μ μ΄μ νκ²½ | μ¬μ© | - |
src/main/resources/
βββ application.yml β λͺ¨λ νκ²½ κ³΅ν΅ μ€μ
βββ application-local.yml β λ‘컬 μ μ© μ€μ
βββ application-dev.yml β κ°λ° μ μ© μ€μ
βββ application-dr.yml β DR μ μ© μ€μ
βββ application-real.yml β μ΄μ μ μ© μ€μ
βββ application-test.yml β ν
μ€νΈ μ μ© μ€μ
β
βββ config-local/datasource.yml β λ‘컬 DB μ μ μ 보
βββ config-dev/datasource.yml β κ°λ° DB μ μ μ 보
βββ config-dr/datasource.yml β DR DB μ μ μ 보
βββ config-real/datasource.yml β μ΄μ DB μ μ μ 보
βββ config-test/datasource.yml β ν
μ€νΈ DB μ μ μ 보
# λ‘컬 νκ²½ μ€ν
./gradlew bootRun --args='--spring.profiles.active=local'
# κ°λ° νκ²½ μ€ν
java -jar app.jar --spring.profiles.active=dev
# μ΄μ νκ²½ μ€ν
java -jar app.jar --spring.profiles.active=real| μ€μ νλͺ© | κ° | μ€λͺ |
|---|---|---|
| JWT Access Token μ ν¨κΈ°κ° | 3,600,000ms (1μκ°) | API μΈμ¦ ν ν° |
| JWT Refresh Token μ ν¨κΈ°κ° | 86,400,000ms (24μκ°) | ν ν° κ°±μ μ© |
| Swagger UI κ²½λ‘ | /apidoc |
API λ¬Έμ μ κ·Ό URL |
| MyBatis 쿼리 νμμμ | 10μ΄ | DB 쿼리 μ΅λ μ€ν μκ° |
| Kafka μ΅λ ν΄λ§ μ | 10건 | 1νμ μ²λ¦¬ν λ©μμ§ μ |
| ShedLock μ΅λ μ κΈ μκ° | 10λΆ | λΆμ° λ½ μ΅λ μ μ§ μκ° |
| μ€μ νλͺ© | κ° | μ€λͺ |
|---|---|---|
| μ΅λ 컀λ₯μ μ | 60 | λμ μ¬μ© κ°λ₯ν μ΅λ DB μ°κ²° |
| μ΅μ μ μ§ μ»€λ₯μ | 20 | νμ μ μ§νλ μ΅μ μ°κ²° μ |
| 컀λ₯μ λκΈ° μκ° | 30μ΄ | 컀λ₯μ νλ μ΅λ λκΈ° |
| 컀λ₯μ μ΅λ μλͺ | 900μ΄ (15λΆ) | 컀λ₯μ μ¬μμ± μ£ΌκΈ° |
| μ ν΄ μ»€λ₯μ λ§λ£ | 300μ΄ (5λΆ) | λ―Έμ¬μ© 컀λ₯μ λ°ν μκ° |
[ ] 1. μ μΌ λ°°μΉ μμ
μ€ν κ²°κ³Ό νμΈ
β /result νλ©΄μμ μ±κ³΅/μ€ν¨ μ¬λΆ νμΈ
β μ€ν¨ν Jobμ΄ μμΌλ©΄ μμΈ νμ
λ° μ¬μ€ν
[ ] 2. μ€μΌμ€λ¬ λμ μν νμΈ
β Quartz Scheduler μ μ ꡬλ μ¬λΆ
β λ±λ‘λ Job μμ DB Job μ μΌμΉ μ¬λΆ
[ ] 3. λ‘κ·Έ λͺ¨λν°λ§
β μ ν리μΌμ΄μ
λ‘κ·Έ νμΌ νμΈ
(./log/krx-nlds-bat-mst.log)
β ERROR λ 벨 λ‘κ·Έ λ°μ μ¬λΆ
[ ] 4. μλ² μμ λͺ¨λν°λ§
β /actuator/health μλν¬μΈνΈ νμΈ
β DB 컀λ₯μ
ν μ¬μ©λ
β Kafka Consumer lag νμΈ
κ°λ°/ν μ€νΈ νκ²½μμ
/apidocμ κ·Ό μ μ 체 API λͺ©λ‘ νμΈ κ°λ₯
| λΆλ₯ | μ£Όμ API κ²½λ‘ | μ€λͺ |
|---|---|---|
| μΈμ¦ | POST /common/api/auth/login-processing |
API λ‘κ·ΈμΈ |
| μΈμ¦ | POST /common/api/auth/refresh |
ν ν° κ°±μ |
| Job | POST /api/create/job |
Job λ±λ‘ |
| Job | GET /api/read/jobs |
Job λͺ©λ‘ μ‘°ν |
| Job | POST /api/update/job |
Job μμ |
| Job | POST /api/delete/job |
Job μμ |
| μΊλ¦°λ | POST /api/create/calendar |
μΊλ¦°λ λ±λ‘ |
| μΊλ¦°λ | GET /api/read/calendars |
μΊλ¦°λ λͺ©λ‘ |
| κ²°κ³Ό | GET /api/read/results |
μ€ν κ²°κ³Ό μ‘°ν |
| μ€μΌμ€λ¬ | POST /api/scheduler/register |
μ€μΌμ€ μλ λ±λ‘ |
β οΈ μ΄μ νκ²½μμ λ°λμ νμΈν μ¬ν
1. PERMIT_ALL_LISTμ "/**" κ° μμΌλ©΄ μ λ¨ (κ°λ° νΈμμ© μ€μ )
β ApiSecurityConfig.PERMIT_ALL_LIST νμΈ
β WebSecurityConfig.PERMIT_ALL_LIST νμΈ
2. Swagger UIλ μ΄μ νκ²½μμ μ κ·Ό μ ν νμ
β /apidoc, /swagger-ui/**, /v3/api-docs/** κ²½λ‘ μ°¨λ¨ κ²ν
3. JWT λΉλ°ν€λ νκ²½λ³λ‘ λ€λ₯΄κ² μ€μ ν΄μΌ ν¨
β application-*.ymlμ jwt.secret κ° νμΈ
4. HTTPS μ μ© μ WebSecurityConfigμ HSTS μ€μ νμ±ν νμ
β http.headers(headers -> headers
.httpStrictTransportSecurity(hsts -> hsts
.maxAgeInSeconds(31536000)
.includeSubDomains(true)))
| μ¦μ | μμΈ | ν΄κ²° λ°©λ² |
|---|---|---|
| λ‘κ·ΈμΈ ν μΈμ μ μ§ μ λ¨ | Redis μ°κ²° λ¬Έμ | Redis μλ² μν λ° μ μ μ 보 νμΈ |
| JWT ν ν° λ§λ£ μ€λ₯ λ°λ³΅ | Access Token μ ν¨μκ° | Refresh TokenμΌλ‘ κ°±μ API νΈμΆ |
| Jobμ΄ λ λ² μ€νλ¨ | ShedLock DB ν μ΄λΈ λ¬Έμ | ShedLock ν μ΄λΈ μν νμΈ |
| νΉμ Jobμ΄ μ€ν μ λ¨ | Quartz μ€μΌμ€ λ―Έλ±λ‘ | μ€μΌμ€λ¬ μ¬μμ λλ μλ λ±λ‘ API νΈμΆ |
| νλ©΄μ μ΄λ¦¬λλ° API μ€λ₯ | κΆν μ€μ λ¬Έμ | μ¬μ©μ ROLE λ° URL κΆν ν μ΄λΈ νμΈ |
| Kafka λ©μμ§ μ²λ¦¬ μ§μ° | Consumer lag μ¦κ° | Consumer μλ² μν λ° ν ν½ νν°μ νμΈ |
| ν΄λμ€λͺ | νμΌ κ²½λ‘ |
|---|---|
| ApiSecurityConfig | ldsframework/common/config/security/ApiSecurityConfig.java |
| WebSecurityConfig | ldsframework/common/config/security/WebSecurityConfig.java |
| ApiJwtAuthenticationFilter | ldsframework/common/config/security/filter/ApiJwtAuthenticationFilter.java |
| JwtTokenProvider | ldsframework/common/config/jwt/JwtTokenProvider.java |
| RedisConfig | ldsframework/common/config/redis/RedisConfig.java |
| SchedulerConfig | ldsframework/common/config/batch/SchedulerConfig.java |
| KafkaConfig | ldsframework/common/config/kafka/KafkaConfig.java |
| CustomUserDetails | ldsframework/common/config/security/principal/CustomUserDetails.java |
| κ·μΉ | λ΄μ© |
|---|---|
| REST API URL ν¨ν΄ | /api/{action}/{resource} (μ: /api/create/job) |
| μλ΅ νμ | CommonResponseDto μλ λν (μμΈ: @NoWrap) |
| κΆν μ²΄ν¬ | @RequirePermission(type = PermissionType.READ) AOP |
| 쿼리 μμΉ | λ¨μ 쿼리: @Mapper μ΄λ
Έν
μ΄μ
/ λμ 쿼리: XML νμΌ |
| κ²μ¦ κ·Έλ£Ή | ValidGroups.Insert, ValidGroups.Update, ValidGroups.Delete |
| κ³΅ν΅ μμΈ | CustomRuntimeException μ¬μ© |
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β λ°°μΉ μμ
λ±λ‘ β μ€μΌμ€λ¬ λ±λ‘ β Agent μ€ν μ§μ β λ°°μΉ μ€ν μ 체 νλ¦ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PHASE 1 μΉ νλ©΄μ ν΅ν λ°°μΉ μμ
(Job) λ±λ‘
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[μ΄μμ λΈλΌμ°μ ] [jobCreateModal.js] [Spring Security]
β β β
β β /job νλ©΄ μ μ β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββΆβ
β β β WebSecurityConfig
β β‘ μμ
λͺ©λ‘ νλ©΄ λ λλ§ β β μΈμ
μΈμ¦ ν΅κ³Ό
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β β’ [μμ
λ±λ‘] λ²νΌ ν΄λ¦ β
ββββββββββββββββββββββββββββββββββββΆβ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ PHASE 2 Quartz Scheduler λ±λ‘ (POST /api/scheduler/register νΈμΆ λλ μ ν리μΌμ΄μ μ¬κΈ°λ μ μλ μ€ν) ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[μ΄μμ / μμ€ν ] β β β POST /api/scheduler/register β βΌ [SchedulerController] β βΌ [SchedulerService.registerAllJobsToScheduler()] β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β CAL νμ μ²λ¦¬ β CRON νμ μ²λ¦¬ βΌ βΌ [CalendarJobHandler.registerJob()] [CronJobHandler.registerJob()] β β β β‘ jobMapper.selectExecutableJobs() β’ jobMapper.selectJobs(μ 체) β β CAL νμ Job μ 체 μ‘°ν β μ 체 Job μ‘°ν β β β β£ λ±λ‘ 쑰건 4κ°μ§ λμ κ²μ¬ β€ λ±λ‘ 쑰건 2κ°μ§ κ²μ¬ β βββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ β β isCalendarJob() β β isCronJob() β β β jobSchdlTpNm == "CAL" β β jobSchdlTpNm == "CRON" β β βββββββββββββββββββββββββββββββ€ ββββββββββββββββββββββββββββ€ β β isUsableJob() β β isUsableJob() β β β μ€λ >= strtDd β β μ€λ >= strtDd β β β μ€λ <= endDd β β μ€λ <= endDd β β βββββββββββββββββββββββββββββββ€ ββββββββββββββββββββββββββββ β β !isFollowJob() β λͺ¨λ ν΅κ³Ό μλ§ λ±λ‘ β β νν Jobμ΄ μλ κ²½μ° β β β (λν κ·Έλ£Ή Jobλ§ λ±λ‘) β β βββββββββββββββββββββββββββββββ€ β β isRunTodayJob() β β β μΊλ¦°λ SQL μ€ν β β β β μ€λ λ μ§κ° κ²°κ³Όμ ν¬ν¨ β β β λλμ§ DB μ‘°νλ‘ νλ³ β β βββββββββββββββββββββββββββββββ β λͺ¨λ ν΅κ³Ό μλ§ λ±λ‘ β β β₯ JobDetail μμ± β₯ JobDetail μμ± β JobBuilder.newJob(CalendarJobExecutor.class) JobBuilder.newJob(CronJobExecutor.class) β .withIdentity("[λ±λ‘μΌμ][μ€νμΌμ][Job ID]", grpNm) .withIdentity("[λ±λ‘μΌμ][CRON][Job ID]", grpNm) β .usingJobData("jobId", ...) .usingJobData("jobId", ...) β .usingJobData("jobExecutePath", ...) .usingJobData("jobExecutePath", ...) β .usingJobData("follwJobId", ...) .usingJobData("follwJobId", ...) β .usingJobData("svrNm", ...) .usingJobData("svrNm", ...) β β β¦ Trigger μμ± β¦ Trigger μμ± β TriggerBuilder TriggerBuilder β .startAt(DateBuilder.todayAt(HH, mm, ss)) .withSchedule( β β μ€λ νΉμ μκ° 1ν μ€ν CronScheduleBuilder.cronSchedule("0 2 * * *")) β β λ°λ³΅ μΌμ μΌλ‘ μ€ν β β β§ scheduler.scheduleJob(jobDetail, trigger) β§ scheduler.scheduleJob(jobDetail, trigger) β β Quartzμ λ±λ‘ μλ£ β Quartzμ λ±λ‘ μλ£ β β λ€μ μ€ν μκ°(Date) λ°ν β λ€μ μ€ν μκ°(Date) λ°ν β β β¨ μ€λ μ€ν μμ μ΄λ©΄ β¨ μ€λ μ€ν μμ μ΄λ©΄ β schedulerMapper.insertJobExecutionInfo(...) schedulerMapper.insertJobExecutionInfo(...) β β EXECUTION_INFO ν μ΄λΈμ μ€ν μμ μ 보 μ μ₯ β EXECUTION_INFO ν μ΄λΈμ μ€ν μμ μ 보 μ μ₯ β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β [Quartz Scheduler] λ±λ‘λ Job λκΈ° μ€ (Thread Pool: 10κ°)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ PHASE 3 μ€μΌμ€ νΈλ¦¬κ±° λ°λ β Agentμ μ€ν μ§μ (Kafka λ©μμ§ λ°ν) ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[Quartz Scheduler - μ§μ λ μκ° λλ¬] β β β Trigger λ°λ (μ§μ μκ° λλ Cron 쑰건 μΆ©μ‘±) β Β· ShedLock: DB Lock νλ μλ β ββ μ±κ³΅ β κ³μ μ§ν (λ€λ₯Έ μλ²μμλ Lock νλ μ€ν¨ β μ€ν 건λλ) β ββ μ€ν¨ β μ΄ μλ²μμ μ€ν μ€λ¨ (μ€λ³΅ μ€ν λ°©μ§) β ββββββββββββββββββββββββββββββββββββββββββββββββ β CAL νμ β CRON νμ βΌ βΌ [CalendarJobExecutor.execute()] [CronJobExecutor.execute()] β β β β‘ context.getJobDetail() β β‘ context.getJobDetail() β β λ±λ‘ μ μ μ₯νλ λ°μ΄ν° κΊΌλ΄κΈ° β β λ±λ‘ μ μ μ₯νλ λ°μ΄ν° κΊΌλ΄κΈ° β β β β’ message 쑰립 β β’ message 쑰립 β { β { β key : jobDetail.key, β key : jobDetail.key, β jobId : "J001", β jobId : "J001", β jobExecutePath : "/batch/run/daily.sh", β jobExecutePath : "/batch/run/daily.sh", β follwJobId : "J002", β νν Job ID β follwJobId : "J002", β svrNm : "REAL01" β μ€ν λμ μλ² β svrNm : "REAL01" β } β } β β ββββββββββββββββββββββββ¬ββββββββββββββββββββββββ β βΌ [SchedulerProducer.sendJobMessage(topic, message)] β β β£ new ProducerRecord<>(topic, message) β β β€ kafkaTemplate.send(record) β jsonKafkaTemplate μ¬μ© (HashMap β JSON μ§λ ¬ν) β ββββββββββββββββββββββββββββββββββββββββββββββββ β CAL νμ β CRON νμ βΌ βΌ Topic: "execute-calendar-job" Topic: "execute-cron-job" β β ββββββββββββββββββββ¬ββββββββββββββββββββββββββββ β βΌ [Apache Kafka Broker] λ©μμ§ μ μ₯ λ° μ λ¬ λκΈ° β β β₯ μ μ‘ μ±κ³΅/μ€ν¨ μ½λ°± β whenComplete((result, ex) -> { β μ±κ³΅: log "offset=N" β μ€ν¨: log "μ μ‘ μ€ν¨" β })
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ PHASE 4 Agent(Worker μλ²)κ° λ©μμ§ μμ β λ°°μΉ μ€ν ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[Apache Kafka Broker] β β β Consumerκ° ν ν½ ν΄λ§ (μ΅λ 10건μ©, μλ 컀λ°) βΌ [Agent / Worker μλ² - Kafka Consumer] β β β‘ λ©μμ§ μμ§λ ¬ν (JSON β HashMap) β { β jobId : "J001", β jobExecutePath : "/batch/run/daily.sh", β follwJobId : "J002", β svrNm : "REAL01" β } β β β’ svrNm κΈ°λ°μΌλ‘ μ€ν λμ μλ² μλ³ β β β£ jobExecutePath κΈ°λ°μΌλ‘ λ°°μΉ νλ‘κ·Έλ¨ μ€ν β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β μ ν Job μ±κ³΅ μ β μ€ν μλ£ ν βΌ βΌ [follwJobId νμΈ] [Oracle DB - RESULT ν μ΄λΈ] follwJobId != null μ€ν κ²°κ³Ό μ μ₯ β νν Jobμ΄ μ‘΄μ¬ν¨ Β· jobId β νν Jobμ μ΄μ΄μ μ€ν μ§μ Β· μ€ν μμ/μ’ λ£ μκ° (λμΌ ν ν½μΌλ‘ νν Job λ©μμ§ λ°ν) Β· μ±κ³΅/μ€ν¨ μ¬λΆ Β· μ€λ₯ λ©μμ§ (μ€ν¨ μ) β β β€ (μ ν) Kafka push-message ν ν½ β β PushMessageKafkaConsumer β β SseEmitterService β β λΈλΌμ°μ μ€μκ° μλ¦Ό
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ μ 체 νλ¦ μμ½ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
μ΄μμ β νλ©΄μμ Job μ λ ₯ β [μ μ₯] β βΌ JWT μΈμ¦ β JobController β JobService β Oracle DB INSERT β Job λ°μ΄ν° μ μ₯ β μ€μΌμ€λ¬ λ±λ‘ λͺ λ Ή (μλ or μ¬κΈ°λ) β β βΌ βΌ Oracle DBμμ Job λͺ©λ‘ μ‘°ν SchedulerService β β 쑰건 κ²μ¬ ββ CAL Job β CalendarJobHandler (νμ / μ ν¨κΈ°κ° / ννμ¬λΆ / μ€λμ€νμ¬λΆ) β β Quartzμ "μ€λ HH:MM" 1ν νΈλ¦¬κ±° λ±λ‘ β ββ CRON Job β CronJobHandler β Quartzμ "Cron ννμ" λ°λ³΅ νΈλ¦¬κ±° λ±λ‘ β μ§μ μκ° / Cron 쑰건 μΆ©μ‘± β βΌ ShedLock β DB Lock νλ (μ€λ³΅ λ°©μ§) β βΌ CalendarJobExecutor / CronJobExecutor JobDetail λ°μ΄ν° κΊΌλ΄κΈ° (jobId, jobExecutePath, svrNm, follwJobId) β βΌ SchedulerProducer Kafka λ©μμ§ λ°ν β ββββββββββββββββββββ΄βββββββββββββββββββ βΌ βΌ execute-calendar-job execute-cron-job ββββββββββββββββββββ¬βββββββββββββββββββ β βΌ Kafka Broker β βΌ Agent (Worker μλ²) λ©μμ§ μμ β λ°°μΉ μ€ν νν Job μμΌλ©΄ μ°μ μ€ν β βΌ κ²°κ³Ό DB μ μ₯ + μ€μκ° μλ¦Ό (SSE)
μ΄ λ¬Έμλ next-krx-lds-bat-mst νλ‘μ νΈμ μν€ν
μ² κΈ°μ€μΌλ‘ μμ±λμμ΅λλ€.