YJ Technical Portfolio · 2026
01 / 26
Backend · Fullstack · AI Product

문제를 서비스 흐름으로
번역하는 개발자, 김용준입니다.

금융 도메인 백엔드, AI QA 자동화, 실시간 WebRTC 게임,
현장 운영형 포토부스까지 끝까지 만들어 본 경험이 있습니다.

Java · Spring Boot JPA · QueryDSL · MyBatis React · Vue · Electron LLM Fine-tuning · Playwright PM · Architecture · UX Flow
Backend 중심 상태·이력·권한·외부 API를 서비스 흐름으로 설계
E2E 구현 입력부터 결과 확인·실패
복구까지 화면/API 구현
AI 제품화 모델 출력이 실제 시스템에서 검증·실행되는 구조 구축
PM 경험 기능 우선순위·협업 문서
·화면 흐름·배포까지 조율
김용준 프로필
maple5741@naver.com github.com/Yongjooon
AboutProfile · Education · Awards
02 / 26
About Me

제 강점은 구현 범위와 제품 맥락을 함께 잡는 것입니다.

01

Backend 중심 구현

단순 CRUD보다 상태 전환·이력 추적·권한 경계·외부 API 실패 가능성을 먼저 봅니다. QueryDSL 조회·트랜잭션 경계·금융 API 검증을 분리해 서비스 코드가 도메인 흐름에 집중하도록 구현합니다.

02

AI 제품화 경험

모델 출력이 제품 안에서 검증되고·실패 시 회복되며·실제 실행까지 이어지는 구조를 중요하게 봅니다.
JSON contract·validator·retry/fixer로 학습 결과가 실행 가능한 시나리오로 이어지게 만듭니다.

03

PM과 UX 흐름

문제 정의·기능 우선순위·API 계약·화면 흐름·WBS·정책 문서를 정리합니다. 사용자가 지금 무엇을 해야 하는지를 화면 상태로 드러내고, FE/BE가 병렬로 움직이도록 조율합니다.

교육 / Education

인천대학교 임베디드시스템공학과 공학사 · 데이터구조 · 알고리즘 · 운영체제 · DB · 임베디드 기반
KB IT's Your Life Java · Spring · Vue · 금융 프로젝트 수행
SSAFY 14기 Java · Spring · Vue · AI 실전 개발

수상 · 자격 · 경험 / Awards

  • KB IT's Your Life 종합실무 최우수상 : BeBig
  • SSAFY 1학기 성적우수상 · 프로젝트 우수상 : Newstagram
  • SSAFY 공통프로젝트 우수상 : A601
  • SSAFY 자율프로젝트 우수상 : AutoQA
  • Google Analytics Certification · OPIc IM3
  • 양천구청 행정인턴 · INU 학습멘토링 봉사활동
6+대표 프로젝트
960hKB IT's Your Life 응용SW 교육
925hSSAFY 1학기 코딩 집중과정
5+수상 내역
About · Profile · Credentials 김용준 · maple5741@naver.com
Projects6 Project Index
03 / 26
Project Index

총 6개 프로젝트 · 백엔드 · 프론트엔드 · AI · 인프라 · PM

01 · BACKEND/PM

BeBig

금융 자산관리 서비스

유형실제 계좌 기반 자산 분석·미션 추천
기간2024.09.04 ~ 2024.10.16
인원7명
업무PM, FE, CODEF 구조 설계
성과KB IT's Your Life 최우수상
02 · FULLSTACK

GBCamera

현장 운영형 포토부스 자동화

유형촬영·합성·QR·무인 출력 자동화
기간2025.10.01 ~ 2025.11.30
인원개인 프로젝트
업무BE, FE, Infra
성과약 50명 부스 운영 검증
03 · BACKEND/PM

Newstagram

AI 뉴스 큐레이션 서비스

유형RSS 수집·기사 임베딩·개인화 추천
기간2025.11.07 ~ 2025.12.26
인원5명
업무PM, BE
성과SSAFY 1학기 프로젝트 우수상
04 · FULLSTACK/PM

Project A601

실시간 WebRTC 마피아 게임

유형WebRTC·WebSocket 실시간 소셜 게임
기간2026.01.06 ~ 2026.02.09
인원4명
업무PM, FE
성과SSAFY 공통프로젝트 우수상
05 · BACKEND

용돈농장

청소년 금융 교육 백엔드

유형부모-자녀 용돈·저축·대출·신용 관리
기간2026.02.16 ~ 2026.04.03
인원4명
업무BE · DB 설계
성과금융 도메인 모델링 경험
06 · AI/PM

AutoQA

AI 기반 웹 QA 자동화 SaaS

유형URL 분석·AI 시나리오·Playwright 실행
기간2026.04.06 ~ 2026.06.02
인원6명
업무PM, AI 데이터 구축, SFT/DPO 학습
성과SSAFY 자율프로젝트 우수상
Projects · Index 김용준 · Technical Portfolio
Project 01BeBig · 금융 자산관리 서비스
04 / 26
01 · BeBig

실제 계좌 데이터를 소비 습관 개선 행동으로 연결한 금융 자산관리 서비스

BeBig은 사용자의 실제 계좌와 거래내역을 기반으로 총자산, 소비 흐름, 금융 성향, 미션을 제공하는 금융 자산관리 서비스입니다. 단순히 잔액과 거래 목록을 보여주는 데서 끝나지 않고, CODEF로 가져온 금융 데이터를 사용자가 오늘 수행할 수 있는 저축/소비 행동으로 번역하는 것을 목표로 했습니다. 저는 PMFrontend를 맡아 계좌 연결 UX, 대시보드, 거래내역 조회, 미션 흐름을 설계·구현하고 Backend의 CODEF 수집 구조를 함께 정리했습니다.

Vue 3 Pinia Axios Spring Boot MyBatis CODEF API Chart UX
  • Work 1CODEF 금융 데이터 활용 구조 설계
  • Work 2사용자 친화적 UX 구현
BeBig 표지 이미지
2024 · KB IT's Your Life · 최우수상 7명 · PM/Frontend
01 BeBigWork 1 of 2
06 / 27
01 BeBig · Work 1

CODEF 금융 데이터 활용 구조 설계

Tech Stack Vue 3 · Axios · Spring Boot · CODEF API · MyBatis batch insert · 금융 데이터 정규화 · 거래내역 중복 방지
상황 · Situation

실제 금융 데이터는 서비스의 출발점이지만, 외부 API 응답을
그대로 쓰기 어려웠습니다.

  • 계좌 연결은 은행 인증, CODEF 연결 ID, 계좌 목록, 거래내역 조회가 순차적으로 이어지는 민감한 흐름이었습니다.
  • 사용자는 빠른 결과를 기대하지만 외부 금융 API는 응답 지연, 빈 거래내역, 기존 연결 ID 재사용 같은 예외가 발생할 수 있었습니다.
과제 · Task

CODEF 응답을 내부 자산 분석과 미션 생성에 재사용 가능한 데이터로
바꿔야 했습니다.

  • 신규 은행 연결과 기존 연결 ID 확장을 분기하고, 계좌 정보와 거래내역을 서비스 도메인 기준으로 정규화해야 했습니다.
  • 중복 거래 저장, 빈 거래내역, 최근 거래 기준 재조회 같은 운영 예외를 고려해야 했습니다.
