정영길

제품 하나를 끝까지 만들고,
현장에서 터진 문제를 원인까지 찾아 고치는
풀스택 개발자입니다.

프론트엔드 3년을 거쳐, 고객사 환경에 직접 설치되어 24시간 무중단으로 도는 제품을 맡고 있습니다.
웹 개발자가 없던 초기 4개월간 신규 제품을 풀스택으로 단독 개발했고,
디스크가 차서 멈추던 700GB 테이블과 운영 장애를 직접 해결했습니다.

신규 제품 풀스택 단독 개발 · 700GB 테이블 구조 개선 · 부팅·실시간 연결 장애 원인 규명
younggil94@naver.com GitHub 기술 블로그

경력 요약

화면부터 API·데이터 모델링·배포 운영까지 한 제품의 전 구간을 맡는 풀스택 개발자입니다. 프론트엔드 3년을 거쳐 전 구간으로 범위를 넓혔습니다. 현재 제품은 고객사 환경에 직접 설치되어 24시간 무중단으로 돌아갑니다 — 원격 접속·롤백·점검 창이 자유롭지 않고 고객사마다 DB 상태와 화면 구성이 다른 조건에서 스키마 변경과 배포를 수행합니다.

경력 5년 3개월 (2020.11 ~ 재직 중)
핵심 역량 대용량 테이블 파티셔닝 · 운영 DB 마이그레이션 이관 · 무중단 장애 원인 분석 · 프론트엔드 성능·테스트 자동화
대표 지표 700GB · 12개 테이블 무중단 파티셔닝(중단 0분) · 3억 2,804만 행 COUNT(*) 87초 제거 · 스토리지 사고 후 11만 건 복구 · E2E 40개 / 고객사 5곳 / 9분 43초
주요 기술 React · TypeScript  /  NestJS · Prisma · PostgreSQL  /  Kubernetes · Helm · ArgoCD
기록 기술 블로그 12편

전 구간을 끝까지 책임집니다. 웹 개발자가 없던 초기 4개월간 신규 제품을 풀스택으로 단독 개발했습니다. 백엔드 API와 화면 전체를 설계·구현하고, 고객사로 나가는 배포 구성까지 다룹니다. 현재는 합류한 풀스택 개발자 1명과 2인 체제로 같은 제품을 운영하며, 시스템 구조와 운영 프로세스의 온보딩을 맡고 있습니다.

반복 비용은 코드가 아니라 구조로 없앱니다. 하루 16만 건이 적재되며 디스크가 차면 쓰기가 실패하고 서비스가 멈추던 12개 테이블(약 700GB)을 DELETE 기반 정리에서 RANGE 파티셔닝 + DROP PARTITION 구조로 전환했습니다(기본 키 전면 재설계). 정식 점검 창을 잡을 수 없는 24시간 서비스라, RENAME swap + 최근 N일치만 이관으로 쪼개 트래픽이 비는 짧은 구간마다 배포해 서비스 중단 0분으로 끝냈고, 정리 작업은 수동 10~30분 → 스케줄러 자동이 됐습니다.

증상이 아니라 원인을 찾습니다. 재현되지 않는 장애는 조건을 하나씩 통제하며 범위를 좁힙니다. 부팅을 막던 3억 2,804만 행 COUNT(*)(87,371ms)를 제거했고, 하나의 증상 뒤에 있던 서로 무관한 원인 3건을 각각 규명했습니다 — 그중 공용 훅 한 곳을 고치자 같은 함정의 폴링 6개가 전부 보호됐습니다. 고칠 때는 재발 시 확인할 진단 수단을 함께 배포합니다.

프론트엔드 3년의 기준을 유지합니다. CI가 없던 프론트엔드에 목을 쓰지 않는 E2E를 붙여, 푸시마다 테스트 40개 · 고객사 5곳 · 9분 43초가 돌게 했습니다. 그 외 공통 컴포넌트 표준화, 서버/클라이언트 상태 분리, 렌더링 전략 구분, 하루 1.8만 건 화면의 가상 리스트 전환이 주로 다룬 주제입니다.

해결한 문제는 배경과 검토한 선택지, 그중 무엇을 왜 택했는지까지 정리해 글로 남깁니다.

기술적 역량

Backend & Data

NestJS Node.js TypeScript Prisma PostgreSQL Redis Stream REST API SSE Socket.IO

운영 DB의 파티셔닝, 인덱스, 마이그레이션 이관 작업을 직접 수행했습니다.

Infra & DevOps

Docker Kubernetes Helm ArgoCD Bitbucket Pipelines GitOps

제품이 고객사 Kubernetes 환경에 설치되는 구조라, Helm 차트가 곧 각 사이트의 구성입니다. 기존 Helm/ArgoCD 구성을 인계받아 차트 수정, 파드 리소스 조정, 빌드·배포 파이프라인 구성을 담당했고, 테스트용 목 서버는 ArgoCD Application을 새로 구성해 올렸습니다.

Frontend

React Next.js TypeScript React Query Zustand Tailwind CSS Storybook React Native

React 기반 화면을 3년간 담당했고, 공통 컴포넌트 표준화와 대용량 목록 가상화, 권한 기반 화면 제어를 직접 구현했습니다.

Sub & Tools

Go (Wails) WPF / C# Claude Code Jira/Slack/Git Figma

현장 PC용 데스크톱 앱을 Go(Wails)로 재작성했고, Claude Code 커맨드로 리뷰·PR 작업을 자동화했습니다.

대표 성과

Aivex에서 맡았던 작업입니다. 각 항목의 배경과 검토한 선택지, 무엇을 왜 택했는지는 기술 블로그에 정리해 두었습니다.

700GB

RANGE 파티셔닝으로 전환한 운영 테이블 12개
상위 3개가 각 ~250GB · 무중단 전환

