[TIL] OncePerRequestFilter — 서블릿 필터 구현 패턴

Spring의 OncePerRequestFilter로 요청당 1회만 실행되는 서블릿 필터를 만드는 방법, shouldNotFilter()로 경로를 선택 적용하고 doFilterInternal()에서 체인을 이어가는 패턴을 정리한 글이다.

Spring에서 커스텀 필터를 만들 때 Filter를 직접 구현하면 forward/include 시 같은 요청에 필터가 여러 번 돌 수 있다. OncePerRequestFilter를 쓰면 요청당 한 번만 실행되고, shouldNotFilter()로 특정 경로를 건너뛰며, doFilterInternal()에서 검증 후 filterChain.doFilter()로 체인을 이어갈 수 있다.

[TIL] @ConfigurationProperties + @Validated — 설정값 검증과 fail-fast

@ConfigurationProperties와 @Validated로 설정값을 앱 시작 시 검증하는 방법, ${ENV_VAR}와 ${ENV_VAR:default}의 차이, 운영 환경에서 fail-fast로 배포 실패를 앞당기는 이유를 정리한 글이다.

운영 환경변수가 빠져 있어도 앱이 뜨고, 첫 요청에서야 터지는 상황은 디버깅 비용이 크다. @ConfigurationProperties@Validated를 붙이고 @NotBlank로 필수값을 선언하면, 배포 직후 시작 단계에서 바로 실패(fail-fast)시킬 수 있다.

[TIL] Spring Boot Actuator - 운영 노출 범위 제어

Spring Boot Actuator 엔드포인트를 운영 환경에 그대로 노출할 때 발생하는 보안 위험과, health 중심 최소 노출 원칙, 환경별 분리 설정, 네트워크/시큐리티 방어층까지 한 번에 정리한 글이다.

Spring Boot Actuator는 운영 관측에 매우 유용하지만, /actuator/env, /actuator/heapdump, /actuator/beans 같은 엔드포인트를 외부에 열어두면 민감 정보 유출로 이어질 수 있다. 운영에서는 필요한 최소 엔드포인트만 노출하고, 애플리케이션/네트워크/인증 계층에서 방어를 겹겹이 두는 것이 안전하다.

[TIL] null과 0은 다르다 — API에서 “데이터 없음”과 “값이 0”을 구분하는 법

API에서 미분석(null·무효 입력)과 분석 완료 후 점수 0을 구분하지 못해 생기는 조용한 버그, 변환 전 유효성 검증·JSON 직렬화·집계 분모 처리까지 정리한 글이다.

📝 TIL (Today I Learned)
null이나 빈 맵을 모두 Map.of()로 흡수하면, 미분석·점수 누락·합계 0인 분석이 한데 섞인다. 변환 전에 isValidScoreMap()으로 걸러내고, 무효면 null을 유지하면 집계·UI에서 의미가 살아난다.

[친구하자] JPQL에서 매핑되지 않은 관계의 LEFT JOIN 한계

Call과 CallEmotionResult를 SQL처럼 LEFT JOIN하고 싶지만 표준 JPQL은 연관관계 기반 JOIN이 기본이라 막히는 문제, Hibernate HQL 확장과의 차이, 네이티브 쿼리·두 쿼리 분리 후 Java 병합, 구현 시 주의점까지 정리합니다.

CallCallEmotionResult를 SQL처럼 LEFT JOIN하고 싶은데, 표준 JPQL은 연관 경로가 없으면 객체 그래프 기반 조인을 쓰기 어렵다. Hibernate HQL은 버전에 따라 엔티티 JOIN … ON이 열리기도 하지만 포터빌리티와 트레이드오프가 있다. SQL·JPQL의 차이와, 우리가 택한 두 쿼리 + 병합, 구현 시 주의점까지 정리한다.

[친구하자] JPA @Modifying(clearAutomatically = true)의 함정

@Modifying(clearAutomatically = true) 사용 시 영속성 컨텍스트가 비워지면서 엔티티가 detached 되어, 상태 변경이 DB에 반영되지 않았던 버그 원인과 해결 과정을 정리합니다.

정기 예약 취소 API에서 CallReservation은 정상적으로 취소되는데 RecurringReservation 상태만 ACTIVE로 남는 버그를 겪었다. 원인은 @Modifying(clearAutomatically = true)로 인해 영속 엔티티가 detached 된 뒤 상태를 변경한 것이었다.

[친구하자] 백분율을 정확히 100%로 만드는 방법 — Largest Remainder Method

감정 분석 API에서 7가지 감정 점수를 소수점 둘째 자리 백분율로 보여주되 합계는 반드시 100.00%가 되게 하는 문제, 반올림 함정과 Largest Remainder Method(최대 잔여 방식) 해법, 구현 시 부동소수점·동점 처리 등을 정리합니다.

감정 분석 API를 만들면서 “각 항목은 소수점 둘째 자리로 보이게 하되, 합계는 반드시 100.00%”라는 요구를 만났다. 단순 반올림과 흔한 보정 방식의 함정, 최대 잔여 방식(Largest Remainder, Hamilton 방식으로도 알려짐)으로 맞춘 과정과 구현 시 체크 포인트를 정리한다.

[TIL] 트랜잭션 이벤트 발행 타이밍 문제 — @TransactionalEventListener vs publishEvent() (#196)

트랜잭션 커밋 전 publishEvent()를 호출했을 때 발생한 타이밍 문제와 @TransactionalEventListener(AFTER_COMMIT)afterCommit() 해결 방식을 정리한 글이다.

📝 TIL (Today I Learned)
@Transactional 안에서 publishEvent()를 호출하면 @Async 리스너가 커밋 전 데이터를 읽으려다 실패할 수 있다. 이 문제는 TransactionSynchronizationManager.afterCommit() 또는 @TransactionalEventListener(AFTER_COMMIT)로 해결한다.

[TIL] 트랜잭션·Redis 정합성, TOCTOU, 보상 트랜잭션 — #150에서 배운 백엔드 포인트

DB 트랜잭션과 Redis 정합성, TOCTOU 경쟁 조건, self-invocation, 보상 트랜잭션, DB UPDATE를 활용한 뮤텍스 등 #150 구현에서 정리한 백엔드 핵심 포인트입니다.

📝 TIL (Today I Learned)
DB 트랜잭션과 외부 시스템(Redis)이 함께 움직일 때, “원자성”과 “정합성”을 어떻게 지켜야 하는지 #150 구현에서 다시 정리했다.

[TIL] Spring Events, @Async, Redis, STOMP — #148·#149에서 배운 백엔드 포인트

Spring Events(@TransactionalEventListener, AFTER_COMMIT), @Async와 LazyInitializationException, Redis ZSET·Lua·TOCTOU, STOMP WebSocket 사용자별 전송, 스케줄러 설계 등 #148·#149 구현에서 정리한 백엔드 포인트입니다.

📝 TIL (Today I Learned)
트랜잭션 경계를 이해하고, Redis에서 원자성을 보장하며, WebSocket 세션 상태를 고려한 분산 환경의 실시간 알림을 다루면서 정리한 내용이다.

Pagination