인프라
백엔드는 여러 플랫폼 서비스를 의존하지만, 여전히 하나의 Spring Boot 애플리케이션으로 실행됩니다. 이 페이지는 코드 동작을 형성하는 백엔드 관점의 런타임 계약을 다룹니다. 클러스터 운영이나 day-2 runbook은 의도적으로 다루지 않습니다.
이 페이지는 레퍼런스 문서입니다.
소스 경로
| 경로 | 역할 |
|---|---|
app/src/main/resources/application.yaml | 데이터 소스, Flyway, Redis, RabbitMQ, MinIO, 워커 URL, CORS, rate limit, OpenAPI, actuator를 포함한 주 런타임 설정 |
app/src/main/resources/application-dev.yml | 쿠키 SameSite 같은 dev 전용 재정의 |
app/src/main/java/com/lumie/app/config/RoutingDataSourceConfig.java | primary/readonly Hikari pool과 Flyway migrator data source |
app/src/main/java/com/lumie/app/config/RuntimeDbRoleGuard.java | RLS를 우회할 수 있는 DB role을 막는 startup guard |
app/src/main/java/com/lumie/app/config/ShedLockConfig.java | 분산 scheduler locking |
app/src/main/java/com/lumie/app/config/CorsConfig.java | CORS 계약 |
app/src/main/java/com/lumie/app/config/ratelimit/RateLimitFilter.java | 프로세스 내부 rate limiting |
modules/exam/src/main/java/com/lumie/exam/adapter/out/config/* | exam 모듈이 소유하는 RabbitMQ, RestClient, MinIO 인프라 |
modules/auth/src/main/java/com/lumie/auth/adapter/out/persistence/RedisTokenRepository.java | auth의 Redis persistence 계약 |
modules/file/src/main/java/com/lumie/file/adapter/out/storage/MinioStorageAdapter.java | file-service object storage 계약 |
modules/billing/src/main/java/com/lumie/billing/adapter/out/external/* | billing의 외부 제공자 adapter |
런타임 토폴로지
의존성 계약
| 의존성 | 구 성 인터페이스 | 주요 백엔드 소유자 | 계약 메모 |
|---|---|---|---|
| PostgreSQL | app.datasource.*, spring.flyway.* | 모든 모듈 | shared-schema RLS, Modulith outbox, ShedLock, primary/readonly pool |
| RabbitMQ | spring.rabbitmq.* | 주로 exam | queue 기반 grading 및 report 워크플로 |
| Redis | spring.data.redis.* | 주로 auth | refresh 토큰, blacklist, 세션 index |
| MinIO | minio.* | exam, file, tenant | OMR object, presigned upload, 파일 메타데이터, 테넌트 logo |
grading-svc | lumie.services.grading.url | exam | 직접 HTTP grading과 queue 콜백 생태계 |
report-svc | lumie.services.report.url | exam | 직접 HTTP report 생성과 queue 콜백 생태계 |
chatbot-svc | lumie.services.chatbot.url | ai | 외부로는 HTTP streaming proxy, 내부로는 HMAC 콜백 인터페이스 |
| Toss Payments | billing config와 제공자 secret | billing | 실제 구현된 HTTP integration |
| Popbill tax invoice path | billing config와 제공자 secret | billing | 현재 코드는 완전한 실서비스 연동이 아니라 stub adapter |
데이터베이스 및 마이그레이션 인프라
읽기/쓰기 분리
RoutingDataSourceConfig는 다음을 선언합니다.
app.datasource.primary.*app.datasource.readonly.*LazyConnectionDataSourceProxy로 감싼RoutingDataSource
라우팅 규칙:
@Transactional(readOnly = true)-> readonly pool- write transaction 또는 비트랜잭션 접근 -> primary pool
Flyway는 별도 자격 증명으로 실행됨
Flyway는 런타임 애플리케이션 pool credential을 사용하지 않습니다.
백엔드는 primary URL과 spring.flyway.user/password로 전용
@FlywayDataSource를 만들기 때문에, DDL은 table 소유 권한으로 실행하고
런타임 트래픽은 제한된 lumie_app role에 머무를 수 있습니다.
런타임 DB 역할 가드
RuntimeDbRoleGuard는 활성 런타임 role이 다음 중 하나면 startup을
실패시킵니다.
SUPERUSERBYPASSRLS
이것은 운영 취향이 아니라 백엔드 안전 불변식입니다.
비동기 및 스케줄러 인프라
- Spring Modulith는
public.event_publication에 outbox row를 저장 spring.modulith.events.completion-mode=deletespring.modulith.events.republish-outstanding-events-on-restart=true- ShedLock은
public.shedlock사용 @EnableAsync가 애플리케이션에 켜져 있고, Spring이 관리하는 async 실행은 테넌트-aware task decorator를 받음
중요한 경계 세부사항:
- Spring이 관리하는 async 작업은 컨텍스트 전파를 자동으로 받음
- AI 모듈의 전용 chat executor 같은 custom executor는 context를 수동으로 다시 세팅해야 함
오브젝트 스토리지와 외부 HTTP
MinIO
exam은 두 개의 MinIO client를 사용합니다. 하나는 internal 엔드포인트용, 다른 하나는minio.external-endpoint를 쓰는 presign 클라이언트입니다.file은 업로드, 다운로드, presigned URL에 MinIO를 사용합니다.tenant는 logo object에 MinIO를 사용합니다.FileServiceAdapter는 database 커밋 이후에만 MinIO object를 삭제합니다.
워커 및 제공자 HTTP
exam은 외부 호출 로깅과 명시적 timeout이 있는RestClient를 사용합니다.OmrServiceClient는 읽기 타임아웃을90s로 재정의합니다.ai는 uvicorn 호환성을 위해chatbot-svc트래픽을 HTTP/1.1에 고정합니다.- billing 제공자 호출은 의도적으로 긴 트랜잭션 바깥에 둡니다.
HTTP 인터페이스와 백엔드 가드
application.yaml과 app config 기준:
- OpenAPI:
/v3/api-docs - Swagger UI:
/swagger-ui.html - CORS origin: production, dev, 그리고 로컬
http://localhost:3000 - multipart 제한: 파일당
5MB, 요청당25MB - graceful shutdown timeout:
30s - actuator 노출:
health,info,prometheus,metrics - 선택된
POSTroute에 대한 per-IP 프로세스 내부 rate limiting
RequestContextFilter는 또한 다음을 제공합니다.
- 생성되거나 전달된
X-Request-Id - request ID, 테넌트, user, 선택적 trace ID에 대한 MDC 채움
현재 드리프트와 유의사항
- billing 모듈에는 실제 Toss integration이 있지만,
PopbillTaxInvoiceClient는 여전히 synthetic success 응답을 반환하고 warning을 남기는 stub입니다. - RabbitMQ topology는 백엔드 Java config에서 선언되지 않습니다. 백엔드 코드는 queue와 policy가 이미 존재한다고 가정하고 application layer bean만 연결합니다.
검증 명령어
cd /Users/bluemayne/Projects/Lumie/lumie-backend
./gradlew :app:test
./gradlew :modules:exam:test
./gradlew :modules:auth:test
./gradlew integrationTest
가장 관련 있는 테스트:
app/src/test/java/com/lumie/app/config/RoutingDataSourceIntegrationTest.javaapp/src/test/java/com/lumie/app/config/RuntimeDbRoleGuardTest.javaapp/src/test/java/com/lumie/app/migration/MigrationsRlsIntegrationTest.java