← 사이트로

A4 세로 기준으로 조판되어 있습니다. 인쇄 대화상자에서 여백 없음 · 배경 그래픽 켜기를 선택하면 화면과 같게 저장됩니다.

박동진

Backend Developer

다양한 개발 경험을 바탕으로, 정량적으로 설계하고 합리적으로 구현합니다.

Selected Outcomes

TPS 175 → 1,568

로그인 처리량 +796%

부하 테스트로 지연의 97%가 외부 IdP 호출임을 규명하고 Redis 토큰 캐시를 도입

38.1% → 76.2%

RAG 정답 핵심내용 포함률

청크 1,500토큰이 컨텍스트 윈도우를 초과하던 문제를 골든셋 평가로 특정

lock 1.5s · stmt 5s

운영 DB 경합 차단 설계

advisory lock 으로 중복 실행을 막고 짧은 timeout 으로 fast-fail 하도록 설계

Projects

Auto Translator 2026 · 실무 LLM 다국어 번역을 "검수 가능한 운영 작업"으로 다루는 번역 콘솔입니다. AI 초안을 바로 DB 에 쓰지 않고, 검증·검수·이관 단계를 거쳐 반영합니다.
First Ticket 2026.04 - 2026.05 · 팀 프로젝트 매크로·동시 접속·중복 예매 문제를 해결하는 MSA 티켓 예매 플랫폼입니다. 6인 백엔드 팀에서 User/Auth 도메인과 API Gateway, Eureka Service Discovery 를 설계·구현했습니다.
Personal RAG 2026.02 - 2026.03 · 개인 프로젝트 각종 문서를 개인 PC 안에서 처리하는 로컬 RAG 챗봇. 로컬 모델의 성능 측정 및 개선을 진행했습니다.
오하아사 2026.01 - 운영 중 · 개인 프로젝트 일본 아사히 TV「오하요 아사히」의 매일 별자리 운세를 한국어·일본어·영어로 제공하는 웹 서비스입니다. 스크래핑부터 번역·배포·운영까지 구축했습니다.

Tech Stack

Backend
Java · Spring Boot · Spring Cloud Gateway · JPA · MyBatis · Python · Gradle · Maven
Frontend
JavaScript · TypeScript · React · HTML5 · Tailwind CSS · jQuery · JSP
Database
PostgreSQL · MySQL · MariaDB · Redis · SQLite · Supabase · Firebase
AI / LLM
Ollama · Spring AI · pgVector · OpenAI API · Gemini API
DevOps
Docker · Kafka · Keycloak · AWS ECS Fargate · GitHub Actions · Cloudflare · WildFly / JBoss
Testing
k6 · nGrinder
Tools
Git · SVN · Notion · Redmine · Slack · Figma · Photoshop

2026. 09. 27. 기준 · 최신 내용은 djpark.work 에서 확인할 수 있습니다.

About

소개

딥라이트에서 LLM을 활용한 자동화 번역 프로그램 제작 경험이 있습니다.

스파르타클럽 내일배움캠프 자바단기심화 부트캠프를 수료하고, MSA 아키텍처 설계 및 구현을 경험했습니다.

KH정보교육원 Java 웹 개발과정 수료 후 (주)빅팀아이앤씨에서 웹사이트 유지보수부터 LLM 챗봇 개발까지 다양한 경험을 쌓았습니다.

건축·디자인에서 개발로 이어진 이력을 바탕으로 폭넓은 도메인 지식을 갖추고 있으며, 협업을 위한 의사소통과 프로젝트의 주안점을 항상 신경 쓰고 있습니다.

Experience

  • 2026.06 - 2026.07 인턴십 · Web Development (주)딥라이트 (AI 캐릭터 채팅 `CCUC`)
  • 2026.02 - 2026.05 Java 단기심화 부트캠프 수료 - MSA / AI 스파르타클럽 내일배움캠프
  • 2024.09 - 2025.06 융합기술사업팀 연구원 · 응용SW개발 (주)빅팀아이앤씨 (Bigteam INC)
  • 2023.11 - 2024.04 공공데이터 융합 자바개발자 양성과정 수료 KH정보교육원
  • 2023.02 - 2023.11 공사감독 · 도면 작업 서울사이버대학교
  • 2020.03 - 2022.02 건축학부 졸업 (학사편입) 건국대학교
  • 2018.01 - 2019.04 3dsmax 건축 모델링 · 2D 리터칭 (주)라이브플랜
  • 2012.03 - 2018.02 실내디자인과 졸업 서울예술대학교