행동 · Action

Vue 요청 흐름과 Spring/MyBatis 저장 흐름이 같은 데이터 계약을 바라보도록 설계했습니다.

  • Vue·Axios 기반 계좌 추가 요청은 선택 은행·인증 정보·사용자 식별 값을 Backend로 전달하고, Backend는 연결 ID 보유 여부에 따라 신규 등록 또는 기존 연결 ID 확장으로 분기했습니다.
  • CODEF 계좌 응답은 은행 코드·계좌번호·계좌명·잔액·통화·계좌 상태처럼 필요한 필드만 추려
    내부 계좌 모델로 변환했습니다.
  • MyBatis batch insert로 여러 계좌를 한 번에 저장하고, 계좌별로 최근 360일 거래내역 조회를
    이어 실행하도록 흐름을 잡았습니다.
  • 거래내역은 거래일시·거래처·입출금·금액·잔액·계좌번호 기준으로 정규화해 대시보드와 상세 화면이
    같은 의미의 필드를 사용하게 했습니다.
  • 거래일자와 금액 중심의 중복 판단 기준으로 동일 거래가 반복 저장되지 않게 처리했습니다.
  • 거래내역이 없는 계좌는 실제 거래 데이터와 분리된 잔액 스냅샷을 생성해 총자산 화면이
    빈 상태로 보이지 않도록 처리했습니다.
결과 · Result
  • 실제 계좌 연결 데이터가 총자산·계좌 상세·소비 분석·미션 추천 흐름으로 이어지는 기반을 만들었습니다.
  • 외부 금융 API 응답을 화면 전용이 아니라 서비스 전반에서 재사용 가능한 금융 도메인 데이터로 전환했습니다.
BeBig · CODEF 데이터 활용 구조 김용준 · Technical Portfolio
01 BeBigWork 2 of 2
07 / 27
01 BeBig · Work 2

사용자 친화적 UX 구현

Tech Stack Vue 3 · Pinia · Axios interceptor · computed grouping · infinite scroll · loading state · dashboard UX
상황 · Situation

금융 데이터는 많을수록 정확하지만, 사용자가 이해하지 못하면 행동으로
이어지지 않습니다.

  • 계좌·거래내역·금융 성향·미션·커뮤니티가 모두 존재해 화면 정보량이 커질 위험이 있었습니다.
  • 계좌 연결 과정은 외부 인증과 로딩이 길어 사용자가 현재 상태를 놓치기 쉬웠습니다.
과제 · Task

금융 데이터를 사용자가 바로 판단할 수 있는 카드·목록·피드백·미션으로
바꿔야 했습니다.

  • 홈에서는 핵심 자산 정보를 빠르게 보여주고, 상세에서는 긴 거래내역을 끊김 없이
    탐색할 수 있어야 했습니다.
  • 은행 연결·계좌 상세·미션 수행이 떨어진 기능이 아닌 하나의 행동 흐름으로 연결되어야 했습니다.
행동 · Action

Vue SPA 안에서 금융 상태와 사용자 행동을 분리해 관리했습니다.

  • 대시보드·은행 추가·은행 인증·계좌 목록·계좌 상세·설문·미션 화면을 목적별 페이지로 나누고
    라우팅 흐름을 단순화했습니다.
  • Pinia에는 사용자 상태·선택 은행·계좌 연결 진행 상태를 저장하고, Axios API 모듈은 서버 통신과
    인증 헤더 처리를 담당하도록 분리했습니다.
  • 홈 대시보드는 사용자 정보·총자산·대표 계좌·계좌 연결 CTA·미션 요약을 한 화면에 배치해
    "현재 상태"와 "다음 행동"이 같이 보이게 구성했습니다.
  • 계좌 상세는 현재 페이지·페이지 크기·전체 페이지·요청 중 상태·추가 데이터 여부를 분리해
    무한 스크롤과 중복 요청 방지를 함께 처리했습니다.
  • 거래내역은 Vue computed 기반 날짜 그룹핑으로 같은 날짜의 소비를 묶고, 목록이 길어져도
    흐름을 읽을 수 있게 했습니다.
  • 새로고침 버튼은 CODEF 재조회 이후 페이지 상태를 초기화하고 최신 거래부터 다시 보여줘
    데이터 갱신 감각을 제공했습니다.
결과 · Result
  • 실제 금융 데이터가 사용자의 총자산 인식·소비 확인·미션 수행으로 이어지는 핵심 UX를 구현했습니다.
  • KB IT's Your Life 종합실무프로젝트에서 BeBig 프로젝트가 최우수상을 수상했습니다.
BeBig · 사용자 친화적 UX 김용준 · Technical Portfolio
Project 02GBCamera · 포토부스 자동화
07 / 26
02 · GBCamera

촬영부터 무인 출력과 QR 공유까지 자동화한
현장 운영형 포토부스

GBCamera는 행사 현장에서 참가자가 직접 촬영·사진 선택·프레임 적용·출력·QR 다운로드까지 진행할 수 있도록 만든 포토부스 자동화 서비스입니다. 웹캠과 프린터를 제어해야 하는 운영 앱은 Electron으로 구성하고,
참가자 결과 확인은 모바일 웹으로 분리했습니다. 저는 기획·Frontend·Backend·Electron·배포·현장 운영
모두 담당하며 브라우저 UI와 로컬 장치 제어·서버 저장·모바일 QR 공유 흐름을 하나로 연결했습니다.

React Zustand Canvas API Electron Spring Boot MySQL BLOB Vercel EC2
  • Work 1배포 운영
  • Work 2Electron 무인 프린트
  • Work 3수동 포토부스 자동화 기획
GBCamera 표지 이미지
2025.11 운영/고도화 · 개인 프로젝트 기획 · FE · BE · Electron · 운영
02 GBCameraWork 1 of 3
09 / 27
02 GBCamera · Work 1

배포 운영

Tech Stack Vercel Serverless Proxy · EC2 · Spring Boot · MySQL LONGBLOB · Base64 변환 · SecureRandom · CORS/Mixed Content 대응
상황 · Situation

운영 앱·결과 조회 웹·Backend가 서로 다른 실행 환경에서 동작해야 했습니다.

  • 촬영 현장의 데스크톱 앱은 로컬 장치를 제어하고, 참가자 휴대폰은 QR로 HTTPS 모바일 웹에 접속해야 했습니다.
  • HTTPS 결과 페이지가 HTTP 기반 서버에 직접 접근하면 Mixed Content와 CORS 문제가 발생했습니다.
과제 · Task

촬영 결과 저장과 모바일 조회를 안정적으로 연결하고 운영 중 장애 지점을
줄여야 했습니다.

  • 촬영 세션마다 고유 식별자를 만들고, 이 값을 서버 저장·QR URL·모바일 조회의 공통 키로
    사용해야 했습니다.
  • 결과 이미지는 큰 바이너리이므로 DB 저장과 Base64 응답 변환을 명확히 분리해야 했습니다.
행동 · Action