3.28억 행

부팅을 막던 COUNT(*)가 읽던 행 수
87,371ms 소요 → 제거 후 정상 기동

11만 건

스토리지 사고 후 복구한 검사 데이터
112,835건 · 이미지 68,990건 복구

40개

푸시마다 도는 E2E 테스트 화면 구성이 다른 고객사 5곳
9분 43초 · 목 없이 실제 백엔드

12편

재직 중 작성한 기술 블로그 글
위 성과 전부가 글로 공개됨

Database

디스크가 차서 멈추던 장비

하루 16만 건이 쌓여 디스크가 차면 저장이 실패하고 장비가 멈췄습니다. 대량 DELETE는 VACUUM 부하로 오히려 write를 지연시켜 배제하고, 12개 테이블 약 700GB(상위 3개가 각 ~250GB)를 RANGE 파티셔닝으로 전환했습니다. 250GB를 전부 복사하는 대신 RENAME swap + 최근 N일치만 이관하고 테이블별로 트랜잭션을 쪼개, 라인이 쉬는 틈에 나눠 배포해 비가동 시간 없이 끝냈습니다. 정리 작업은 수동 10~30분 → DROP PARTITION 스케줄러 자동으로 바뀌었습니다.

📝 디스크가 꽉 차서 멈춘 검사 장비, 삭제를 없애기까지 — 대용량 테이블 파티셔닝 삽질기
Incident

연결이 끊긴 채 복구되지 않던 장애

장비를 재부팅해도 연결 끊김 표시가 사라지지 않고 브라우저 새로고침에만 복구됐습니다. 폴링 영구 정지 / heartbeat 미도달 / 재연결 취소 조건 — 서로 무관한 원인 3건을 각각 규명했습니다. 재귀 setTimeout을 finally로 옮겨 공용 훅 한 곳을 고치자 같은 함정에 걸려 있던 폴링 6개가 전부 보호됐고, heartbeat 10초 · watchdog 30초(3회 미수신) 기준으로 half-open을 감지하도록 바꿨습니다. 재발 시 쓸 진단 로그 수집도 함께 배포했습니다.

📝 연결은 살아있는데 데이터가 안 온다 — 새로고침해야만 복구되던 SSE 고치기
Architecture

데스크톱 앱 150MB → 10.9MB

웹 화면 하나를 띄우기만 하는 앱이 Chromium을 통째로 번들링해 150MB(157,664,256B)였습니다. Chromium 취약점이 나올 때마다 앱을 다시 빌드해야 하는, 엔진 수명주기를 앱이 떠안는 구조였습니다. OS에 이미 있는 웹뷰를 빌려 쓰는 Go/Wails로 재작성해 10.9MB(11,517,440B) 단일 exe가 됐습니다 — 93% 감소, 약 1/14. 빌드·설치 파일 생성·릴리스도 자동화해 버전 태그 push만으로 배포됩니다.

📝 웹 화면 하나 띄우는 데 150MB — Electron 래퍼를 Wails로 옮기기
Ownership

신규 제품 풀스택 단독 개발

실장비도 데이터도 확정 기획서도 없이 시작한 신규 제품에서 백엔드 API와 화면 전체를 단독 개발했습니다. 장비마다 다른 통신 규격을 하나의 인터페이스로 감싸는 추상화 계층을 두어 새 장비 유형이 붙어도 상위 로직을 바꾸지 않도록 설계했고, 이벤트는 Redis Stream으로 수신하되 최신 상태는 메모리 캐시로 조회하도록 나눴습니다. 수십만 건 이력의 엑셀 다운로드는 스트리밍 방식으로 구현해 조회 기간이 길어져도 서버 메모리가 일정하게 유지됩니다. 5개 스프린트에 걸쳐 Task 71건을 처리했고, 장비 동작을 모사하는 Mock 서버로 실장비 없이 인터페이스를 확정했습니다.

📝 센서 없이 시작한 프로젝트, 다섯 스프린트 동안 한 일
Recovery

스토리지가 찬 뒤 남은 11만 건

용량을 확보한 뒤에도 밀린 112,835건이 자동으로 복구되지 않았습니다. 업로드 에이전트가 최근 24시간의 미완료 건만 조회하고, 검사 전송은 이미지 상태가 확정되지 않은 건을 걸러내던 구조 — 앞단의 정체가 뒷단의 침묵으로 이어졌습니다. 복구 방식 3가지를 비교해 기간을 지정하는 신규 조회 경로를 택했고, 상시 폴링에 분기를 남기지 않도록 복구 전용 엔드포인트를 분리했습니다. 검사 결과는 전 구간, 이미지는 68,990건 복구. 원본이 이미 지워진 40,050건은 '없음 확정'으로 기록해 남겼습니다.

📝 스토리지가 찬 뒤 남은 11만 건 — 어디까지 복구할 수 있었나
Testing

목을 쓰지 않는 E2E — 고객사 5곳 화면을 푸시마다 검증

프론트엔드에는 CI 자체가 없어, 고객사별로 다른 화면 조합이 깨져도 배포 전에 알 방법이 없었습니다. 목을 쓰지 않고 실제 백엔드에 검사를 주입해 전역 집계까지 확인하는 E2E를 붙였습니다. 다만 모든 테스트가 하나의 백엔드를 공유해 병렬 실행 시 결과가 오염됐고 — 4회 중 2회 실패 — 병렬로 버는 시간은 10초 남짓이었습니다. 10초를 아끼자고 CI 게이트의 신뢰도를 바꿀 이유가 없어 워커를 1개로 고정했습니다. 지금은 푸시마다 테스트 40개 · 고객사 5곳(A 9 / B 6 / C 9 / D 8 / E 5) · 9분 43초가 돌고, 인증 → 잔여 페이지 정리 → 백엔드 설정 정합화 setup 3단계가 매 실행 앞단에서 스스로를 복구합니다. 남은 과제는 재시도로 덮인 플레이키 2건과, 직렬 10분이라 아직 머지 게이트로 걸지 못한 점입니다.