Auto Translator

Auto Translator - LLM 번역 및 자동 배치 운영 콘솔

2026 · Full-Stack 실무

LLM 다국어 번역을 "검수 가능한 운영 작업"으로 다루는 번역 콘솔입니다. AI 초안을 바로 DB 에 쓰지 않고, 검증·검수·이관 단계를 거쳐 반영합니다.

PythonPostgreSQLSQLiteOpenAIGemini APIDocker

주요 기능

  • 18개 번역 테이블과 필드 계약을 설정 파일로 관리
  • 수동 콘솔 - 검색 · 상태 필터 · 서버 페이지네이션 · AI 초안 · 검토 후 UPSERT
  • 수동 배치 - 선택한 테이블·언어·건수만 실행, 성공 건만 저장
  • 자동 배치 - 실행 주기 · 테이블 우선순위 · 처리 한도 정책
  • OpenAI · Gemini allowlist 기반 공급자·모델 선택
  • 응답 ID · 필수 필드 검증 후 실패·충돌 건은 수동 처리 큐로 이관
  • 읽기 전용 데이터 조회 (SELECT/WITH · 3초 timeout · 200행 제한)
  • 작업 이력 · API 오류 기록 (SQLite, 기본 90일 보존)

성과

  • 한국어 → pt-BR · ja · zh-CN · zh-TW 4개 언어 번역 파이프라인 구축
  • advisory lock · lock_timeout 1.5s · statement_timeout 5s 로 운영 DB 경합 차단
  • LLM 응답 대기 중 DB 연결 미점유 - 풀 대기 1초 초과 건은 수동 이관
  • API 키 · 요청 헤더 · 전체 프롬프트를 브라우저와 로그에서 완전히 분리
  • 읽기 전용 역할 전환 실패 시 쓰기 계정으로 대체 실행하지 않는 안전 실패 확립
Auto Translator — 설계와 트러블슈팅

상세내용

한국어 원문을 포르투갈어(브라질)·일본어·중국어 간체/번체로 번역해 운영 DB에 반영합니다. 확장성을 고려해 번역 대상 테이블과 필드 계약을 설정파일로 관리할 수 있게 구성했습니다.

핵심 기술적 과제는 `운영 DB의 부담을 최소화한다` 였습니다. 해당 주문에 맟춰 설계 및 구성했습니다.

핵심 전제는 "LLM 번역 결과값을 바로 저장하지 않는다" 였습니다. 응답 ID·필수값 필드를 먼저 검증하고 통과한 건만 검토/UPSERT 로 보냅니다. UNIQUE 충돌·lock 대기·statement timeout·검증 실패는 버리지 않고 수동 처리 큐로 이관해 다시 볼 수 있게 남깁니다. 수동 콘솔은 AI 초안을 자동 저장하지 않고, 검수 담당자가 필드별로 확인·수정해야 (원본 FK, locale) 기준 UPSERT 가 실행됩니다.

운영 중인 서비스 DB에 접근하는 작업이므로 경합 상황에 대한 차단을 먼저 설계했습니다. 번역 Worker 는 PostgreSQL advisory lock 으로 인스턴스 간 중복 실행을 막고, 연결 풀은 최소 1 최대 2 로 묶었습니다. 자동 배치는 사람이 이미 검토한 항목과 이전 실패 항목을 제외하며, 다른 작업이 먼저 needs_translation 을 해제한 행은 덮어쓰지 않습니다.

트러블슈팅

번역 배치 작업이 운영DB 를 오래 붙잡고 있을 위험 확인

