Sub-scope 04 (inbound-web) ratelimit + admission + budget + throttle revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5 generatedAt=2026-08-30T07:23:43+00:00 === OWNED FILES === 91364220d354fa936a10b942e6b2dcde630498b3 main/java/dev/caskeleton/adapter/inbound/web/admission/AdmissionDecision.java 59 178b4490eb12e5eed46a3f852a8a264b85c86e0d main/java/dev/caskeleton/adapter/inbound/web/admission/AdmissionPermit.java 21 16681817bdd516264d4909bcb4786f732855920b main/java/dev/caskeleton/adapter/inbound/web/admission/AdmissionProfile.java 80 d00ff8067c01ba747e4f94c96572f43173e44405 main/java/dev/caskeleton/adapter/inbound/web/admission/SemaphoreAdmissionController.java 118 b14a7024c1c8b003ef79df07368278a0444358d1 main/java/dev/caskeleton/adapter/inbound/web/admission/WebAdmissionController.java 21 064bc2a25fb24a24318f4e4836e28ef3a7142aca main/java/dev/caskeleton/adapter/inbound/web/advanced/ratelimit/RateLimitDraftHeaderWriter.java 73 25ef35f4c36501e9848d1c28dfc130cc3c8ce8fd main/java/dev/caskeleton/adapter/inbound/web/advanced/ratelimit/RateLimitDraftProfile.java 36 527173887c38bb4299fcea99e11fbb36a4deb81e main/java/dev/caskeleton/adapter/inbound/web/advanced/ratelimit/RateLimitDraftVersion.java 41 7300a77496caf76d63d42aba79efed3b5ec0e874 main/java/dev/caskeleton/adapter/inbound/web/budget/WebBudgetCatalog.java 77 7c429e0e8257d90e9fd8bcd594eef9368358fc2d main/java/dev/caskeleton/adapter/inbound/web/budget/WebBudgetExceededException.java 56 219b33822d4b542333a2dab1449cc23ba26ffc16 main/java/dev/caskeleton/adapter/inbound/web/budget/WebBudgetMeter.java 89 df6334d8bc0fc3eccc1aee269ccde151f1549028 main/java/dev/caskeleton/adapter/inbound/web/budget/WebBudgetOutcome.java 40 65a4d2c3f3b6ff18458e587550de70f3579d7c17 main/java/dev/caskeleton/adapter/inbound/web/budget/WebBudgetProfileName.java 35 5ccabea10ffcdb5066a8da97146da3d0a58e200b main/java/dev/caskeleton/adapter/inbound/web/budget/WebBudgetViolation.java 39 476086f93ce7d1358dc5e03b509edbcffc361f91 main/java/dev/caskeleton/adapter/inbound/web/budget/WebRequestBudget.java 141 37c6eaaa23dc44f2aa7e696a1fb0b4c094c14252 main/java/dev/caskeleton/adapter/inbound/web/mvc/budget/BoundedHttpServletRequest.java 115 8ba1739ac67c6743deae81c3ad732cc631b974ba main/java/dev/caskeleton/adapter/inbound/web/mvc/budget/BoundedHttpServletResponse.java 151 ea75c7ef7569a86c5c5c6156f56e505954644324 main/java/dev/caskeleton/adapter/inbound/web/mvc/budget/WebMvcBudgetExceptionHandler.java 84 d35a927c92567e81c69f64f512de827c0b53ed65 main/java/dev/caskeleton/adapter/inbound/web/mvc/budget/WebMvcBudgetFilter.java 122 132e294ed05e2e576f04ac7bbdf45343c20c279e main/java/dev/caskeleton/adapter/inbound/web/mvc/throttle/WebMvcThrottleFilter.java 136 d6d622affd05580e675083c8f5bfc2361129a52b main/java/dev/caskeleton/adapter/inbound/web/ratelimit/ClientIpResolver.java 8 3998c4a6d452d2b07efb3527446ebc578529fe13 main/java/dev/caskeleton/adapter/inbound/web/ratelimit/ClientIpResolverFactory.java 13 00303de4d8813ad2f634d41845fe90372c9bd6e6 main/java/dev/caskeleton/adapter/inbound/web/ratelimit/EdgeRateLimitTransportBridge.java 86 980c68b886f3dd3141245504ae8df8cca73bf739 main/java/dev/caskeleton/adapter/inbound/web/ratelimit/EdgeRateLimitTransportSettings.java 40 48a302c4834994d13c7ab59cbdb99b87a7d87cb5 main/java/dev/caskeleton/adapter/inbound/web/ratelimit/ForwardedHeaderClientIpResolver.java 18 3a946d89ad14457d8c044e40a6680bee5eed10e2 main/java/dev/caskeleton/adapter/inbound/web/ratelimit/RateLimitClientIpMode.java 13 30294e192050277f092a8224231d1750a44d5342 main/java/dev/caskeleton/adapter/inbound/web/ratelimit/RateLimitDecision.java 65 0726c4d35d1a0a1d063626e2fa6aaadc07904f53 main/java/dev/caskeleton/adapter/inbound/web/ratelimit/RateLimitEvaluationIdGenerator.java 8 5e05dc2cb9c3e33d1ac42c7e61b50565bf8874e2 main/java/dev/caskeleton/adapter/inbound/web/ratelimit/RateLimitFailurePolicy.java 30 19e7cf3969ec583c50bd01d631a79536a2e8ed7f main/java/dev/caskeleton/adapter/inbound/web/ratelimit/RateLimitInterceptor.java 112 a475a46a747e8ac49c694b479fda5972e9e60f40 main/java/dev/caskeleton/adapter/inbound/web/ratelimit/RateLimitKeyResolver.java 66 34928384705f1b47268ecfef9d71daba9a4b4e02 main/java/dev/caskeleton/adapter/inbound/web/ratelimit/RateLimitProfileName.java 32 651e860d43ed50f1d2e00496fc4dbc4f3f8f5768 main/java/dev/caskeleton/adapter/inbound/web/ratelimit/RateLimitTransportError.java 38 b460c3cb37399a5c581320b9c34eb005544499bb main/java/dev/caskeleton/adapter/inbound/web/ratelimit/RateLimitWebConfig.java 67 d20cc46d411c98e414855fd107480e7dd6368461 main/java/dev/caskeleton/adapter/inbound/web/ratelimit/RemoteAddrClientIpResolver.java 11 b0a9a5ce791f990544a182a059f2340b0fc9f728 main/java/dev/caskeleton/adapter/inbound/web/ratelimit/SecureRandomRateLimitEvaluationIdGenerator.java 38 7afd8c25c817d7ae49017a651f94fd39a773d5bc main/java/dev/caskeleton/adapter/inbound/web/ratelimit/VersionedEdgeSubjectPseudonymizer.java 45 2d51bee694b2bd6847addf938d7cb54abecf26db main/java/dev/caskeleton/adapter/inbound/web/ratelimit/WebRateLimiter.java 25 817578500dc87cc5d4affbaaafc15243f36ce64f main/java/dev/caskeleton/adapter/inbound/web/webflux/budget/BoundedServerWebExchange.java 79 172eca7694b781fc0a14206f328c92f0ad008d80 main/java/dev/caskeleton/adapter/inbound/web/webflux/budget/WebFluxBudgetFilter.java 122 58b921077cdb445708a87b5083d4b47992925658 main/java/dev/caskeleton/adapter/inbound/web/webflux/throttle/WebFluxThrottleFilter.java 142 ded314b65a8deaa1efffbeb7145f9eea1f26174b test/java/dev/caskeleton/adapter/inbound/web/advanced/ratelimit/RateLimitDraftHeaderWriterTest.java 108 25f51374ee7763c347632ca7cd5904212f220c62 test/java/dev/caskeleton/adapter/inbound/web/budget/WebRequestBudgetTest.java 110 e43e7f9b760ddd43f3a589f0388e816bc0dcb2e6 test/java/dev/caskeleton/adapter/inbound/web/ratelimit/EdgeRateLimitTransportBridgeTest.java 100 6dffb8edee33161a156cd3431ae32b43c55a36e1 test/java/dev/caskeleton/adapter/inbound/web/ratelimit/EdgeRateLimitTransportSettingsTest.java 44 67ec066c7261ab339e0e0d4556420b76508a663b test/java/dev/caskeleton/adapter/inbound/web/ratelimit/RateLimitInterceptorTest.java 178 5b22af742cf30c3729d2e31b8772c7a4a1778d39 test/java/dev/caskeleton/adapter/inbound/web/ratelimit/RateLimitKeyResolverTest.java 99 15168b5a9a2eb38933a71146649141656837d1ae test/java/dev/caskeleton/adapter/inbound/web/ratelimit/RateLimitWebConfigTest.java 35 e01a2ce6cb177dddb3ae3855b1debe3ca04decf1 test/java/dev/caskeleton/adapter/inbound/web/ratelimit/SecureRandomRateLimitEvaluationIdGeneratorTest.java 24 6ec469f04b3dbb6c0da4b5859cc97e777c600ccd test/java/dev/caskeleton/adapter/inbound/web/ratelimit/VersionedEdgeSubjectPseudonymizerTest.java 32 file_count=50 === 8.1 도달성: 네 필터와 admission controller 의 등록 지점 === -- WebMvcBudgetFilter ./testkit/java/dev/caskeleton/webtestkit/BudgetFixtureApplication.java:43: FilterRegistrationBean budgetFilter() { ./testkit/java/dev/caskeleton/webtestkit/BudgetFixtureApplication.java:44: FilterRegistrationBean registration = ./testkit/java/dev/caskeleton/webtestkit/BudgetFixtureApplication.java:46: new WebMvcBudgetFilter( -- WebFluxBudgetFilter ./webfluxContractTest/java/dev/caskeleton/adapter/inbound/web/testkit/budget/ReactiveBudgetFixtureApplication.java:39: return new WebFluxBudgetFilter( -- WebMvcThrottleFilter ./testkit/java/dev/caskeleton/webtestkit/ThrottleFixtureApplication.java:47: FilterRegistrationBean throttleFilter(CountingRateLimiter limiter) { ./testkit/java/dev/caskeleton/webtestkit/ThrottleFixtureApplication.java:48: FilterRegistrationBean registration = ./testkit/java/dev/caskeleton/webtestkit/ThrottleFixtureApplication.java:50: new WebMvcThrottleFilter( -- WebFluxThrottleFilter ./webfluxContractTest/java/dev/caskeleton/adapter/inbound/web/testkit/throttle/ReactiveThrottleFixtureApplication.java:44: new WebFluxThrottleFilter( -- SemaphoreAdmissionController ./testkit/java/dev/caskeleton/adapter/inbound/web/testkit/throttle/ThrottleFixtureSupport.java:39: return new SemaphoreAdmissionController(AdmissionProfile.standard(), writeProfile()); -- WebRateLimiter -- WebBudgetMeter ./main/java/dev/caskeleton/adapter/inbound/web/mvc/budget/WebMvcBudgetFilter.java:56: new WebBudgetMeter(WebBudgetViolation.RESPONSE_TOO_LARGE, budget.maxResponseBytes())); ./main/java/dev/caskeleton/adapter/inbound/web/mvc/budget/WebMvcBudgetFilter.java:62: new WebBudgetMeter(WebBudgetViolation.BODY_TOO_LARGE, budget.maxBodyBytes())), ./main/java/dev/caskeleton/adapter/inbound/web/webflux/budget/WebFluxBudgetFilter.java:103: new WebBudgetMeter(WebBudgetViolation.BODY_TOO_LARGE, budget.maxBodyBytes()) ./main/java/dev/caskeleton/adapter/inbound/web/webflux/budget/BoundedServerWebExchange.java:41: new WebBudgetMeter(WebBudgetViolation.BODY_TOO_LARGE, budget.maxBodyBytes()); ./main/java/dev/caskeleton/adapter/inbound/web/webflux/budget/BoundedServerWebExchange.java:43: new WebBudgetMeter(WebBudgetViolation.RESPONSE_TOO_LARGE, budget.maxResponseBytes()); === 8.2 조건 형제 비교: 두 개의 rate limiting 메커니즘 === $ grep -n 'addInterceptors' -A 3 adapter/inbound/web/src/main/java/dev/caskeleton/adapter/inbound/web/ratelimit/RateLimitWebConfig.java 55: public void addInterceptors(InterceptorRegistry registry) { 56- registry.addInterceptor(rateLimitInterceptor); 57- } 58- exit=0 $ grep -rn 'WebRateLimiter' --include=*.java adapter/inbound/web/src/main | sed 's|.*/web/||' ratelimit/WebRateLimiter.java:16:public interface WebRateLimiter { mvc/throttle/WebMvcThrottleFilter.java:13:import dev.caskeleton.adapter.inbound.web.ratelimit.WebRateLimiter; mvc/throttle/WebMvcThrottleFilter.java:41: private final WebRateLimiter limiter; mvc/throttle/WebMvcThrottleFilter.java:61: WebRateLimiter limiter, webflux/throttle/WebFluxThrottleFilter.java:13:import dev.caskeleton.adapter.inbound.web.ratelimit.WebRateLimiter; webflux/throttle/WebFluxThrottleFilter.java:44: private final WebRateLimiter limiter; webflux/throttle/WebFluxThrottleFilter.java:66: WebRateLimiter limiter, exit=0 === 8.3 WebBudgetCatalog 소비자 === $ grep -rn 'WebBudgetCatalog' --include=*.java adapter/inbound/web/src/main app-bootstrap/src/main | grep -v 'WebBudgetCatalog.java' | sed 's|.*/web/||;s|.*/bootstrap/|BOOT:|' mvc/autoconfigure/WebMvcPlatformAutoConfiguration.java:3:import dev.caskeleton.adapter.inbound.web.budget.WebBudgetCatalog; mvc/autoconfigure/WebMvcPlatformAutoConfiguration.java:66: public WebBudgetCatalog webBudgetCatalog() { mvc/autoconfigure/WebMvcPlatformAutoConfiguration.java:67: WebBudgetCatalog catalog = new WebBudgetCatalog(); webflux/autoconfigure/WebFluxPlatformAutoConfiguration.java:3:import dev.caskeleton.adapter.inbound.web.budget.WebBudgetCatalog; webflux/autoconfigure/WebFluxPlatformAutoConfiguration.java:84: public WebBudgetCatalog webBudgetCatalog() { webflux/autoconfigure/WebFluxPlatformAutoConfiguration.java:85: WebBudgetCatalog catalog = new WebBudgetCatalog(); exit=0 === 8.4 budgets 게이트 프로퍼티가 존재하는가 === $ grep -rn 'backend.web.budgets' --include=*.yml --include=*.yaml --include=*.properties --include=*.java . | sed 's|adapter/inbound/web/src/||' ./webfluxContractTest/java/dev/caskeleton/adapter/inbound/web/testkit/budget/ReactiveWebBudgetIT.java:19: properties = "backend.web.budgets.enabled=true") ./test/java/dev/caskeleton/adapter/inbound/web/testkit/budget/TomcatWebBudgetIT.java:20: properties = "backend.web.budgets.enabled=true") ./main/java/dev/caskeleton/adapter/inbound/web/mvc/budget/WebMvcBudgetExceptionHandler.java:40:@ConditionalOnProperty(prefix = "backend.web.budgets", name = "enabled", havingValue = "true") ./jettyCompatTest/java/dev/caskeleton/adapter/inbound/web/testkit/budget/JettyWebBudgetIT.java:20: properties = "backend.web.budgets.enabled=true") exit=0 $ grep -rn 'BudgetProblemMapper' --include=*.java adapter/inbound/web/src/main app-bootstrap/src/main | grep -v 'BudgetProblemMapper.java' | sed 's|.*/web/||' mvc/budget/WebMvcBudgetFilter.java:7:import dev.caskeleton.adapter.inbound.web.error.BudgetProblemMapper; mvc/budget/WebMvcBudgetFilter.java:32: private final BudgetProblemMapper problems; mvc/budget/WebMvcBudgetFilter.java:43: WebRequestBudget budget, BudgetProblemMapper problems, JsonMapper mapper) { mvc/budget/WebMvcBudgetExceptionHandler.java:4:import dev.caskeleton.adapter.inbound.web.error.BudgetProblemMapper; mvc/budget/WebMvcBudgetExceptionHandler.java:28: *

Both paths produce the document through the same {@link BudgetProblemMapper}, so which one mvc/budget/WebMvcBudgetExceptionHandler.java:37:// Gated on a property rather than on the BudgetProblemMapper bean, for the same reason: on a mvc/budget/WebMvcBudgetExceptionHandler.java:44: private final BudgetProblemMapper problems; mvc/budget/WebMvcBudgetExceptionHandler.java:51: public WebMvcBudgetExceptionHandler(BudgetProblemMapper problems) { webflux/budget/WebFluxBudgetFilter.java:7:import dev.caskeleton.adapter.inbound.web.error.BudgetProblemMapper; webflux/budget/WebFluxBudgetFilter.java:39: private final BudgetProblemMapper problems; webflux/budget/WebFluxBudgetFilter.java:50: WebRequestBudget budget, BudgetProblemMapper problems, JsonMapper mapper) { exit=0