📝 끝까지 자동인 배포에 검증 한 칸 넣기 — 목을 쓰지 않는 E2E

경력 사항

Aivex

현재

Fullstack Engineer

2026.03 - 재직 중

산업 검사 장비의 운영 대시보드 개발 (기존 제품 + 신규 제품). 고객사 환경에 직접 설치되는 온프레미스 구조
프론트엔드(React) · 백엔드(NestJS/Prisma/PostgreSQL) · 현장 PC용 데스크톱 앱(Go) · 배포(Helm/ArgoCD) 담당
웹 개발자가 없던 초기 4개월간 웹 전 구간을 단독 담당했고, 이후 합류한 풀스택 개발자 1명과 2인 체제로 전환 — 시스템 구조와 운영 프로세스 인수인계를 담당
여섯 갈래 작업을 병행했습니다. 신규 제품 개발을 축으로 두고, 운영 이슈가 들어오면 그날 단위로 전환하는 방식으로 진행했습니다.

React TypeScript NestJS Prisma PostgreSQL Redis Stream SSE Go (Wails) Docker Kubernetes Helm ArgoCD

신규 제품 풀스택 단독 개발 — 5개 스프린트로 장비 연동 외 전 구간 완료

  • 백엔드 API 전체 신규 작성 — 도메인별로 책임 경계를 나눠 설계해, 기획이 자주 바뀌어도 변경 범위를 한 영역 안에 가둠. 기획이 계속 움직여 격일 스크럼으로 주기를 맞추고, 이해한 내용을 문서로 되돌려 팀에 검증받으며 진행
  • 장비 이벤트를 Redis Stream으로 수신·처리, 최신 상태는 메모리 캐시로 조회. 장비마다 다른 통신 규격을 하나의 인터페이스로 감싸는 추상화 계층 작성
  • 동시 유입 시 같은 데이터가 두 번 저장되고 주문 상태가 어긋나던 문제를 DB 락으로 처리 순서를 강제해 해소
  • 수십만 건 규모 이력의 엑셀 다운로드를 스트리밍 방식으로 구현 — 조회 기간이 길어져도 서버 메모리 사용량이 일정하게 유지
  • 화면 전체 구현 — 측정값 추이 차트 대시보드, 단계별 장비 초기 설정 마법사, 실시간 현황 패널, 주문 생성·조회, 권한 제어
  • 공통 기반 작성 — 전역 알림 토스트, 저장 전 이탈 방지 훅, 화면 밖으로 밀려나지 않는 모달 레이아웃, API 타임아웃·중복 요청 제거
  • 스프린트별 처리량은 16 → 6 → 9 → 14 → 25건. 초반이 얇은 건 담긴 게 만들 것이 아니라 알아낼 것이었기 때문 — 그때 정해진 것들이 마지막 스프린트에 25건을 담을 수 있게 함. 격일 스크럼과 스프린트 리뷰에 참여해 타 직군과 변경 주기를 맞춤
  • 매뉴얼에도 고객사 담당자에게도 없던 답을 현장 작업자 유선 문의로 확보. 가장 정확한 정보원은 문서가 아니라 장비를 매일 쓰는 사용자였음
  • 5개 스프린트 동안 실장비·데이터·확정 기획서 없이 진행. 그룹장이 세운 Epic·Story 체계 안에서 필요한 작업을 직접 티켓으로 분해해 처리(Task 71건)하고, 디자이너 / 판정 모듈 담당 / 제어 모듈 담당과 인터페이스를 맞춤. 장비 동작을 모사하는 Mock 서버를 만들어 말이 아닌 실제 데이터로 인터페이스를 조율

🚀 Impact: 장비 연동을 제외한 화면·API·데이터·인터페이스 검증까지 완료

📝 센서 없이 시작한 프로젝트, 다섯 스프린트 동안 한 일

대용량 테이블 파티셔닝 전환 (700GB · 12개) — 무중단 · 정리 작업 수동 10~30분 → 스케줄러 자동

  • 검사 한 건이 이미지 메타·ROI·시퀀스 등 여러 행을 파생시켜 하루 약 16만 건이 적재. 디스크가 차면 저장이 실패하고 24시간 무중단으로 도는 서비스가 정지. 팀 최우선 과제로 지정된 문제로, 그룹장이 지목한 대상 테이블을 받아 전환 방식 검토부터 구현·배포까지 담당
  • 대량 DELETE는 VACUUM 부하가 디스크를 붙잡아 신규 write를 지연시켜 배제. 삭제 시간대 분산도 "한가한 새벽"이 없는 24시간 가동 환경이라 기각
  • 12개 테이블 · 약 700GB를 PARTITION BY RANGE(created_at)로 전환 — 파티션 키를 포함하도록 기본 키 전면 재설계, 단일 행 보장이 깨지는 자리는 쓰기 로직을 updateMany → 0건이면 create로 교체. 부담이 상위 3개 테이블(각 ~250GB)에 몰려 있다는 점이 "최근 N일만 이관" 설계의 단서가 됨
  • 250GB를 전부 복사하는 대신 RENAME swap + 최근 N일치만 이관. 수백 GB 복사를 한 트랜잭션에 묶었다 막판에 깨지면 전부 롤백되므로 테이블별 개별 트랜잭션으로 분리 — 실패한 테이블만 TRUNCATE 후 재시도. ALTER SEQUENCE ... OWNED BY 이관까지 챙겨 swap 후 id 연속성 보존
  • 정식 점검 창을 확보할 수 없는 24시간 서비스라, 점심·휴식 등 트래픽이 비는 짧은 구간마다 테이블을 하나씩 전환하고, DB 구조 변경이 끝난 뒤 파티션 인지 코드를 배포하는 2단 분리로 진행 — 비가동 시간을 따로 잡지 않고 무중단으로 완료. swap 직후에는 매번 EXPLAIN ANALYZE로 partition pruning 작동을 확인한 뒤 트래픽 재개
  • 보관 기간만 설정하면 새 파티션 생성·만료 파티션 DROP을 자동 수행하는 스케줄러를 애플리케이션 안에 직접 구현 (pg_partman 대신 — 운영 제약과 로그·모니터링 가시성 때문. 되돌릴 수 없는 작업이라 단위 테스트 동반)
  • 고객사마다 DB 상태가 달라 현재 상태를 스스로 판별해 분기하는 스크립트로 prisma db push 운영을 prisma migrate 이력 체계로 이관. 기존 마이그레이션 4개를 통합본 1개로 정리하고, 이력 자체가 없는 DB는 전체 baseline 마킹으로 처리