원인 LLM 응답은 번역 분량에 따라 수초에서 수십 초가 걸리는데, 저장용 커넥션을 미리 잡고 응답을 기다리면 그 시간만큼 운영 트래픽이 쓸 커넥션이 묶임

해결 LLM 호출 구간과 DB 저장 구간을 분리해 대기 중에는 커넥션을 점유하지 않도록 조치 - 연결 풀은 최소 1 최대 2 로 묶고, lock_timeout 1.5초 · statement_timeout 5초를 걸어 오래 버티는 대신 빨리 포기하도록 설정

여러 인스턴스가 동시에 뜰 경우 같은 행을 중복 번역하는 이슈

원인 기존 배치 Worker 가 이미 실행 중인지 확인할 방법이 없어, 프로세스가 둘 이상일 경우 같은 대상을 각자 처리했습니다.

해결 PostgreSQL advisory lock 을 통해 Worker 진입을 직렬화해 인스턴스 간 중복 실행을 차단했습니다.

저장 단계에서 실패한 건이 기록 없이 사라지는 현상

원인 UNIQUE 충돌 · lock 대기 · statement timeout · 응답 검증 실패가 모두 예외로 끝나면서, 어떤 항목이 왜 빠졌는지 남지 않았습니다.

해결 실패 유형을 구분해서 수동 처리 큐로 이관하고 작업 이력에 기록했습니다. 풀 대기가 1초를 넘는 건도 실패로 처리하지 않고 같은 큐로 보내 다시 검토할 수 있게 했습니다.

기여도 · 1인 개발 - CLI 배치 · 웹 콘솔 Front-end · DB 연동 Back-end

First Ticket

First Ticket - MSA 티켓 예매 플랫폼

2026.04 - 2026.05 · Backend & Infra 팀 프로젝트

매크로·동시 접속·중복 예매 문제를 해결하는 MSA 티켓 예매 플랫폼입니다. 6인 백엔드 팀에서 User/Auth 도메인과 API Gateway, Eureka Service Discovery 를 설계·구현했습니다.

Java 21Spring BootSpring Cloud GatewayKeycloakPostgreSQLRedisKafkaQueryDSLAWS ECS FargateDockerGrafanaGitHub Actions

주요 기능

  • Keycloak ROPC 기반 회원가입 · 로그인 · 토큰 재발급
  • Redis JTI 블랙리스트 + Refresh Token Rotation
  • Gateway 인증 필터 - 헤더 위조 차단 후 사용자 컨텍스트 주입
  • L1 Caffeine + L2 Redis 2단 블랙리스트 캐시
  • Eureka 서비스 디스커버리 · Config Server 설정 관리
  • HOST 권한 신청 · 승인 (HostRequest Aggregate)
  • QueryDSL 기반 관리자 전용 사용자 검색 API
  • Resilience4j Circuit Breaker · Bulkhead · Zipkin 분산 추적

성과

  • 블랙리스트 조회 스파이크 24회 → 1회 (-95.8%)
  • GET /users/me TPS 1,720 — Little's Law 예측 대비 오차 1%, 응답 37ms → 11ms (-70%)
  • 로그인 TPS 175 → 1,568 (+796%), 응답 135ms → 63ms (-53%)
  • BulkheadFullException 4,917건 → 0건, Circuit Breaker CLOSED 유지
  • 비밀번호 변경 후 남는 고아 세션 0건 (RFC 7009 즉시 revoke)
First Ticket — 설계와 트러블슈팅

상세내용

대기열로 트래픽을 흡수하고, 분산락으로 선점 좌석을 직렬화하고, Kafka Saga 로 결제 실패를 보상하는 구조입니다. 6개 서비스가 Spring Cloud Gateway · Eureka · Config Server 위에 올라가고, 모든 요청의 진입점인 Gateway 에서 인증·인가·보안을 단일 흐름으로 처리합니다. 배포는 AWS ECS Fargate 에 GitHub Actions CI/CD 로 이어집니다.