Vercel·EC2·Spring Boot·MySQL을 역할별로 나누고 프록시 계층을 추가했습니다.

  • 결과 조회 화면은 Vercel에 배포하고, Backend는 EC2에서 Spring Boot API로 운영해
    모바일 접근성과 서버 제어를 분리했습니다.
  • Vercel Serverless Proxy를 두어 HTTPS 결과 페이지가 EC2 Backend와 통신할 때
    Mixed Content·CORS 문제를 우회하도록 구성했습니다.
  • 촬영 세션 생성 API는 SecureRandom 기반 URL-safe 문자열을 생성하고,
    DB 기본키 충돌 시 재시도하도록 설계했습니다.
  • 결과 저장 API는 최종 합성 이미지를 Base64에서 바이너리로 변환해 MySQL LONGBLOB에 저장하고, 조회 API는 다시 Base64로 변환했습니다.
  • 행사 단위 운영 규모에 맞춰 LONGBLOB로 단순화했고, 이미지 규모가 커지면 S3 같은
    Object Storage로 분리 가능한 구조로 두었습니다.
  • 운영 앱과 모바일 웹은 배포 환경에 따라 API base URL을 다르게 사용하도록 구성해
    로컬 테스트와 운영을 분리했습니다.
  • 서버 API는 세션 생성·결과 저장·결과 조회 책임만 갖게 해 UI 변경이 Backend에 과도하게
    번지지 않게 했습니다.
결과 · Result
  • 촬영 앱이 만든 결과물이 서버에 저장되고, 참가자가 QR로 모바일 웹에서 바로 확인하는 운영 흐름을 만들었습니다.
  • 현장 네트워크와 배포 프로토콜 차이로 인한 모바일 조회 실패 가능성을 줄였습니다.
GBCamera · 배포 운영 김용준 · Technical Portfolio
02 GBCameraWork 2 of 3
10 / 27
02 GBCamera · Work 2

Electron 무인 프린트

Tech Stack Electron IPC · Preload bridge · BrowserWindow · silent print · deviceName · localStorage · Canvas image data URL
상황 · Situation

일반 브라우저 인쇄는 운영자가 매번 다이얼로그를 확인해야 해
무인 부스에 맞지 않았습니다.

  • 행사 부스에서는 참가자가 촬영을 마친 뒤 출력까지 자연스럽게 이어져야 했습니다.
  • 브라우저 기본 인쇄는 프린터 선택·매수·확인 버튼이 노출되어 운영자 개입이 필요했습니다.
과제 · Task

프린터 목록 조회와 자동 출력을 웹 UI 안에서 안전하게 사용할 수 있어야 했습니다.

  • Renderer가 OS 권한에 직접 접근하지 않으면서도 프린터 목록·출력 명령을
    사용할 수 있어야 했습니다.
  • 최종 합성 이미지가 저장된 뒤 지정 프린터·매수로 조용히 출력되어야 했습니다.
행동 · Action

Electron IPC를 사용해 UI 계층과 OS 인쇄 계층을 분리했습니다.

  • Renderer는 노출된 Electron API만 호출하고, Main Process가 프린터 목록·인쇄 실행을
    담당하도록 보안 경계를 나눴습니다.
  • Electron IPC 채널을 통해 프린터 목록 조회·이미지 인쇄 요청·결과 응답을 주고받도록 구성했습니다.
  • 프린터 선택값은 로컬 저장소에 유지해 현장에서 앱을 다시 열어도 기존 설정을
    재사용할 수 있게 했습니다.
  • 최종 JPEG 이미지는 data URL 기반 출력 문서로 변환하고, 숨겨진 BrowserWindow에 로드한 뒤
    로딩 완료 시점에 인쇄를 실행했습니다.
  • Electron silent print 옵션·deviceName·copies 설정으로 인쇄 다이얼로그 없이 지정 프린터로 출력되게 했습니다.
  • Electron 환경이 아니거나 프린터가 없을 때는 출력 단계를 건너뛰고 QR 공유 흐름을 유지해
    부스 운영이 멈추지 않게 했습니다.
결과 · Result
  • 촬영 완료 후 참가자가 별도 조작 없이 인화 결과를 받을 수 있는 무인 출력 흐름을 구현했습니다.
  • 웹 UI의 편의성과 데스크톱 앱의 로컬 장치 제어 능력을 함께 활용했습니다.
GBCamera · Electron 무인 프린트 김용준 · Technical Portfolio
02 GBCameraWork 3 of 3
11 / 27
02 GBCamera · Work 3

수동 포토부스 자동화 기획

Tech Stack React Router · Zustand · MediaStream · Canvas crop · JPEG Blob · QR flow · photobooth service design
상황 · Situation

수동 포토부스는 촬영·선택·편집·출력·공유 단계마다 운영자의 손이 필요했습니다.

  • 사용자가 촬영 타이밍·선택 흐름을 스스로 이해하지 못하면 운영자가 계속 안내해야 했습니다.
  • 웹캠 비율과 프레임 비율이 달라 최종 이미지가 늘어나거나 잘리는 문제가 발생할 수 있었습니다.
과제 · Task

촬영부터 QR 공유까지 하나의 셀프서비스 여정으로 설계해야 했습니다.

  • 설정·촬영·사진 선택·프레임 합성·저장·출력·QR 확인이 자연스럽게 이어져야 했습니다.
  • 카메라 입력과 프레임 합성은 다양한 해상도에서도 인생네컷 형태를 안정적으로 유지해야 했습니다.
행동 · Action

React 상태 흐름과 Canvas 합성 규칙을 기준으로 자동 촬영 경험을 만들었습니다.

  • React Router로 설정·촬영·선택·프레임·결과 화면을 분리하고, Zustand에 스트림·이미지·프레임
    ·세션 식별자를 저장했습니다.
  • MediaStream을 video element에 연결하고, 6초 간격 타이머로 총 6장을 자동 캡처해
    촬영 버튼 반복 입력을 없앴습니다.
  • Canvas에는 object-fit cover와 같은 비율 계산을 적용해 웹캠 원본을 프레임 슬롯에 맞게
    중앙 크롭했습니다.
  • 전면 카메라 사용 시 미리보기와 저장 결과의 방향이 어색하지 않도록 좌우 반전 기준을
    캡처 단계에 반영했습니다.
  • 최종 프레임은 고정 출력 비율로 3장의 선택 이미지를 지정 슬롯에 그리고,
    마지막에 프레임 오버레이로 인쇄 경계를 안정화했습니다.
  • 완성 이미지는 JPEG Blob과 Base64로 변환해 서버 저장·Electron 출력·QR 조회 흐름에서
    같은 결과물을 사용하게 했습니다.
결과 · Result
  • 50명을 대상으로 실제 부스 운영을 진행하며 자동 촬영·프레임 합성·출력·QR 공유 흐름을 검증했습니다.
  • 운영자 설명 의존도를 줄이고 참가자가 화면 흐름을 따라 스스로 촬영을 마칠 수 있게 했습니다.
GBCamera · 자동화 기획 김용준 · Technical Portfolio
Project 03Newstagram · AI 뉴스 큐레이션
11 / 26
03 · Newstagram

RSS 수집과 기사 임베딩으로 관심사 기반 뉴스를 제공한 AI 큐레이션 서비스