🚀 Impact: 정리 작업이 10~30분 + 운영자 직접 실행에서 즉시 완료 + 스케줄러 자동 처리로 변경. 전환 전 구간 서비스 중단 0분

📝 디스크가 꽉 차서 멈춘 검사 장비, 삭제를 없애기까지 — 대용량 테이블 파티셔닝 삽질기 📝 고객사마다 제각각인 운영 DB를 prisma db push에서 migrate로 옮기기

SSE 실시간 연결 끊김 장애 수정 — 원인 3건 규명 · 훅 1곳 수정으로 폴링 6개 동시 보호

  • 장비를 재부팅해도 연결 끊김 표시가 사라지지 않고 브라우저 새로고침에만 복구되던 문제. 하나의 증상 뒤에 서로 무관한 원인 3건
  • ① 재귀 setTimeout 폴링이 콜백 reject 시 다음 실행을 예약하지 않아 영구 정지. 백엔드만 재시작되면 새로고침 전까지 상태 조회 0건 → finally로 옮겨 해소. 공용 훅 한 곳을 고치자 같은 함정에 걸려 있던 폴링 6개가 전부 보호됨 (비전 모듈 5초·모션 컨트롤러 3초 폴링 포함 — 내가 확인한 건 2개였고 나머지 4개는 덤)
  • ② heartbeat의 data가 빈 문자열이라 NestJS가 data: 라인을 생략했고, SSE 규격상 브라우저가 이벤트를 디스패치하지 않아 리스너가 한 번도 호출되지 않음. watchdog이 그동안 재고 있던 건 연결 상태가 아니라 "업무 이벤트 30초 부재" → 설비가 조용한 시간대마다 정상 연결을 30초마다 강제 재연결. 전송 형식 수정으로 오탐 제거 (heartbeat 10초 · watchdog 30초 = 3회 연속 미수신 기준)
  • ③ 데이터 수신 시 재연결 예약을 조건 없이 취소해, 버퍼에 남아 있던 이벤트 1건에 예약이 취소되며 복구가 최대 30초 지연 → 연결이 살아 있을 때만 취소하도록 조건 보정. 덤으로 watchdog 경로는 이미 30초를 기다린 뒤인데 기본 재연결 지연 3초가 또 붙던 것도 제거
  • 재발 시 근거로 쓸 진단 로그 수집 기능 신설. 중복 억제가 없으면 부하를 만들고, 억제를 넣으니 이번엔 필요한 로그를 삼키던 문제까지 이어서 수정

🚀 Impact: 새로고침 없이 자동 복구되도록 수정, 재발 시 확인할 진단 경로 확보

📝 연결은 살아있는데 데이터가 안 온다 — 새로고침해야만 복구되던 SSE 고치기

장비 기동 실패 원인 추적 — 3억 2,804만 행 COUNT(*) 87초 제거로 정상 기동

  • 한동안 쓰지 않던 장비가 다시 켜지지 않는 장애. 재실행·재설치로는 재현되지 않음
  • 설정 파일을 하나씩, 다시 항목을 하나씩 바꿔가며 원인을 데이터 보관 설정으로 좁힘
  • 파티셔닝 배포 두 달 뒤, 처음으로 만료 파티션이 생긴 순간 그것도 하필 가장 무거운 이미지 메타 테이블에서 터짐. 정리 작업이 파티션 테이블을 순회하는 구조라 88초짜리 조회가 반복되며 부팅을 끝내지 못한 채 파드가 종료
  • 삭제 대상 선정 후 다음 로그까지 87,371ms(약 88초)간 완전한 침묵. 밖에서 보면 멈춘 것과 구분되지 않음. 범인은 만료 파티션을 DROP하기 전 행 수를 세던 COUNT(*) — rows: 328,040,507. 로그에 건수를 찍으려고 넣은 한 줄이 부팅 경로를 막고 있었고, 동작에 쓰이지 않아 제거
  • 원인을 다 파악하기 전에도 진행 상황을 계속 공유하고, 정식 배포 전까지는 코드 변경 없이 설정 값만 바꿔 우회하도록 현장에 안내. 수정 배포 시점은 내 준비가 아니라 공장 라인이 쉬는 시간에 맞춰 조율
  • 기능 테스트는 통과했는데 운영에서 터진 유형. 개발 환경 파티션엔 몇천 건뿐이라 COUNT(*)가 눈 깜짝할 새 끝났고, 같은 코드가 운영에선 3억 2,804만 행을 읽음. 5자릿수 데이터량 차이는 5자릿수 지연으로 돌아온다는 것 — 이후 리뷰에서 전체 스캔·반복문 내 쿼리는 운영 데이터량을 대입해 읽는 기준을 세움