Keycloak 이 발급한 JWT 는 만료 전 강제 무효화가 불가능합니다. 로그아웃·비밀번호 변경 후에도 탈취된 토큰이 유효한 문제를 Redis JTI 블랙리스트로, 탈취된 Refresh Token 재사용을 Rotation 으로 해결했습니다. 짧은 AT TTL 만 쓰는 안과 서버 세션 안은 각각 UX 저하와 Stateless 이점 상실로 기각했고, 로그아웃 후 최대 5초(L1 TTL) 지연을 감수하는 쪽을 택했습니다.

트러블슈팅

요청 1건마다 Redis 조회 - vuser 70 구간에서 1,400 TPS 스파이크

원인 모든 요청이 Gateway 에서 Redis 내 blacklist:{jti} 를 조회하다 보니, 초당 처리량이 그대로 Redis 호출량이 됐습니다. 실제로 블랙리스트에 걸리는 토큰은 1% 미만임에도 전량을 조회하고 있었습니다.

해결 Caffeine L1 캐시(TTL 5s)를 우선 조회하고 Cache Miss 일 때만 Redis 로 내려가게 바꿔 조회 24회 → 1회 (-95.8%). 로그아웃 후 최대 5초 지연은 AT TTL(15분) 대비 0.3% 라 수용했습니다.

vuser 50 구간에서 503 에러 및 TPS 가 0 으로 떨어지는 현상

원인 Resilience4j Bulkhead 의 maxConcurrentCalls 가 25 로 묶여 있었습니다. 동시 호출이 한도를 넘자 BulkheadFullException 이 즉시(elapsed 0ms) 발생했고, 이 예외를 Circuit Breaker 가 실패로 집계해 sliding window 실패율이 50% 를 넘겨 OPEN 으로 전환됐습니다.

해결 한도를 200 으로 올려 BulkheadFullException 4,917건 → 0건, Circuit Breaker 는 CLOSED 를 유지했습니다.

로그인 TPS 175 에서 정체, 응답 135ms

원인 부하테스트 분석 결과 지연의 97% 가 Keycloak ROPC 호출이었습니다. Gateway 1ms 미만, User Service 5ms 미만인데 Keycloak 왕복만 약 130ms 였습니다.

해결 at-cache:{SHA-256(lower(email))} 키로 Redis AT 캐시를 도입해 TPS 175 → 1,568 (+796%), 응답 135ms → 63ms (-53%). 이메일을 해시로 써서 PII 평문 저장을 피했습니다.

DB 커넥션 대기로 응답이 지연되는 현상

원인 HikariCP 풀 기본값 10 인데 vuser 는 50 이라서 구조적으로 부족했습니다. 게다가 connection-timeout 이 30초라 대기가 그대로 응답 지연으로 쌓였습니다.

해결 Little's Law(L = λ × W)로 필요 커넥션을 산정해 풀을 50 으로, timeout 은 3초 fast-fail 로 조정했습니다. GET /users/me TPS 1,720 으로 예측 대비 오차 1%, 응답 37ms → 11ms (-70%).

기여도 · 6인 백엔드 팀 - User/Auth 도메인 · API Gateway · Eureka 설계 및 구현

Personal RAG

Personal RAG - 로컬 모델 / LLM API 사용가능 챗봇

2026.02 - 2026.03 · Backend & LLM 개인 프로젝트

각종 문서를 개인 PC 안에서 처리하는 로컬 RAG 챗봇. 로컬 모델의 성능 측정 및 개선을 진행했습니다.

Java 17Spring BootSpring AIOllamapgVectorPostgreSQLReactTypeScriptDockerGitHub Actions

주요 기능

  • Ollama qwen3:8b 로컬 추론 + bge-m3 임베딩
  • pgVector 유사도 검색 기반 RAG
  • LLM Tool Calling (모델이 필요하다고 판단할 때만 벡터 검색 호출)
  • 비동기 ETL (URL·PDF·DOCX·XLSX·PPTX·TXT) + SSE 프로그레스 바 구현
  • WebSocket 토큰 스트리밍 채팅
  • 지식베이스 관리 UI (소스별 청크 조회·삭제)
  • 골든셋 기반 자동 평가 하네스 4종