Newstagram은 여러 언론사의 RSS 기사를 자동 수집하고, 기사 임베딩클러스터링을 통해 실시간/일간/주간 이슈와 개인화 추천을 제공하는 뉴스 서비스입니다. 단순 키워드가 아니라 의미 기반 벡터를 사용해 비슷한 이슈와 사용자의 관심사를 연결했습니다. 저는 PM·Backend·Frontend를 담당하며 RSS 수집·Spring Batch/Quartz 자동화·기사 임베딩 저장·추천/검색 화면 연결까지 이어지는 데이터 파이프라인을 설계했습니다.

Spring Batch Quartz Rome RSS Jsoup PostgreSQL pgvector OpenAI Embedding Kafka
  • Work 1Batch · Quartz 자동화
  • Work 2RSS 기사 수집
  • Work 3기사 임베딩 파이프라인
Newstagram 표지 이미지
2025.11 – 2025.12 · 5명 PM · Backend · Frontend · 파이프라인 설계
03 NewstagramWork 1 of 3
13 / 27
03 Newstagram · Work 1

Batch · Quartz 자동화

Tech Stack Spring Batch · Quartz · ThreadPoolTaskExecutor · chunk processing · Asia/Seoul scheduler · clustering trigger
상황 · Situation

뉴스 서비스는 새 기사가 계속 들어오기 때문에 수동 수집으로는
신선도를 유지할 수 없었습니다.

  • RSS 수집·기사 임베딩·기간별 클러스터링이 정해진 시간에 자동으로 이어져야 했습니다.
  • 외부 RSS와 임베딩 API는 실패 가능성이 있어 배치 실행 결과를 추적할 수 있어야 했습니다.
과제 · Task

무거운 데이터 작업을 사용자 API와 분리하고, 일정 기반으로 안정 실행해야 했습니다.

  • 뉴스 수집과 임베딩을 하나의 작업으로 묶되 단계별 성공/실패를 분리해서 볼 수 있어야 했습니다.
  • REALTIME·DAILY·WEEKLY 클러스터링은 실행 시점에 따라 다른 주기로 호출되어야 했습니다.
행동 · Action

Spring Batch Job을 RSS 수집 Step과 임베딩 Step으로 나누고 Quartz로 실행 시점을 제어했습니다.

  • Spring Batch Job을 RSS 기사 수집 Step과 미임베딩 기사 처리 Step으로 분리해,
    수집 실패와 임베딩 실패를 독립적으로 추적할 수 있게 했습니다.
  • ThreadPoolTaskExecutor로 언론사 source 단위 작업을 병렬 처리하고,
    chunk 크기를 source 단위(1건)로 잡아 한 언론사 실패가 다른 언론사로 번지지 않게 했습니다.
  • Quartz 스케줄러는 Asia/Seoul 시간대 기준 실행·중복 실행 방지 정책으로
    이전 배치가 끝나기 전 같은 작업이 겹치지 않게 했습니다.
  • RSS 수집·임베딩 완료마다 REALTIME 클러스터링을 요청하고, 0시에는 DAILY,
    월요일 0시에는 WEEKLY 클러스터링을 추가 실행하도록 분기했습니다.
  • 배치 실행 상태·처리 건수·retry·error message를 로그로 남겨 외부 RSS 실패나
    임베딩 API 실패 원인을 좁힐 수 있게 했습니다.
  • 사용자 API와 배치 모듈의 책임을 분리해 뉴스 조회 요청이 대량 수집/임베딩 작업에
    직접 영향을 받지 않게 했습니다.
결과 · Result
  • RSS 수집·기사 임베딩·기간별 핫 이슈 생성이 자동 실행되는 데이터 파이프라인을 구축했습니다.
  • 실패 가능성이 높은 외부 데이터 작업을 사용자 기능과 분리해 서비스 안정성을 높였습니다.
Newstagram · Batch·Quartz 자동화 김용준 · Technical Portfolio
03 NewstagramWork 2 of 3
14 / 27
03 Newstagram · Work 2

RSS 기사 수집

Tech Stack Rome RSS · Jsoup · URL unique constraint · ON CONFLICT DO NOTHING · thumbnail extraction · text normalization
상황 · Situation

언론사 RSS는 포맷이 비슷해 보여도 썸네일·본문·날짜·작성자 품질이
제각각이었습니다.

  • 기사 URL 중복·비어 있는 본문·추적용 이미지·누락된 썸네일 같은 케이스가 반복적으로 발생했습니다.
  • 수집 품질이 낮으면 이후 임베딩과 클러스터링 품질도 함께 낮아졌습니다.
과제 · Task

RSS 원본을 검색·추천에 쓸 수 있는 내부 Article 데이터로 안정 변환해야 했습니다.

  • 언론사별 RSS entry를 독립적으로 처리하고, 실패한 feed가 전체 수집을 중단시키지 않게
    해야 했습니다.
  • 썸네일과 본문은 여러 위치에서 추출하되 광고/추적 이미지를 제외해야 했습니다.
행동 · Action

Rome과 Jsoup 기반 파싱 흐름에 정규화와 중복 방지를 결합했습니다.

  • Rome으로 RSS XML을 feed·entry 단위로 파싱하고, 각 feed를 독립 처리해 특정 언론사 실패가
    전체 수집 실패로 번지지 않게 했습니다.
  • RSS entry의 제목·설명·본문·URL·썸네일·작성자·발행일·언론사·카테고리 정보를 내부 기사 모델로 변환했습니다.
  • 썸네일은 enclosure → media RSS → HTML 본문 이미지 순서로 탐색하고, pixel·beacon·tracking 성격의 이미지는 제외했습니다.
  • Jsoup으로 HTML 태그를 제거하고, 언론사별 불필요 문구·공백을 정규화해 임베딩 입력 품질을 높였습니다.
  • PostgreSQL URL unique constraint와 conflict ignore 전략으로 이미 저장된 기사는
    skip 처리했습니다.
  • 수집 결과는 inserted·skipped·errors로 나누어 기록해 수집량 증가와 실패 원인을
    확인할 수 있게 했습니다.
결과 · Result
  • RSS 원본을 서비스 내부에서 일관되게 사용할 수 있는 기사 데이터로 정리했습니다.
  • 중복 URL과 품질 낮은 이미지/본문이 임베딩 단계로 넘어가는 비율을 줄였습니다.
Newstagram · RSS 기사 수집 김용준 · Technical Portfolio
03 NewstagramWork 3 of 3
15 / 27
03 Newstagram · Work 3

기사 임베딩 파이프라인

Tech Stack OpenAI text-embedding-3-large · dimensions=1536 · pgvector · batch embedding · response validation · semantic search
상황 · Situation

같은 이슈도 언론사마다 표현이 달라 단순 키워드로는 안정적으로 묶기 어려웠습니다.

  • 사용자의 자연어 검색과 기사 추천은 의미적으로 가까운 기사를 찾을 수 있어야 했습니다.
  • 임베딩 API 호출은 비용·시간이 들기 때문에 이미 처리된 기사와 미처리 기사를 구분해야 했습니다.
과제 · Task

기사 텍스트를 벡터로 변환하고, pgvector 기반 검색과 클러스터링에
재사용해야 했습니다.

  • 임베딩 입력은 너무 길지 않으면서 제목과 본문의 의미를 충분히 담아야 했습니다.
  • 외부 임베딩 API 응답 개수와 벡터 차원을 검증한 뒤 저장해야 데이터 무결성을 유지할 수 있었습니다.