🚀 Impact: 장비 정상 기동. 개발 환경 데이터 양으로는 드러나지 않는 종류의 문제를 코드 리뷰 확인 항목에 추가

📝 파티션 정리가 부팅을 막았다 — 로그 한 줄을 위한 COUNT(*) 3억 건

현장 PC용 데스크톱 앱 재작성 — 설치 파일 150MB → 10.9MB (93% 감소)

  • 설치 파일 150MB(157,664,256B) — 웹 화면 하나를 띄우기만 하는 앱인데 Chromium을 통째로 번들링. 부속 DLL·pak 파일까지 같은 폴더에 함께 배포됐고, Chromium 취약점이 나올 때마다 앱을 다시 빌드해 재배포해야 하는 — 엔진 수명주기를 앱이 떠안는 구조
  • 그 엔진의 기능을 거의 쓰지 않아, OS에 이미 설치된 웹뷰를 빌려 쓰는 Go/Wails로 재작성 → 10.9MB(11,517,440B) 단일 exe — 93% 감소, 약 1/14. 앱이 하는 일은 전과 동일
  • 확대·새로고침·폴더 열기 버튼, 확대 배율 저장, 연결 상태 표시와 재시도 중단 조건 구현
  • 설치 관리자가 제거·업데이트 도중 공용 웹뷰 프로세스를 종료해 같은 PC의 다른 앱까지 꺼지던 문제 수정
  • 빌드·배포 파이프라인과 설치 파일 생성 자동화 — 버전 태그 push만으로 릴리스 생성. 150MB 폴더를 통째로 옮기며 어느 현장이 어느 버전인지 물어봐야 하던 배포가, 단일 파일이 되면서 내려받아 교체하는 흐름으로 정리됨

🚀 Impact: 설치 파일 150MB → 10.9MB, 단일 파일 배포로 전환. 브라우저 엔진 보안 업데이트는 OS가 처리

📝 웹 화면 하나 띄우는 데 150MB — Electron 래퍼를 Wails로 옮기기

온프레미스 K8s 배포 구성 운영 — OOMKilled 반복 종료 해소 · Helm 차트 수정·운영

  • 제품이 고객사 Kubernetes 환경에 설치되어 나가는 구조라, Helm 차트가 각 사이트의 실제 구성. 기존 Helm/ArgoCD 구성을 인계받아 유지·운영하며 차트 수정을 담당 (클러스터·ArgoCD 자체 구축은 기존 인프라)
  • 테스트에 필요하지만 어디에도 올라가 있지 않던 장비 동작 흉내용 목 서버는 ArgoCD Application을 새로 구성해 개발·운영 환경에 배포
  • OOMKilled로 반복 재시작되던 백엔드 서버에 파드 리소스 limit/request 재조정 적용해 종료 해소
  • 자동 배포 실패 오류 수정, 환경별 실행 명령을 설정값으로 분리, 서버 사양에 맞춘 이미지 빌드

🚀 Impact: 고객사로 나가는 배포 구성을 인계받아 관리, 테스트용 서버를 자동 배포 대상에 신규 편입, 반복되던 백엔드 서버 다운 해소

스토리지 용량 사고 후 미처리 검사 데이터 복구 — 11만 건 중 검사 결과 전 구간 · 이미지 68,990건 복구

  • 검사 이미지를 장기 보관하는 스토리지가 가득 차 신규 저장이 막혔고, 용량을 확보한 뒤에도 밀린 112,835건이 자동으로 복구되지 않음. 업로드 에이전트가 최근 24시간의 미완료 건만 조회하고 검사 데이터 전송은 이미지 상태가 확정되지 않은 건을 걸러내던 구조라, 앞단의 정체가 뒷단의 침묵으로 이어짐. 백엔드와 업로드 에이전트를 담당해 세 팀이 걸친 사고의 중간에서 대응
  • 사이트별로 원본 이미지 폴더 · 스토리지 적재 여부 · 검사 데이터 서버 상태를 대조해 11만 건을 복구 대상 / 원본 소실 확정 / 결과만 선전송 세 갈래로 분류. 고화질 촬상 사이트는 보관 규칙에 걸려 9일치 원본이 이미 지워졌고 저화질 사이트는 18일치가 온전해, 같은 사고인데도 복구 가능 범위가 갈림
  • 복구 방식 3가지를 비교해 기간을 지정하는 신규 조회 경로를 선택 — 조회 기간 제한을 푸는 안은 아직 저장이 끝나지 않은 방금 찍힌 검사를 실패로 확정할 위험이 있었고, 이미지를 포기하는 안은 영구 손실이었기 때문
  • 상시 폴링 API에 분기를 넣지 않고 복구 전용 엔드포인트와 1회성 실행 경로를 분리 — 복구가 끝난 뒤에도 조건이 상시 경로에 남는 것을 막기 위해서. 사후 정리에서는 새 기능이 도는지가 아니라 상시 조회가 이전과 동일한 쿼리를 만드는지를 테스트로 고정

🚀 Impact: 검사 결과는 전 구간 복구, 이미지는 68,990건 복구. 원본이 이미 지워진 40,050건은 복구를 포기하되 '없음 확정'으로 기록해 이후 조사에서 재구성이 가능하도록 남김. 한 번에 밀어 넣지 않고 비가동 구간마다 나눠 실행해 당일 검사에 지연이 쌓이지 않게 함

📝 스토리지가 찬 뒤 남은 11만 건 — 어디까지 복구할 수 있었나

