배우고, 기록하고, 성장합니다 | GitHub

$ls -la ./tags/Spring Boot

#Spring Boot

31 posts

운영 중인 서비스를 왜 지금 리팩토링하기로 했나

운영 중인 서비스를 왜 지금 리팩토링해야 했는지, 그리고 왜 전면 재작성 대신 점진적 전환을 선택했는지를 정리합니다.

왜 Spring Boot, Gradle, React Router v7로 방향을 정했나

왜 Spring Boot, Gradle, React Router v7 SSR을 선택했고, 왜 /backend와 /frontend 구조를 먼저 만들었는지 정리합니다.

Gradle 전환과 미사용 코드 정리부터 시작한 이유

왜 코드 개선보다 먼저 Gradle 전환과 미사용 코드 정리부터 시작했는지, 그리고 그 순서가 왜 중요했는지 정리합니다.

Spring Boot 시작하기

Spring Boot로 웹 애플리케이션을 시작하는 방법을 소개합니다. 프로젝트 생성부터 간단한 API 구현까지 다룹니다.

Spring Boot 예외 처리 전략 - @ExceptionHandler와 @ControllerAdvice

Spring Boot에서 전역 예외 처리를 구현하는 방법을 정리합니다. 커스텀 예외와 에러 응답 표준화를 다룹니다.

Spring Security + JWT 인증 구현하기

Spring Security와 JWT를 활용하여 토큰 기반 인증을 구현합니다. Access Token과 Refresh Token 전략을 다룹니다.

2026.02.27

JPA N+1 문제 해결과 쿼리 최적화

JPA에서 자주 발생하는 N+1 문제의 원인과 해결 방법을 정리합니다. Fetch Join, EntityGraph, BatchSize를 활용한 최적화 전략을 알아봅니다.

2026.02.25

JPA 엔티티 매핑 - 연관관계 설정과 영속성 컨텍스트

JPA의 엔티티 매핑과 연관관계 설정 방법을 정리합니다. 영속성 컨텍스트의 동작 원리를 이해합니다.

2026.02.22

GitHub Actions로 CI/CD 파이프라인 구축하기

GitHub Actions를 활용하여 Spring Boot 프로젝트의 빌드, 테스트, 배포를 자동화하는 방법을 알아봅니다.

2026.02.18

Docker Compose로 멀티 컨테이너 환경 구성하기

Docker Compose를 활용하여 여러 컨테이너를 한 번에 관리하는 방법을 알아봅니다. Spring Boot + MySQL 환경을 예제로 구성합니다.

프로젝트 회고: 잘한 설계, 아쉬운 설계

클린 아키텍처로 문서 분석 시스템을 구축하면서 내린 설계 결정들을 돌아봅니다. 잘한 것과 아쉬운 것을 솔직하게, 그리고 다시 만든다면 무엇을 바꿀지 이야기합니다.

QueryDSL로 복잡한 동적 검색 쿼리 설계하기

상태, 카테고리, 날짜 범위, 도메인을 조합하는 복잡한 동적 검색 요구사항을 QueryDSL로 해결하고, 소프트 딜리트와 인덱스 설계까지 고민한 경험을 공유합니다.

Dead Letter Queue로 장애를 설계 레벨에서 대비하기

외부 API 호출 실패를 조용히 삼키지 않고, Dead Letter Queue 패턴과 Google Chat 알림으로 운영 가시성을 확보한 경험을 공유합니다.

느리고 큰 외부 API 응답, 스트리밍으로 처리하기

AI 분석 API의 느린 응답을 Reactor의 Flux 스트리밍으로 처리하고, AbstractApiClient 추상 클래스로 공통 관심사를 분리한 경험을 공유합니다.

Redis Streams로 비동기 분석 파이프라인 설계하기

Kafka, RabbitMQ, Redis Streams 중 Redis Streams를 선택한 이유와 트레이드오프, TransactionalEventListener로 데이터 정합성을 지키는 방법, Consumer Group으로 at-least-once를 보장하는 구조를 정리합니다.

Port & Adapter 패턴으로 외부 스토리지 연동하기