행동 · Action

미임베딩 기사만 선별해 OpenAI 임베딩과 pgvector 저장 흐름으로 연결했습니다.

  • PostgreSQL에서 embedding 값이 비어 있는 기사만 조회해 이미 처리된 기사에 대한 중복 비용을 줄였습니다.
  • 임베딩 입력은 정규화된 제목·본문을 결합하고, 제목의 불필요 패턴을 제거한 뒤 본문 길이를 제한해
    API 입력 크기를 관리했습니다.
  • batch size를 적용해 여러 기사 입력을 묶어 text-embedding-3-large에 dimensions=1536을 지정해 1536차원 임베딩을 생성했습니다.
  • 임베딩 API 응답 개수가 요청 입력 개수와 일치하는지 검증하고, 불일치 시 해당 배치를 실패 처리해 잘못된 벡터 매핑을 방지했습니다.
  • 생성된 float 배열은 pgvector가 이해할 수 있는 vector literal로 변환해
    PostgreSQL vector(1536) 컬럼에 저장했습니다.
  • source 단위 retry와 성공/skip 로그를 남겨 특정 언론사·기사에서 반복 실패가 발생하는지 추적했습니다.
결과 · Result
  • 기사 의미 검색·자연어 프롬프트 검색·기간별 이슈 클러스터링에 사용할 벡터 데이터 기반을 구축했습니다.
  • 1536차원 기사 임베딩을 pgvector에 저장해 검색과 추천 기능의 핵심 데이터로 재사용했습니다.
Newstagram · 기사 임베딩 파이프라인 김용준 · Technical Portfolio
Project 04Project A601 · 실시간 WebRTC 마피아
15 / 26
04 · Project A601

WebRTC와 WebSocket을 결합한
AI 판결 기반 실시간 마피아 게임

Project A601은 SF 세계관의 실시간 마피아 게임입니다. LiveKit WebRTC로 영상/음성 대화를 제공하고, STOMP WebSocket으로 방 상태·게임 페이즈·직업 능력·사망·AI 판결 결과를 동기화했습니다.
저는 PMFrontend를 맡아 게임 루프·반응형 인게임 UX·LiveKit 권한 제어·STOMP 이벤트 상태 관리를 설계했고, 특히 게임이 처음부터 끝까지 끊기지 않도록 서버 이벤트와 클라이언트 연출 사이의 완충 구조를 만들었습니다.

React TypeScript Zustand LiveKit WebRTC STOMP SockJS Responsive Game UX
  • Work 1PM·게임 루프 설계 및 몰입형 반응형 UX
  • Work 2LiveKit WebRTC 권한 제어
  • Work 3STOMP WebSocket · 상태관리
Project A601 표지 이미지
2026.01.06 – 2026.02.09 · 4명 PM · Frontend · WebRTC/WebSocket UX
04 A601Work 1 of 3
17 / 27
04 Project A601 · Work 1

PM · 게임 루프 설계 및 몰입형 반응형 UX

Tech Stack React · TypeScript · Zustand · state machine · ResizeObserver · responsive game board · stage transition UX
상황 · Situation

실시간 마피아 게임은 규칙·통신·연출이 한 박자라도 어긋나면 몰입이 깨집니다.

  • 대기방·역할 공개·낮 토론·AI 판결·밤 능력·결과·엔딩이 서버 페이즈와 맞춰 진행되어야 했습니다.
  • 모바일과 데스크톱에서 영상 타일·채팅·타이머·버튼·모달이 동시에 보이는 게임 UI를 유지해야 했습니다.
과제 · Task

서버 이벤트를 그대로 반영하지 않고, 사용자가 이해할 수 있는 단계 전환으로
보여줘야 했습니다.

  • 서버 페이즈 전환은 즉시 오지만, 클라이언트는 역할 공개·결과 연출 같은 완충 화면이 필요했습니다.
  • 게임 상태와 UI 연출 상태를 분리해 갑작스러운 화면 전환과 중복 렌더링을 막아야 했습니다.
행동 · Action

게임 단계를 상태 머신처럼 모델링하고 반응형 스테이지 UX로 연결했습니다.

  • 게임 단계를 lobby·role·morning·ai·judgment·night·result·ending처럼 명확한 stage로 나누고
    각 stage의 UI·입력 가능 행동을 분리했습니다.
  • 서버의 GAME_PHASE 이벤트는 Zustand의 현재 stage·대기 stage·timerEnd·currentTurn
    상태로 변환해 화면이 서버 이벤트를 직접 해석하지 않도록 했습니다.
  • GAME_START 직후에는 역할 공개 인트로를 먼저 보여주고, 짧은 타이머 이후 pending stage로 이동하게 해 역할 확인 없이 게임이 시작되는 문제를 막았습니다.
  • 역할별 색상·설명·능력 안내·사망자/생존자 상태를 UI variant로 분리해 같은 화면에서도 상태가
    명확히 보이도록 했습니다.
  • 고정 기준 캔버스와 ResizeObserver 기반 스케일링으로 모바일에서도 영상 타일·판결문·액션 버튼이 겹치지 않게 조정했습니다.
  • BGM·효과음·AI 판결 연출·타이핑 자막·글리치/스캔라인 효과를 stage 전환과 연결해
    SF 마피아 세계관의 몰입감을 강화했습니다.
결과 · Result
  • 대기방부터 엔딩까지 완주 가능한 게임 루프를 만들고, 서버 이벤트와 사용자 연출 사이의 충돌을 줄였습니다.
  • SSAFY 공통프로젝트에서 A601 프로젝트가 우수상을 수상했습니다.
A601 · 게임 루프 설계 김용준 · Technical Portfolio
04 A601Work 2 of 3
18 / 27
04 Project A601 · Work 2

LiveKit WebRTC 권한 제어

Tech Stack LiveKit · WebRTC · local publish control · media publication · deviceId switching · remote audio subscription · dead-user guard
상황 · Situation

마피아 게임은 생존 여부와 낮/밤 페이즈에 따라 말할 수 있는 사람이 달라집니다.

  • 대기방에서는 모두가 말할 수 있지만, 밤이나 사망 상태에서는 음성/영상 권한이 제한되어야 했습니다.
  • 미디어 제어와 게임 이벤트를 한 통신으로 처리하면 디버깅과 권한 관리가 복잡해질 위험이 있었습니다.
과제 · Task

WebRTC 미디어 권한을 게임 상태와 정확히 맞추면서도 사용자 장치 설정은
유지해야 했습니다.

  • 카메라·마이크·화면 공유·원격 오디오 구독을 페이즈와 생존 상태에 따라 다르게 제어해야 했습니다.
  • 사망자도 게임을 관전할 수 있어야 하지만 생존자 토론에 영향을 주면 안 됐습니다.
행동 · Action