성과

  • 청크 1500 → 800 토큰으로 문항 통과율 0.0% → 50.0%
  • 정답 핵심내용 포함률 38.1% → 76.2% - gpt-4o-mini 와 동일한 값
  • 콜드스타트 37.2s → 1.2s (-97%), k6 에러율 100% → 0%
  • 평균 지연 88.9s → 33.0s (-63%), p95 188.6s → 74.5s (-60%)
  • 8GB VRAM 단일 GPU 에서 상용 API 없이 로컬 Ollama qwen3:8b + bge-m3 로 RAG 챗봇 구동
Personal RAG — 설계와 트러블슈팅

상세내용

ChatGPT, Gemini 등의 상용 LLM API는 품질과 생성 속도를 보장하지만 기본적으로 인터넷 연결이 필요하고, 문서 본문 또한 외부로 전송되고 사용량만큼 과금됩니다. 정부 공고문·계약서·사내 매뉴얼 등 외부 유출에 민감한 문서를 다루기 위해 로컬에서 끝나는 파이프라인이 필요했습니다. 과거 Java 8 · eGovFramework 기반이던 LLM 챗봇을 Java 17 + Spring Boot 3.5 + Spring AI 로 다시 설계하고, Ollama(qwen3:8b)와 pgVector 를 붙여 로컬에서 구동할 수 있도록 했습니다.

RTX 4060 Ti 8GB 기준으로 qwen3:8b(5.6GB)와 bge-m3(0.7GB)를 함께 사용하는 상황에서의 적절 청크 크기, 재정렬 방식, GPU 성능 까지 잡는것이 메인 포인트였습니다.

개선에 앞서 먼저 측정 체계부터 만들었습니다. LLM은 같은 질문에도 매번 다른 답을 내놓기 때문에, 한 번의 테스트 결과를 그대로 믿지 않고 모든 비교 실험을 3회 이상 반복해 재현되는지 확인하는 걸 원칙으로 삼았습니다. 실제로 로컬 모델과 상용 모델을 처음 비교했을 땐 62.5% 대 62.5%로 정확히 동률이 나와 "차이가 없다"고 결론 낼 뻔했지만, 반복하자 50.0% 대 58.3%로 격차가 드러났습니다. 게다가 결과가 들쭉날쭉했던 쪽은 오히려 상용 모델이었습니다(편차 12.5%p 대 0.0%p) — 한 번의 우연한 결과만 믿었다면 정반대 결론을 냈을 것입니다.

트러블슈팅

콜드스타트 37.2초, 부하 테스트 에러율 100%

원인 설정 파일에는 올바른 값이 적혀 있었지만 요청에 실리지 않았습니다. 응답 유지시간(keepAlive)을 YAML 정수 -1 로 쓰자 문자열 "-1" 로 직렬화됐고, 단위가 없는 값이라 Ollama측에서 거부하고 있었습니다.

해결 단위를 명시(-1s)해 콜드스타트 37.2s → 1.2s (-97%), 에러율 100% → 0% 로 회복했습니다.

100 ~ 450자 답변시간 평균 88.9초, p95 188.6초

원인 모델이 답하기 전 내부적으로 추론하는 과정(thinking mode)을 끄는 설정이 적용되지 않고 있었습니다. application.yaml 에는 있었지만 ChatClientFactory 가 defaultOptions 를 통째로 지정하면서 덮어쓰고 있었습니다.

해결 전달 경로를 고쳐 평균 88.9s → 33.0s (-63%), p95 188.6s → 74.5s (-60%). 다만 사실 포함률이 77.8% → 57.1% 로 함께 떨어져, 트레이드오프를 규명하고 기본값은 품질 우선으로 되돌렸습니다.

검색은 정답을 찾아오는데 모델이 그 내용을 쓰지 못함

원인 청크 1500토큰이 한국어 공고문에서 평균 5,425자 청크를 만들었고, topK=3 근거만으로 약 4,521토큰이 되어 검색 단계에서 이미 num_ctx 4,096 을 초과하고 있었습니다.