파일 업로드/다운로드 설계에서 Presigned URL 방식을 선택한 이유와, FileStorage 인터페이스(Port)와 CephFileStorage(Adapter)로 기술 독립성을 확보한 과정을 정리합니다.

상태 머신을 도메인 객체로 표현하는 방법

AnalysisStatus와 AnalysisStep Enum으로 분석 파이프라인의 상태 전이 규칙을 캡슐화한 설계를 소개합니다. 정보전문가 패턴과 상태 머신을 결합해 잘못된 상태 전이를 도메인 수준에서 차단하는 방법을 다룹니다.

멀티 모듈 프로젝트, 왜 클린 아키텍처로 시작했나

Spring Boot 3.5 + Java 21 기반 문서 분석 시스템을 설계하면서 클린 아키텍처와 Gradle 멀티 모듈 구조를 선택한 이유와 그 과정을 정리했습니다.

멀티 모듈 Gradle로 공통 모듈 분리와 의존성 설계하기

SofacApiResponse를 복붙했다가 한 달 만에 응답 포맷이 달라져 API 클라이언트가 깨진 경험, 그리고 commons/support 멀티 모듈로 정리한 과정

2025.06.09

BaseAuditing 계층 설계: Soft Delete부터 MemberContext까지

BaseEntity를 복사해 쓰다가 동기화 실패, MemberContext clear() 누락으로 메모리 누수까지 겪은 뒤 공통 모듈로 추출한 이야기

Reader/Writer 패턴으로 가볍게 시작하는 CQRS

공고 목록 3초 로딩과 151개 쿼리를 겪고, Repository를 Reader/Writer로 분리해 200ms까지 줄인 이야기

주문/결제 이중 상태 머신과 트랜잭션 분리 전략

OrderStatus 5개로 시작했다가 환불 요구사항에 8개로 늘리고, PG 승인-주문 상태 불일치 사고를 겪은 뒤 트랜잭션을 분리한 이야기

PaymentEvent 이벤트 소싱과 PaymentDetail 다형성

결제 상태만 저장했다가 고객 문의를 못 풀게 된 뒤, 모든 상태 변화를 이벤트로 기록하게 된 이야기

Toss Payments 연동: 3계층 구조와 에러 처리 전략

PG 연동 코드를 UseCase에 직접 넣었다가 테스트 불가능해진 뒤, 3계층으로 분리하고 에러 처리를 체계화한 이야기

Domain Model과 JPA Entity를 분리한 이유

OrderEntity에 비즈니스 로직을 넣었다가 테스트가 지옥이 되어, 도메인 모델을 따로 빼게 된 이야기

임시 주문 → 실주문 2단계 결제 모델 설계하기

주문 테이블 하나로 시작했다가 PENDING 주문 폭탄을 맞고, TemporaryOrder를 분리하게 된 이야기

Kakao AlimTalk 연동기: Port & Adapter로 외부 API 깔끔하게 감싸기

UseCase에 HTTP 호출을 직접 넣었다가 타임아웃이 트랜잭션을 롤백시킨 뒤, Port & Adapter로 분리한 이야기

2024.10.21

순환 의존을 이벤트로 끊은 이야기 — Aggregate 간 통신 패턴

Posting과 Step 사이의 순환 의존, 결제 완료 후 장바구니 상태 변경 등 서로 다른 Aggregate 간 이벤트 기반 통신의 실전 경험

2024.10.07

지원 한 번에 리스너 10개가 반응한다 — 부수효과 실전 해부

지원자 온라인 지원 시 발생하는 중복 체크, 이메일, 알림톡, Meta 동기화, 통계 업데이트까지 이벤트 리스너의 실전 코드를 해부한다

2024.09.23

검색에서 지원자가 사라졌다 — BEFORE_COMMIT vs AFTER_COMMIT 삽질기

ApplicantMeta가 간헐적으로 생성되지 않는 버그를 추적하면서 배운 @TransactionalEventListener의 트랜잭션 페이즈 전략

2024.09.09

80줄짜리 UseCase를 15줄로 줄인 이야기 — 도메인 이벤트 도출기

지원자 등록 UseCase가 비대해지면서 겪은 문제와, 도메인 이벤트로 부수효과를 분리하기까지의 과정