LiveKit은 미디어 전용 계층으로 두고, STOMP 게임 상태를 기준으로 권한을 계산했습니다.

  • 방 입장 시 Backend에서 받은 LiveKit URL·token으로 room에 join하고, 영상/음성 송수신은 LiveKit이 전담하도록 통신 책임을 분리했습니다.
  • 로컬 참가자의 camera·microphone publication 상태를 읽어 장치 설정 화면에서 선택된 deviceId로 카메라·마이크를 전환할 수 있게 했습니다.
  • 사망자 감지 로직을 두어 dead user가 되면 camera·microphone·screen share publish를
    즉시 중단하고, 대기방·게임 종료 시 복구할 수 있게 했습니다.
  • 원격 오디오 구독은 lobby·morning·night처럼 대화가 허용되는 stage에서만 활성화해
    AI 판결·결과 연출 중 불필요한 음성이 섞이지 않도록 했습니다.
  • 서버 게임 상태(STOMP)와 클라이언트 media publish 제어를 함께 사용해 네트워크 지연·UI 불일치가 있어도 발화 가능 상태가 게임 규칙에 맞게 제한되도록 이중 방어했습니다.
  • 영상 타일에는 mute·speaking·ready·dead·role badge 같은 상태 표시를 결합해 미디어 상태와
    게임 상태가 한눈에 보이도록 했습니다.
결과 · Result
  • 영상/음성 통신은 LiveKit으로 안정화하고, 게임 규칙에 따른 권한 제어는 상태 기반으로 처리하는 구조를 만들었습니다.
  • 사망자 관전·밤 페이즈·AI 판결 연출처럼 복잡한 상황에서도 미디어 권한이 게임 규칙과 맞게 동작했습니다.
A601 · LiveKit WebRTC 권한 김용준 · Technical Portfolio
04 A601Work 3 of 3
19 / 27
04 Project A601 · Work 3

STOMP WebSocket · 상태관리

Tech Stack STOMP · SockJS · topic subscription Map · Zustand slice · reconnect delay · event-driven UI · role action publish
상황 · Situation

게임 이벤트는 모든 플레이어에게 가는 메시지와 개인에게만 가는 메시지가
섞여 있었습니다.

  • 방 입장·준비·게임 시작·페이즈 변경·직업 능력·AI 결과·사망 처리가 실시간으로 동기화되어야 했습니다.
  • 역할 정보와 밤 능력 결과는 개인 메시지로만 전달되어야 해 전체 room topic과 분리할 필요가 있었습니다.
과제 · Task

STOMP 메시지를 안정적으로 구독하고, Zustand 상태로 변환해 UI가 일관되게
반응해야 했습니다.

  • 중복 구독·재연결·메시지 순서 차이로 인한 stage 꼬임을 줄여야 했습니다.
  • 직업별 publish destination과 수신 이벤트 처리를 명확히 나눠야 유지보수가 가능했습니다.
행동 · Action

STOMP Client와 Zustand store 사이에 이벤트 해석 계층을 두었습니다.

  • SockJS 기반 STOMP 연결에서 Authorization·roomId·room 입장 검증 정보를 header로 전달하고, reconnect delay 설정으로 일시적 연결 끊김에 대응했습니다.
  • 구독 정보를 Map으로 관리해 같은 topic을 중복 구독하지 않도록 하고, room topic과
    personal topic을 분리했습니다.
  • publish destination은 준비·게임 시작·AI 변론·직업 능력·방어·CCTV·처형 선택처럼 역할 행동별로 나누어 서버 API 계약이 UI에 흩어지지 않게 했습니다.
  • 수신 메시지는 개인 메시지와 방 메시지를 먼저 구분하고, GAME_PHASE·AI_RESULT·PLAYER_DEATH·ROLE_ASSIGNED 같은 이벤트 타입별로
    Zustand 상태를 갱신했습니다.
  • GAME_PHASE는 stage·timer·turn 정보를 갱신하고, AI_RESULT는 판결 결과만 저장해
    결과 표시 시점은 stage 전환이 담당하게 했습니다.
  • PLAYER_DEATH 이벤트는 사망자 목록과 결과 상태를 동시에 갱신하고, LiveKit 권한 제어 로직과 연결해 미디어 권한까지 반영되도록 했습니다.
결과 · Result
  • WebRTC 미디어와 WebSocket 게임 이벤트를 분리하면서도 하나의 인게임 UX로 연결했습니다.
  • 방 상태·개인 역할·게임 페이즈·직업 능력 결과가 각 플레이어 화면에 맞게 반영되었습니다.
A601 · STOMP WebSocket 김용준 · Technical Portfolio
Project 05용돈농장 · 청소년 금융 교육 백엔드
19 / 26
05 · 용돈농장

부모와 자녀가 함께 금융 행동을 경험하는
청소년 금융 교육 백엔드

용돈농장은 부모가 관리하는 환경에서 자녀가 용돈·예금·적금·대출·일과 보상·신용점수를 경험하는 금융 교육 서비스입니다. 금융 행동이 단순 화면 상태가 아니라 거래 장부·상품 가입 상태·신용점수 이력으로 남도록 설계하는 것이 중요했습니다. 저는 Backend를 담당하며 DB 설계·도메인 모델링·QueryDSL 복잡 조회 API를 구현했고, 특히 부모-자녀 관계·상품 가입 가능 여부·신용점수·대출 상환 상태처럼 조건이 많은 도메인을 JPAQueryDSL로 정리했습니다.

Spring Boot JPA QueryDSL PostgreSQL JWT OAuth2 Redis SSAFY 금융 API
  • Work 1DB 설계 · 도메인 모델링
  • Work 2QueryDSL 복잡 조회 API 구현
용돈농장 표지 이미지
Backend · 금융 도메인 모델링 JPA · QueryDSL · 금융 API · 인증/인가
05 용돈농장Work 1 of 2
21 / 27
05 용돈농장 · Work 1

DB 설계 · 도메인 모델링

Tech Stack Spring Data JPA · @MapsId · @OneToOne · @ManyToOne · aggregate modeling · domain method · state transition
상황 · Situation

금융 교육 서비스는 한 번의 사용자 행동이 여러 도메인 상태와 이력에 영향을 줍니다.

  • 예금 가입·적금 납입·대출 승인·대출 상환·일과 보상은 자녀 자산·신용점수·거래 이력에 함께 반영되어야 했습니다.
  • 부모와 자녀는 같은 데이터를 보더라도 권한·행동 범위가 달라 관계 기반 인가가 필요했습니다.
과제 · Task

공통 사용자·자녀 프로필·금융 상품·가입 내역·대출 상태를 추적 가능한 모델로
분리해야 했습니다.

  • 사용자 인증 정보와 자녀 금융 속성을 한 테이블에 섞으면 권한·도메인 정책이 복잡해질 수 있었습니다.
  • 상품 마스터와 자녀 가입 상태를 분리해 상품 정책 변경과 가입 이력을 독립적으로 관리해야 했습니다.
행동 · Action

