Enterprise Work Experience · 2023 – 2026

Enterprise HR Platform

대기업 그룹사가 사용하는 통합 인사(HR) 시스템. 3년간 채용·승진·건강검진 도메인 신규 구축부터 레거시 Spring → Spring Boot 3.5 플랫폼 현대화, OCR·LLM·RAG 챗봇 등 AI 기능 실무 도입까지 백엔드 중심 풀스택으로 수행. 커밋 4,491건 · 참여 업무 250건.

Java 11→25Spring Boot 2.7→3.5Spring Security 6JPA·QueryDSLMyBatisVue 3ElasticsearchLLM·RAGSSEOCR

3년간의 핵심 기여

도메인 시스템 신규 구축, 플랫폼 현대화, AI 기능 실무 도입까지 — 운영 중인 엔터프라이즈 시스템의 전 영역

채용 시스템 신규 구축

입사 후 첫 프로젝트로 채용 관리자 시스템을 처음부터 구축. JPA/QueryDSL 데이터 접근 기반과 전역 예외 처리·공통 응답·Audit 등 공통 인프라 골격을 설계하고, 오픈 후 4개월 운영 안정화까지 완주.

승진 시스템 신규 개발

기준관리부터 추천 플로우까지 승진 시스템을 신규 개발하고 3차 QA를 거쳐 오픈. 이듬해 기준 테이블 재설계, 근태·발령 연동, AI 추천사유 요약 등 대규모 개선을 주도.

플랫폼 현대화

레거시 Spring → Spring Boot 2.7 전환(커밋 267건)으로 발판을 만들고, Java 25 + Spring Boot 3.5 + jakarta 마이그레이션까지. OpenRewrite 자동 변환 후 3,184건 전수 테스트로 회귀 검증.

AI 기능 실무 도입

영수증 OCR + LLM 판독을 시작으로 면접관 AI 질의 채팅, 프롬프트 캐싱·전략 패턴 공통화, SSE 기반 LLM Tool Calling까지. 자연어로 일정을 일괄 입력하는 "AI 채우기" 기능 구현.

VOC RAG 챗봇

사내 문의 지식으로 답하는 RAG 챗봇을 E2E 구축. BM25+kNN 하이브리드 검색(RRF), 권한 기반 ACL fail-closed 필터, SSE 스트리밍, 미답변 적재로 지식이 성장하는 루프. TDD로 진행.

인증·보안 현대화

Keycloak Adapter → Spring Security OAuth2 Resource Server 마이그레이션, SecurityContext 자식 스레드 전파 복구, 레거시 XSS 필터 제거, 보안검수 대응까지 인증·보안 체계 정비.

아키텍처 하이라이트

01

점진적 플랫폼 현대화

운영 중인 인사 시스템을 멈추지 않고 레거시 Spring → Boot 2.7 → Boot 3.5(Java 25, Security 6)로 단계적 전환. javax 전용 사내 라이브러리는 바이트코드 변환으로 호환 처리.

Legacy Spring → Boot 2.7 → Boot 3.5 · javax → jakarta
02

JPA 쿼리 런타임 핫스왑 프레임워크

배포 없이 운영 중 JPA/QueryDSL 쿼리를 교체하는 AOP 기반 오버라이드 프레임워크를 설계·구현(커밋 100건). dry-run 롤백 격리, 변경 쿼리(@Modifying) 차단, TTL 최대 2주 클램프 등 다층 안전장치. 쿼리는 저장 시점에 컴파일 타입 체크로 검증하고, 브로커로 전 서버 메모리에 동기화.

AOP override · dry-run rollback · TTL clamp
03

AI 채팅 인프라의 단계적 발전

면접관 질의 채팅방 → 스트리밍/UX 개선 → 전략 패턴 공통화 + 프롬프트 캐싱 → SSE 기반 Tool Calling. 한 번 만든 인프라를 "AI 채우기", VOC 챗봇 등 타 도메인이 재사용.

Strategy Pattern · Prompt Caching · SSE tool_call
04

VOC RAG 파이프라인

질의 재작성(공식 용어 변환) → ACL 티어 리졸버(fail-closed) → Elasticsearch BM25+kNN 하이브리드 검색(RRF) → 근거 기반 답변 생성 → SSE 스트리밍(근거 선행 전송). 근거 부족 시 후퇴하고 미답변으로 적재.

rewrite → ACL → hybrid search(RRF) → generate → SSE
05

Vue 3 Island 점진 도입

JSP 레거시 화면을 전면 재작성하는 대신 화면 단위로 Vue 3를 얹는 island 패턴 정착. 공통 컴포넌트·다국어 props 체계를 만들고, 건강검진 개편에서 Vue 3 + 상용 그리드 하이브리드 관리자 화면으로 확장.

JSP + Vue 3 island · 화면 단위 점진 전환
3
Years
4,491
Commits
250
Tasks
3,184
Regression Tests
63s→11s
No-op Build
-33%
Log Noise

기술적 의사결정

DECISION 01

왜 빅뱅 재작성이 아닌 점진적 현대화인가

운영 중인 인사 시스템은 중단이 불가능. Boot 2.7 전환으로 발판을 만들고, 인증·테스트 체계를 먼저 정비한 뒤 Boot 3.5로 마이그레이션. 단계마다 전수 회귀 테스트로 검증하며 리스크를 분할.

