Files
tasteby/backend-java/build.gradle
joungmin 319fd18258 feat(stats): #337 봇 UA 필터 + IP 레이트리밋
- BotDetector 유틸 (Pattern.CASE_INSENSITIVE: bot|crawler|spider|slurp|scrap|fetch|monitor|preview|lighthouse)
- RateLimitService: Redis SET NX EX(60s) 패턴으로 같은 IP 윈도우 차단
  - Bucket4j 대신 spring-data-redis 기존 의존성 재사용 (간결)
  - Redis 다운 시 fail-open (사용자 경험 우선)
- StatsController.recordVisit: HttpServletRequest 받아 UA + X-Forwarded-For 우선 IP
  - 봇/리밋 초과 → 200 + counted:false (사용자 페이지 로드 지장 X)
  - 통과 → 200 + counted:true → statsService.recordVisit()
- application.yml: app.rate-limit.visit-window-seconds (env VISIT_WINDOW_SECONDS) 기본 60
- dev 검증: 봇 UA → counted=false, Mozilla → true, 즉시 재호출 → false

설계서: docs/design/337-stats-bot-ratelimit/README.md

Refs: #337 (Developer 단계)
2026-06-15 15:26:27 +09:00

78 lines
2.7 KiB
Groovy

plugins {
id 'java'
id 'org.springframework.boot' version '3.3.5'
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'com.tasteby'
version = '0.1.0'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
repositories {
mavenCentral()
}
dependencies {
// Spring Boot
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-security'
// MyBatis
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.4'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-validation'
// #335 — 분산 락 (RollingUpdate 시 멀티 파드 공존 중 데몬 중복 실행 차단)
implementation 'net.javacrumbs.shedlock:shedlock-spring:5.16.0'
implementation 'net.javacrumbs.shedlock:shedlock-provider-redis-spring:5.16.0'
// #337 — IP 레이트리밋은 Redis SET NX EX 패턴으로 자체 구현 (기존 spring-data-redis 활용)
// Oracle JDBC + Security (Wallet support for Oracle ADB)
implementation 'com.oracle.database.jdbc:ojdbc11:23.7.0.25.01'
implementation 'com.oracle.database.security:oraclepki:23.7.0.25.01'
// JWT
implementation 'io.jsonwebtoken:jjwt-api:0.12.6'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6'
// Google OAuth2 token verification
implementation 'com.google.api-client:google-api-client:2.7.0'
// OCI SDK (GenAI for LLM + Embeddings)
implementation 'com.oracle.oci.sdk:oci-java-sdk-generativeaiinference:3.49.0'
implementation 'com.oracle.oci.sdk:oci-java-sdk-common:3.49.0'
implementation 'com.oracle.oci.sdk:oci-java-sdk-common-httpclient-jersey3:3.49.0'
// Jackson for JSON
implementation 'com.fasterxml.jackson.core:jackson-databind'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
// YouTube Transcript API (Java port of youtube-transcript-api)
implementation 'io.github.thoroldvix:youtube-transcript-api:0.4.0'
// Playwright (browser-based transcript fallback)
implementation 'com.microsoft.playwright:playwright:1.49.0'
// HTTP client for YouTube/Google APIs
implementation 'org.springframework.boot:spring-boot-starter-webflux'
// Lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
// Test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}