JPA 연관관계와 도메인 메서드로 금융 상태 변경 규칙을 모델 내부에 모았습니다.

  • 공통 사용자 모델에는 인증·프로필·역할 정보를 두고, 자녀 모델은 같은 식별자를 공유하는
    one-to-one 구조로 분리했습니다.
  • 자녀 모델은 부모와 many-to-one 관계를 가지며, 용돈 금액·지급일·신용점수·리뷰 점수·대출 금리 같은 금융 속성을 별도로 보유했습니다.
  • @MapsId를 활용해 공통 사용자와 자녀 프로필의 식별자를 맞추고, 인증 계층과 자녀 금융 도메인의 책임을 분리했습니다.
  • 부모 연결·용돈 설정·신용점수 변경은 도메인 메서드로 캡슐화하고, 신용점수는 최소/최대 범위 보정이 적용되도록 했습니다.
  • 예금/적금 상품 마스터와 자녀 가입 엔티티를 분리해
    상품 조건·가입 상태·시작일·종료일·가입 금액·보상·서명 이미지를 따로 관리했습니다.
  • 대출은 부모·자녀·원금·금리·잔액·상태를 가진 모델과 상환 이력을 분리하고,
    상환 금액 검증·잔액 0원 완료 처리를 도메인 규칙으로 만들었습니다.
결과 · Result
  • 부모-자녀 관계·금융 상품·가입 상태·대출 상환·신용점수 이력을 추적 가능한 백엔드 모델로 구성했습니다.
  • 금융 이벤트가 단순 상태 변경이 아니라 장부와 이력으로 남을 수 있는 기반을 만들었습니다.
용돈농장 · DB 설계·도메인 모델링 김용준 · Technical Portfolio
05 용돈농장Work 2 of 2
22 / 27
05 용돈농장 · Work 2

QueryDSL 복잡 조회 API 구현

Tech Stack QueryDSL · JPAQueryFactory · Projection DTO · CaseBuilder · not exists subquery · composite cursor · fetch join
상황 · Situation

상품 목록과 금융 이력 조회는 단순 CRUD보다 많은 조건을 동시에 계산해야 했습니다.

  • 자녀 신용점수에 따라 가입 가능 여부가 달라지고, 이미 가입 중인 상품은 목록에서
    제외되어야 했습니다.
  • 신용점수 이력과 대출 거래 내역은 커서 페이지네이션과 동적 조건이 필요했습니다.
과제 · Task

가입 가능 상품을 우선 정렬하면서도 무한 스크롤에서 누락과 중복을 막아야 했습니다.

  • 정렬 기준이 가입 가능 여부와 상품 ID로 복합 구성되어 단순 ID 커서만으로는 안정적인
    다음 페이지 조회가 어려웠습니다.
  • 여러 연관 테이블의 조건을 조합하되 API 응답은 화면에서 바로 사용할 수 있는
    DTO 형태여야 했습니다.
행동 · Action

QueryDSL Custom Repository로 조회 책임을 분리하고 복합 커서를 설계했습니다.

  • JPAQueryFactory를 중심으로 복잡 조회 전용 Custom Repository를 구성해 단순 CRUD와
    동적 조회 책임을 분리했습니다.
  • 상품 목록은 Projection DTO로 바로 조회하고, 자녀의 현재 신용점수와 상품 최소 신용점수를 비교하는 subquery로 가입 가능 여부를 계산했습니다.
  • QueryDSL CaseBuilder를 사용해 가입 가능 상품을 먼저 보여주고, 같은 그룹 안에서는
    최신 상품 순으로 정렬했습니다.
  • 현재 ACTIVE 상태로 가입 중인 자녀 상품은 not exists subquery로 제외해 중복 가입 가능성이 화면에 노출되지 않게 했습니다.
  • 커서는 가입 가능 여부 커서와 상품 ID 커서를 함께 사용해 available 그룹에서 unavailable 그룹으로 넘어갈 때도 누락과 중복을 줄였습니다.
  • 신용점수 이력은 createdAt과 ID 복합 커서를 사용하고, 자녀 연관 정보를 fetch join해
    N+1 조회 위험을 줄였습니다.
결과 · Result
  • 가입 가능 상품 우선 정렬·중복 가입 제외·커서 페이지네이션·신용점수 이력 조회를 안정적으로 구현했습니다.
  • 금융 도메인 조회를 QueryDSL로 분리해 화면 요구사항이 복잡해져도 API 응답 구조를
    유지할 수 있게 했습니다.
용돈농장 · QueryDSL 복잡 조회 김용준 · Technical Portfolio
Project 06AutoQA · AI 웹 QA 자동화
22 / 26
06 · AutoQA

웹 분석 결과를 실행 가능한 QA 시나리오로
바꾸는 AI 테스트 자동화 플랫폼

AutoQA는 URL을 분석해 웹 페이지의 액션 후보와 흐름을 추출하고, AI가 Playwright로 실행 가능한 QA suite JSON을 생성하며, 실제 브라우저 실행 결과를 리포트로 제공하는 플랫폼입니다. 핵심은 "그럴듯한 테스트 설명"이 아니라 validator와 실행기가 통과할 수 있는 구조화 JSON을 만드는 것이었습니다. 저는 PMAI 파트를 맡아 학습용 데이터셋 구축·SFT/DPO 학습·Qwen3-8B 기반 모델 개선·vLLM 추론 환경과 JSON 검증 구조를 설계했습니다.

Qwen3-8B LoRA SFT DPO vLLM Guided JSON Playwright Validator
  • Work 1AI 모델 학습용 데이터셋 구축
  • Work 2SFT · DPO 학습 & 모델 개선
  • Work 3추론 환경 개선
AutoQA 표지 이미지
2026.04.06 – 2026.06.02 · 6명 PM · AI · 데이터·SFT/DPO·추론 설계
06 AutoQAWork 1 of 3
24 / 27
06 AutoQA · Work 1

AI 모델 학습용 데이터셋 구축

Tech Stack SFT dataset · DPO negative pair · QA contract · strict JSON · nodeId whitelist · Playwright executable scenario
상황 · Situation

LLM이 만든 테스트 케이스는 자연어로는 좋아 보여도 실제 실행 계약을
자주 어겼습니다.

  • 실제 분석 결과에 없는 nodeId를 참조하거나, 클릭할 수 없는 대상에 click step을 생성하는
    문제가 있었습니다.
  • 웹 분석 산출물은 길고 복잡해 그대로 학습 입력으로 쓰기 어렵고, 모델이 중요한 후보를
    놓칠 수 있었습니다.
과제 · Task

웹 분석 결과와 실행 가능한 QA suite JSON을 연결하는 학습 데이터를
만들어야 했습니다.

  • 모델이 설명문이 아니라 정해진 contract를 만족하는 JSON을 출력하도록 입력/출력 형식을 고정해야 했습니다.
  • 좋은 예제뿐 아니라 실패 유형을 명확히 담은 negative pair가 필요했습니다.
행동 · Action

실제 AutoQA 파이프라인 산출물을 학습 가능한 SFT/DPO 데이터로 재구성했습니다.

  • 웹 분석 결과에서 site summary·analysis summary·action candidate·QA suite JSON을 추출해 모델 입력과 정답 출력으로 연결했습니다.
  • self-generated 데이터·수작업 보강 데이터·teacher 모델 데이터를 합쳐 다양한 사이트와 시나리오 유형을 포함하도록 구성했습니다.
  • 시나리오 개수·step type 다양성·unique nodeId 비율·reasoning 중복도·contract 위반 여부를 기준으로 학습 데이터 품질을 필터링했습니다.
  • SFT message는 system prompt·QA contract·정책·site summary·analysis summary·instruction을 입력으로 제공하고 assistant가 strict JSON만 출력하도록 만들었습니다.
  • DPO rejected는 hallucinated nodeId·invalid click target·whitelist violation·duplicated reasoning·mode collapse처럼 실행 실패와 직접 연결되는 유형을 중심으로 만들었습니다.
  • 목표를 "테스트 케이스 설명 생성"이 아니라 "Playwright 실행기가 소비할 수 있는 QA JSON 생성"으로 고정해 학습 데이터의 평가 기준을 명확히 했습니다.