프론트엔드 E2E 테스트 파이프라인 구축 — 테스트 40개 · 고객사 5곳 · 9분 43초

  • 백엔드에는 CI가 있었지만 프론트엔드에는 CI 자체가 없었음. 고객사마다 화면 조합이 달라, 한 곳에 맞춘 변경이 다른 곳을 깨도 배포 전에 알 방법이 없던 상태
  • 목을 쓰지 않고 실제 백엔드에 검사를 주입해 결과표·검사 수량·불량 그래프 같은 전역 집계까지 확인하는 방식을 택함 — 목으로는 중복 집계 같은 실제 버그가 잡히지 않기 때문
  • 모든 테스트가 하나의 백엔드를 공유해 병렬 실행 시 서로의 결과를 오염 — 재봤더니 4회 중 2회 실패, 매번 다른 테스트가 깨짐. 병렬로 버는 시간은 43~49초 → 27~41초, 10초 남짓. 10초를 아끼자고 CI 게이트의 신뢰도를 바꿀 이유가 없어 워커를 1개로 고정 (describe.serial은 파일 내부만 보장해 불충분)
  • 매 실행 앞단에 setup 3단계를 직렬로 배치해 스스로를 복구하도록 구성 — 인증(6.4초) → 이전 실행의 잔여 페이지 정리(146ms) → 백엔드 설정 정합화(115ms)
  • 알람 로그 생성 API가 플래그 기본값 탓에 응답 전 외부 서버 업로드를 대기, CI에서 그 주소가 닿지 않아 네트워크 타임아웃까지 매달리며 훅 타임아웃 60초로 스펙이 통째로 죽던 문제를 규명·수정
  • 테스트 이름이 그대로 명세가 되도록 작성 — "주입한 검사가 결과표에 그대로 반영된다", "주입 건수가 검사 수량 Total/OK/NG에 반영된다" 등 목록만 훑어도 무엇을 보장하는지 읽힘

🚀 Impact: CI 부재(default 자체가 없음) → 푸시마다 E2E 40개 · 고객사 5곳(A 9 / B 6 / C 9 / D 8 / E 5) · 9분 43초가 도는 상태로 전환. 남은 과제는 재시도로 덮인 플레이키 2건과, 직렬 10분이라 아직 머지 게이트로 걸지 못한 점

📝 끝까지 자동인 배포에 검증 한 칸 넣기 — 목을 쓰지 않는 E2E

기존 제품 기능 개발 및 유지보수 — GraphQL→REST 이관 · RBAC 도입 · 멈추던 운영 화면 복구

  • API 아키텍처를 GraphQL에서 REST로 전환 — 서버 처리와 화면 호출 코드를 양쪽 다 이관
  • 사용자 역할에 따라 화면 노출과 조작 권한을 나누는 역할 기반 접근 제어(RBAC) 도입
  • 하루 1.8만 건이 쌓이는 알림 이력 화면이 수만 행을 한 번에 DOM으로 렌더하느라 멈추던 문제를 가상 리스트(@tanstack/react-virtual)로 전환 — 수만 행 → 실제로 보이는 수십 행만 렌더 (내부 화면 녹화 기준 첫 표시 약 5초 → 1초 수준, 정밀 계측 아님). 방법 5가지·라이브러리 3가지를 비교해 번들 크기(4KB)와 기존 테이블 마크업을 유지한 채 적용 가능한지를 기준으로 선택 (컬럼 정렬을 지키려 table-layout: fixed + spacer 행 방식 채택). "느리다"의 원인 절반은 렌더가 아니라 조회 방식이라, 하루 단위 + 시간대 필터로 조회도 함께 재설계
  • 장비 수동 조작 화면의 명령 종류 확장, 설정값 불일치 경고 기능, 작업 이력 조회, 데이터 미저장 오류 수정 등 현장 요청 대응
  • AI 코딩 도구에 코드 리뷰 커맨드를 만들어 리뷰를 PR 이전 단계로 이동. 모든 변경이 배포 전 최소 한 번 점검을 거치게 되면서 console.log 잔존, 이벤트 리스너 cleanup 누락(실시간 화면 메모리 누수), 중복 컴포넌트가 사전에 걸러짐. 삭제·민감 파일 수정을 막는 훅과 도메인 매뉴얼 자동 로딩 커맨드도 함께 구성

🚀 Impact: API 아키텍처 REST 이관 + RBAC 도입, 수만 행 렌더링으로 멈추던 운영 화면을 보이는 수십 행만 렌더하도록 복구, 배포 전 사전 코드 리뷰를 습관화

📝 하루 1.8만 건 알림 로그 테이블, 가상 리스트로 최적화 📝 Claude Code 커맨드로 개발 작업 효율 높이기 — 사전 코드 리뷰부터 컨텍스트 자동화까지

팀 온보딩 및 운영 지식 문서화 — 문서 부재 상태에서 제품 설명 문서 신규 작성 · 후임 1명 온보딩 담당

  • 합류 시점에 담당 제품 2종(운영 대시보드 · 현장 에이전트)의 동작을 설명하는 문서가 존재하지 않아, 필요한 정보를 매번 그룹장에게 물어 파악해야 했음 → 파악한 내용을 제품 전반의 동작 설명 문서로 정리해 신규 작성
  • 현장 장애를 처리할 때마다 증상 · 원인 · 조치 내용을 유형별로 누적 기록해, 동일 유형 재발 시 재분석 없이 조치 이력을 먼저 조회하도록 함
  • 도메인 규칙은 AI 코딩 도구가 작업 중 자동 로딩하는 매뉴얼 커맨드로 레포에 반영 — 문서를 따로 찾지 않아도 참조되도록 구성
  • 온프레미스 특성상 사이트별 배포 시점이 달라, 이미 조치했으나 배포 시점을 확보하지 못한 고객사가 생김 — 어느 사이트에 어느 조치가 반영됐는지 조회 가능해야 한다는 점이 이력을 남긴 이유