DECISION 02

왜 JPA 쿼리 런타임 핫스왑인가

운영 장애 시 쿼리 한 줄 수정에도 배포가 필요했음. 배포 없이 쿼리를 교체하는 프레임워크로 대응 시간을 단축하되, dry-run 롤백 격리·@Modifying 차단·TTL 클램프로 오남용을 다층 차단.

DECISION 03

왜 BM25 + kNN 하이브리드(RRF)인가

사내 용어·코드명 질의는 키워드 매칭(BM25)이, 자연어 질문은 의미 검색(kNN)이 강함. 단일 방식은 반쪽 — RRF로 두 순위를 융합해 양쪽 질의 유형을 모두 커버.

DECISION 04

왜 ACL fail-closed인가

인사 데이터는 잘못 노출되면 파급이 큼. 챗봇 검색 필터에서 권한 판단이 불가능한 경우 기본값을 "노출"이 아닌 "차단"으로 설계. 편의보다 안전을 우선.

DECISION 05

왜 Vue Island 패턴인가

JSP 전면 재작성은 리스크와 비용이 과다. 화면 단위로 Vue 3를 점진 도입해 신규·개편 화면부터 현대화하고, 레거시와 신규 스택이 공존 가능한 구조 선택.

DECISION 06

빌드 63초 → 11초: APT 플러그인 교체

QueryDSL apt-maven-plugin이 변경 없는 빌드에도 전체 어노테이션 프로세싱을 재실행. annotationProcessorPaths로 교체해 no-op 빌드를 63초에서 11초로 단축.

실전 트러블슈팅

TROUBLESHOOT 01

운영 ajax 산발 401의 근본 원인 규명

문제 정의

운영 환경에서 ajax 요청이 간헐적으로 401을 반환. 재현이 되지 않아 장기간 원인 미상으로 남아 있던 문제.

원인 추적

curl 재현 스크립트 + ELK 로그 분석으로 시나리오 구성. 동시 요청의 세션 읽기 miss와, 401 응답이 내려주는 익명 세션 쿠키가 이후 정상 요청까지 오염시키는 증폭 구조를 입증.

핵심 설계

추측성 패치가 아니라 로그로 입증된 두 원인을 각각 수정 — 세션 읽기 경합 보완 + 401 응답의 익명 세션 쿠키 발급 차단.

결과

산발 401 재발 제로. "재현 불가" 장애를 로그 근거로 입증·수정한 사례.

TROUBLESHOOT 02

라이브러리 상향 후 엑셀 전면 장애 복구

문제 정의

보안 이슈로 POI 3.9 → 4.1.2 상향 후, 소스 수정이 불가능한 상용 그리드 서버모듈과의 바이너리 비호환으로 엑셀 다운로드가 전면 장애.

핵심 설계

벤더 모듈을 바이트코드 호환 패치로 처리해 90개 화면 복구. 동일 유형의 잠재 위험을 전수 audit하고 회귀 테스트로 재발 방지.

결과

전면 장애를 소스 접근 없이 복구. 의존성 상향의 영향 범위를 전수 검증하는 절차 확립.

TROUBLESHOOT 03

운영 로그를 "증거"로 만들기 — 노이즈 정리 + 요청 추적

문제 정의

운영 로그가 프레임워크 DEBUG·헬스체크·정적 리소스 노이즈로 가득 차 ERROR 추적이 사실상 불가능. 예외 1건이 스택트레이스 3회 중복 출력되고, 어떤 로그가 어떤 요청의 것인지 알 수 없었음.

핵심 설계

모든 로그 라인에 요청 단위 traceId + 사용자 ID(MDC) 삽입, TaskDecorator로 비동기 스레드까지 MDC 전파. 노이즈 로거 레벨 정리, 헬스체크·정적 리소스 access log 제외, 예외 로깅 3회→1회 단일화, 인증 토큰 마스킹 유틸로 PII 보호.

결과

운영 로그 평일 기준 약 33% 감축. 장애 시 응답 헤더의 traceId 하나로 ELK에서 요청 진입→SQL→예외→종료를 시간순 추적 — CS/QA도 직접 조회 가능한 체계.

TROUBLESHOOT 04

라이브러리 업그레이드 후 캐시 클리어 무동작 규명

문제 정의

spring-data-redis 버전 업그레이드 후 캐시 클리어가 아무리 실행해도 동작하지 않는 회귀 발생. 에러도 없이 조용히 실패해 원인 단서가 없었음.

원인 추적

삭제 로직이 zRange로 "캐시명~keys" Sorted Set을 조회하고 있었는데, 이는 구버전 RedisCacheManager가 자동 생성해주던 키 인덱스였음. 라이브러리 소스를 버전별로 추적해 신버전에서 이 구조가 사라졌음을 규명.

핵심 설계

keys()가 아닌 scan() 패턴 조회로 삭제 로직 재구현 — 싱글 스레드 Redis에서 keys()는 전체 조회가 끝날 때까지 다른 명령을 블로킹하므로, 명령을 분할하는 scan()을 선택.

결과

캐시 클리어 정상화. "라이브러리가 해주던 일"을 소스 레벨에서 확인하고, 운영 Redis에 안전한 방식으로 대체하는 접근을 정착.