결과 · Result
  • 139개 사이트에서 수집한 원본 QA 시나리오를 정제해 clean scenario와 DPO negative pair를 구축했습니다.
  • 모델 학습 기준을 자연어 품질이 아니라 validator 통과 가능성·실행 가능성으로 전환했습니다.
AutoQA · 데이터셋 구축 김용준 · Technical Portfolio
06 AutoQAWork 2 of 3
25 / 27
06 AutoQA · Work 2

SFT · DPO 학습 & AI 모델 개선

Tech Stack Qwen3-8B · LoRA · QLoRA · SFT · DPO · gradient checkpointing · contract validation · mode collapse analysis
상황 · Situation

긴 웹 분석 입력과 구조화 JSON 출력은 일반 LLM 호출만으로
안정화하기 어려웠습니다.

  • 초기 모델 실험에서는 긴 context로 인한 OOM·device map 문제·JSON truncation·특정 사이트 mode collapse가 발생했습니다.
  • 모델은 nodeId·action type을 정확히 따라야 했기 때문에 창의적 답변보다 계약 준수가 중요했습니다.
과제 · Task

제한된 GPU 환경에서 모델을 학습하고, 실행 가능한 QA JSON 생성 성능을
개선해야 했습니다.

  • LoRA/QLoRA 기반으로 학습 비용을 줄이면서도 JSON 구조와 QA 정책을 모델에
    주입해야 했습니다.
  • SFT 이후에도 반복되는 실패 유형은 DPO로 선호 방향을 조정해야 했습니다.
행동 · Action

모델 후보 실험·LoRA 타깃 조정·SFT/DPO 학습·평가 지표를 반복했습니다.

  • 초기 Gemma 계열 LoRA/QLoRA 실험에서 긴 context OOM·multimodal tower/device-map 리스크를 확인하고, 구조화 JSON 생성에 더 적합한 Qwen3-8B를 production 후보로 전환했습니다.
  • LoRA target module은 language model projection 중심으로 제한하고,
    gradient checkpointing·KV cache off·sequence length 조정으로 메모리 사용량을 낮췄습니다.
  • SFT에서는 scenarioId·category·priority·preconditions·steps·targetRef·expectedSignals 같은 QA contract 필드를 반복 학습시켰습니다.
  • DPO에서는 없는 nodeId 생성·클릭 불가능 대상·whitelist 위반·reasoning 중복·특정 사이트만 반복하는 mode collapse를 rejected로 구성했습니다.
  • 평가는 validator pass rate·step 다양성·unique nodeId 비율·contract violation·JSON parse 실패·truncation 비율을 함께 확인했습니다.
  • 학습 결과와 추론 실패 사례를 다시 데이터셋으로 되돌리는 루프를 만들고, self-generated positive와 수작업 예제를 보강하는 방향으로 개선했습니다.
결과 · Result
  • Qwen3-8B 기반 SFT/DPO 학습 파이프라인을 구축하고, 실행 가능한 QA JSON 생성에 맞춘
    모델 개선 루프를 만들었습니다.
  • Stage A SFT train loss 0.6776, Stage C DPO train loss 0.1680으로 학습 수렴을 추적하고, validator pass·parse fail·truncation·nodeId hallucination을 별도 평가 지표로 관리했습니다.
AutoQA · SFT·DPO 학습 김용준 · Technical Portfolio
06 AutoQAWork 3 of 3
26 / 27
06 AutoQA · Work 3

추론 환경 개선

Tech Stack vLLM · LoRA adapter · prefix caching · guided JSON schema · token clamp · nodeId whitelist · validation fallback
상황 · Situation

학습된 모델도 운영 추론에서 입력 길이·JSON 깨짐·잘못된 target 선택 문제를
다시 만날 수 있었습니다.

  • 웹 분석 요약은 사이트마다 크기가 달라 prompt token이 크게 흔들렸습니다.
  • 한 번에 많은 시나리오를 만들게 하면 출력이 잘리거나 schema를 벗어나는 문제가 발생했습니다.
과제 · Task

vLLM 기반 추론을 안정화하고, 생성 결과를 validator가 통과할 수 있는 suite로
정규화해야 했습니다.

  • 입력은 학습 때 사용한 형식과 최대한 맞추되 운영 환경의 길이 제한을 넘지 않아야 했습니다.
  • 모델 출력은 guided JSON으로 제한하고, 후처리에서 nodeId·action target을 다시 검증해야 했습니다.
행동 · Action

전처리·vLLM 런타임·생성 오케스트레이션·검증 후처리를 분리했습니다.

  • site summary와 analysis summary를 학습 입력과 같은 구조로 압축하고,
    page·action candidate 수를 제한해 prompt 길이를 안정화했습니다.
  • autoScenarioEligible·importance·candidateConfidence 기준으로 후보 우선순위를 정하고,
    form·container 태그처럼 클릭이 항상 실패하는 후보는 입력 단계에서 제외했습니다.
  • vLLM은 Qwen3-8B와 LoRA adapter를 로드하고, prefix caching·prompt 길이 기반
    max token clamp로 처리량과 안정성을 조정했습니다.
  • 생성은 category별 round plan으로 나누고, 한 round에 하나의 scenario만 생성하도록
    guided JSON schema의 maxItems를 제한해 truncation을 줄였습니다.
  • 출력 후에는 단일 scenario 추출·nodeId whitelist 검증·action step 검증·matcher/signal 정규화·중복 제거를 거쳐 최종 suite로 조립했습니다.
  • 검증 실패 시 전체 실패가 아니라 재생성·보정·drop fallback을 적용해 남은 유효 scenario라도 사용자에게 제공되도록 정책을 세웠습니다.
결과 · Result
  • 모델 추론을 단순 텍스트 생성이 아니라 전처리·guided JSON·검증·fallback이 포함된
    운영 파이프라인으로 개선했습니다.
  • AI 생성 결과가 Backend validator와 Playwright 실행기로 넘어갈 수 있는 구조적 안정성을 확보했습니다.
AutoQA · 추론 환경 개선 김용준 · Technical Portfolio
Closing김용준 · 마무리
26 / 26
Closing

제가 반복해서 해온 일은
복잡한 흐름을 사용 가능한 제품으로
정리하는 것입니다.

BeBig에서는 금융 데이터를 행동으로, GBCamera에서는 현장 운영을 자동 흐름으로, Newstagram에서는 뉴스 데이터를 추천 파이프라인으로,
A601에서는 실시간 통신을 게임 규칙으로, 용돈농장에서는 금융 이벤트를 백엔드 도메인으로,
AutoQA에서는 AI 출력을 실행 가능한 QA 시스템으로 연결했습니다.

Backend 설계와 구현 Frontend UX 구현 AI 데이터/모델 파이프라인 PM 의사결정 제품 완성 경험
Email maple5741@naver.com
GitHub github.com/Yongjooon
Phone 010-7153-6922