해결 청크를 800토큰으로 낮춰 문항 통과율 0.0% → 50.0%, 정답 핵심내용 포함률 38.1% → 76.2% 로 올렸습니다.

기여도 · 개인 프로젝트 1인 개발 - 기획 · 백엔드 · 프론트엔드 · 인프라

오하아사

오하아사 - 오늘의 별자리 운세 사이트

2026.01 - 운영 중 · Full-Stack 개인 프로젝트

일본 아사히 TV「오하요 아사히」의 매일 별자리 운세를 한국어·일본어·영어로 제공하는 웹 서비스입니다. 스크래핑부터 번역·배포·운영까지 구축했습니다.

ReactTypeScriptViteTailwind CSSCloudflareDeepL APIi18next

주요 기능

  • Cloudflare Workers 스크래핑 + KV 일일 단위 캐싱
  • DeepL API 자동 번역 (일본어 → 한국어 / 영어)
  • i18next 기반 3개 국어 실시간 전환
  • 12별자리 순위 정렬 및 1위 하이라이트
  • 별자리별 생일 범위 · 행운의 아이템 표시
  • 방송 시간(오전 7시) 기준 당일 / 전날 운세 구분
  • API 갱신 지연 시 원본 사이트 직접 조회 fallback
  • GitHub Actions 로 매일 캐시 워밍업

성과

  • ohaasa.site 도메인으로 실서비스 운영 중
  • KV 캐시로 인해 트래픽이 몰려도 원본 사이트에 부하가 가지 않음
  • SEO 최적화 (OG · Twitter Card · sitemap) 및 Google Analytics · Microsoft Clarity 계측 적용
  • 기획부터 배포·운영까지 혼자 완성한 개인 서비스
오하아사 — 설계와 트러블슈팅

상세내용

Cloudflare Workers 가 매일 원본 운세를 수집하고 DeepL API 로 일본어 원문을 한국어·영어로 번역한 뒤 Cloudflare KV 에 캐싱합니다. 프론트엔드는 Cloudflare Pages 에 배포되어 KV 캐시만 읽으므로, 방문자가 몰려도 원본 사이트에 부하가 가지 않습니다.

방송 시간(오전 7시)을 기준으로 당일/전날 운세를 구분해 노출하고, API 갱신이 늦어지면 TV Asahi 사이트를 직접 조회하는 fallback 을 둬 빈 화면이 뜨지 않도록 했습니다. 다크 모드 전용 배경 애니메이션처럼 서비스 성격에 맞는 연출도 함께 다듬었습니다.

초기에는 Gemini API 로 번역했으나, 별자리 운세처럼 짧고 정형화된 문장에서는 범용 LLM보다 전용 번역 엔진인 DeepL이 더 안정적인 품질을 보여 전환했습니다. i18next 를 적용해 3개 국어를 실시간 전환할 수 있습니다.

트러블슈팅

오전 이른 시간에 접속하면 빈 화면이 뜨거나 전날 운세가 나오는 현상

원인 원본 방송이 오전 7시에 갱신되는데 그 시각을 기준으로 삼지 않아, 갱신 전 접속과 갱신 후 접속이 같은 데이터를 보고 있었습니다.

해결 방송 시간을 기준으로 당일/전날 운세를 구분해 노출하고, API 갱신이 늦어지면 TV Asahi 사이트를 직접 조회하는 fallback 을 둬 빈 화면이 뜨지 않도록 했습니다.

방문자가 늘수록 원본 사이트로 요청이 그대로 전달됨

원인 초기 구조에서는 방문 시점마다 원본을 조회해, 트래픽이 그대로 외부 사이트 부하로 이어졌습니다.

해결 Cloudflare Workers 가 하루 한 번 설정한 시간에 수집·번역한 결과를 KV 에 캐싱하고 프론트엔드는 캐시만 읽도록 바꿨습니다. GitHub Actions 로 매일 캐시를 미리 채워 첫 방문자도 지연을 겪지 않게 했습니다.

기여도 · 1인 개발 - 기획 · 프론트엔드 · Workers 백엔드 · 배포 및 운영