🚀 Impact: 합류한 풀스택 개발자 1명의 온보딩을 담당. 미배포 고객사에서 같은 증상이 재발했을 때, 후임이 조치 이력 문서만으로 원인을 특정하고 대응

팀패스 (Team Pass)

Frontend Developer

2025.04 - 2026.01 (10개월)

화장품 제조 뷰티 플랫폼 '브래닛' 프론트엔드 개발
React 기반 화면 전 범위 담당
1~2주 단위 스프린트로 배포하며 공통 컴포넌트 정비와 결제 연동을 수행

React TypeScript React Query Zustand Tailwind CSS Storybook

공통 컴포넌트 정비 및 상태 관리 구조 정리 — 신규 화면 작업 시간 단축

  • 버튼·입력·팝업 등 공통 컴포넌트를 variant/size/disabled/loading 규격으로 표준화하고 Storybook으로 문서화
  • 전면 교체는 1~2주 단위 배포 주기를 멈춰야 해 배제하고, 신규·수정 화면부터 적용해 레거시를 점진 전환 — 디자이너와 규격을 먼저 합의해 화면별 구현 편차를 차단
  • 다단계 요청 플로우에서 서버 응답과 화면 상태가 어긋나 버그 원인을 특정하기 어렵던 문제 — 서버 상태(React Query) / 화면 국소 상태 / 비즈니스 로직(Custom Hook) 세 갈래로 책임을 분리해, 버그가 나면 어느 갈래인지부터 좁히고 들어가도록 구조를 바꿈
  • AI 어시스턴트로 반복 레이아웃 초안을 생성하고 인터랙션·상태 케이스 중심으로 정교화

🚀 Impact: 공통 컴포넌트 재사용으로 신규 화면 작업 시간 단축, 상태 관리 책임 분리로 버그 원인 범위 축소

레이아웃 시프트 최소화 및 전환 UX 안정화 — 로딩 중 오조작 감소

  • Skeleton/Placeholder 영역을 고정하고 높이·간격을 선확보해 렌더링 전후 레이아웃 변동을 최소화
  • 모달·탭·리스트 갱신 등 전환 구간 인터랙션을 재사용 가능한 패턴으로 정리

🚀 Impact: 로딩 중 화면이 밀려 잘못 클릭하는 문제 감소

구독 유료화 결제 연동 — 예외 케이스까지 처리한 결제 플로우 운영

  • 상품·상태 조회 → 결제 팝업 호출 → 결과 처리 → 서버 확인 요청 → 구독 상태 동기화까지 프론트엔드 구간 연결
  • 성공·실패·취소 등 결제 결과별 UX와 구독 상태 기반 접근 제어·노출 정책 정리

🚀 Impact: 결제 중단·실패·재시도 케이스까지 처리한 구독 결제 플로우 운영

케이브먼트 (Cavement)

Frontend Developer

2023.11 - 2025.04 (1년 6개월)

남성 미용의료 플랫폼 '미남이오' 앱/웹과 제모 탐색 서비스 '제모데이' 웹 개발
렌더링 전략 분리와 지도 UX 최적화를 중심으로 성능 개선
CodePush 기반 운영 대응 구조와 결제 연동을 함께 수행

Next.js React Native TypeScript

렌더링 전략 구분 및 캐싱 최적화 — 초기 로딩 시간 단축

  • 페이지 목적(SEO·개인화)과 데이터 변경 주기를 기준으로 정적 화면은 SSG/ISR, 개인화·권한 기반 영역은 SSR로 분리 적용
  • 자주 이동하는 페이지는 미리 불러두고, 이미지가 많은 화면은 화면에 들어올 때 불러오도록 변경
  • 같은 데이터를 여러 번 요청하지 않도록 캐싱하고 다시 불러오는 시점의 규칙을 정리

🚀 Impact: 초기 로딩 시간 단축 및 동일 데이터 중복 호출 감소

지도 탐색 화면 렌더링 최적화 — 깜빡임 제거, 재조회 호출 감소

  • 지도 이동·줌마다 자동 재조회가 발생해 깜빡임과 마커 중복 렌더링이 생기던 문제
  • 이동·줌이 끝난 뒤에만 요청하도록 지연 처리하고, “검색” 버튼을 눌렀을 때만 조회하도록 변경 (기획과 조회 시점 기준을 재합의)
  • 마커를 매번 다시 그리지 않고 바뀐 것만 추가·제거하도록 수정, 지도 렌더링 로직 분리

🚀 Impact: 지도 이동 시 발생하던 깜빡임 제거 및 재조회 호출 감소

펫피플 (Pet People)

Frontend Developer

2022.04 - 2023.03 (1년)

반려동물 플랫폼 '와요/펫플래닛'의 앱 및 내부 어드민 개발

React React Native JavaScript

앱 신규 기능 개발 — 탐색·예약·기록 3개 기능 추가

  • 지도 기반 장소 탐색 — 카테고리·마커 탐색 구성, 마커 선택에서 상세 이동까지 동선 정리
  • 숙소 예약 — 조건별 필터로 탐색 조건을 구성하고 탐색 → 상세 → 예약·문의(결제 포함) 흐름 구현
  • 단계 기반 기록 작성 — 앱 종료·백그라운드 전환에도 흐름이 끊기지 않도록 임시저장을 제공해 입력 유실 방지

🚀 Impact: 장소 탐색·숙소 예약·기록 작성 세 기능을 앱 기능 범위로 확장

휴라(Hura)

응용프로그래머

2020.11 - 2022.04 (1년 6개월)

전파 탐지 장비의 모니터링 프로그램 개발 (WPF/C#)

WPF

전파 탐지 장비 모니터링 화면 개발 — 운영자의 상태 파악 속도 개선

  • 장비에서 계속 전달되는 전파 데이터를 받아 화면에 실시간으로 표시하는 모니터링 UI 구현
  • 운영자가 값을 빠르게 읽을 수 있도록 대시보드·그래프·상태 표시 중심으로 화면 구성 및 사용자 흐름 정리

🚀 Impact: 실시간 모니터링 환경에서 운영자가 상태를 파악하는 속도를 개선

Writing

업무에서 실제로 겪은 문제를 배경 · 검토한 선택지 · 결정 근거 · 결과 순으로 정리해 공개하고 있습니다. · velog.io/@yg1110

운영 데이터베이스

멈추면 안 되는 DB의 구조를 바꾼 작업

  • 디스크가 꽉 차서 멈춘 검사 장비, 삭제를 없애기까지 — 대용량 테이블 파티셔닝 삽질기

    2026.06

    지우는 방식 대신 테이블을 쪼개는 구조를 택한 이유와, 장비를 세우지 않고 바꾼 절차

  • 고객사마다 제각각인 운영 DB를 prisma db push에서 migrate로 옮기기

    2026.06

    고객사마다 상태가 다른 운영 DB에 변경 이력 관리 체계를 도입한 방법

  • 파티션 정리가 부팅을 막았다 — 로그 한 줄을 위한 COUNT(*) 3억 건

    2026.08

    로그에 건수를 찍으려던 쿼리가 3억 건을 세느라 장비 기동을 막던 장애의 추적 과정

  • 스토리지가 찬 뒤 남은 11만 건 — 어디까지 복구할 수 있었나

    2026.09

    용량 사고로 밀린 112,835건을 세 갈래로 분류하고, 상시 경로를 건드리지 않는 복구 전용 경로를 만든 과정

실시간 · 성능

느리거나 멈추던 것들을 고친 작업

  • 연결은 살아있는데 데이터가 안 온다 — 새로고침해야만 복구되던 SSE 고치기

    2026.08

    하나의 연결 끊김 증상 뒤에 있던 서로 무관한 원인 3건을 분리해 수정한 과정

  • 하루 1.8만 건 알림 로그 테이블, 가상 리스트로 최적화

    2026.06

    수만 행을 그리다 멈추는 표를 고치며 방법 5가지·라이브러리 3가지를 비교한 기준

  • 웹 화면 하나 띄우는 데 150MB — Electron 래퍼를 Wails로 옮기기

    2026.08

    데스크톱 앱을 다시 만들며 따진 용량과 통제력의 트레이드오프

일하는 방식

프로젝트 진행 방식과 개발 프로세스

  • 센서 없이 시작한 프로젝트, 다섯 스프린트 동안 한 일

    2026.08

    실제 장비와 기획서 없이 5개 스프린트를 진행하며 팀과 맞춰간 방식

  • Claude Code 커맨드로 개발 작업 효율 높이기 — 사전 코드 리뷰부터 컨텍스트 자동화까지

    2026.06

    AI 코딩 도구에 전용 명령을 만들어 리뷰·PR 작업을 자동화한 구성

  • 물어보던 사람에서, 먼저 제안하는 사람으로 — 풀스택 수습 3개월

    2026.06

    풀스택 수습 3개월 회고

  • 프론트엔드 3년차, 풀스택으로 첫 걸음을 뗀 1.5개월

    2026.06

    풀스택 전향 후 첫 1.5개월 회고

사이드 프로젝트

프로젝트 태그

  • 완료 최소 기능 제품을 완성해 실제 사용 가능한 프로젝트
  • 진행중 개발·기능 추가가 계속 진행 중인 프로젝트

Loopin

완료

2026.07

Source Code

습관·루틴을 매일 체크하고 연속 기록(streak)을 쌓는 PWA. 습관 기록은 기기 로컬에 저장하고, 올린 인증만 공개 피드로 공유. Service Worker와 Web Push로 체크 알림을 발송

React 19 Vite PWA (Workbox) Web Push Supabase Expo / React Native

Bookorry

완료

2026.03

Source Code

초대코드와 닉네임만으로 참여할 수 있는 소규모 독서 모임용 소셜 기록 앱. 독후감 공유와 헬스·식단 등 일상 루틴 인증을 그룹 피드로 함께 확인

Next.js 16 Supabase TypeScript Tailwind CSS

ClipStack

완료

2026.03

Source Code

복사한 텍스트를 자동으로 기록하고 전역 단축키(⌘+Shift+V)로 빠르게 접근할 수 있는 macOS용 클립보드 히스토리 매니저

Electron

Sprintlog

완료

2026.03

Source Code

OKR 관리와 일일 업무기록을 한 곳에서 관리하는 생산성 앱

React 19 Supabase

JobLens

완료

2026.02

Source Code

사람인·잡코리아 채용공고를 수집하고, 스코어링 엔진으로 추천/보류/제외를 판단한 뒤 이메일 알림을 발송하는 개인용 의사결정 지원 시스템

Python FastAPI pytesseract (OCR) Spring Boot PostgreSQL

RMancer

완료

2026.01

Source Code

인바디·1RM·운동목표를 바탕으로 사용자에게 최적화된 운동 루틴을 추천해주는 서비스

Next.js 16 NestJS 11 PostgreSQL Docker Compose

SnipSnip

완료

2024.11

Source Code

북마크를 폴더로 분류하고 드래그 앤 드롭으로 정리할 수 있는 개인 북마크 관리 서비스

Next.js 14 NestJS 10 MySQL Docker

학력 및 수료

  • 한밭대학교
    컴퓨터공학 학사
    2013.03 - 2019.02
  • 삼성 청년 SW 아카데미 (SSAFY)
    SW 개발자 과정 수료
    2019.07 - 2020.06 (2기)

자격증

  • 정보처리기사
    2019.08.16
  • 네트워크관리사 2급
    2019.05.21
© Younggil Jeong. All rights reserved.