오영근 — 프론트엔드 개발자 이력서
안녕하세요. 프론트엔드에 깊고, 제품 전체를 다루는 개발자 오영근입니다.
사용자의 불편을 빠르게 포착하고, 팀과 맥락을 공유하며, 유지보수 가능한 코드로 개선하는 과정을 가장 중요하게 생각합니다.
- Email: dureng5@gmail.com
- Website: younggeun0.dev
- GitHub: github.com/younggeun0 (새 창에서 열림)
일하는 방식
서비스를 직접 써보며 불편을 찾는 편입니다. 미묘한 레이아웃 틀어짐, 폰트 크기 불일치처럼 놓치기 쉬운 UI 불일치를 발견하고 고치는 일을 중요하게 생각합니다. 구현 전에는 근거를 먼저 맞추고, 필요한 경우 테스트로 리스크를 줄입니다. 코드리뷰와 페어 프로그래밍을 선호하며, 작성한 코드에 대한 다양한 피드백을 적극적으로 수용합니다.
메디쿼터스 (새 창에서 열림) (2022.11 ~ 현재)
메디쿼터스에서 프론트엔드 개발자로 일하며 MAU 100만 일본 커머스 플랫폼 nugu를 개발하고 있습니다. nugu 몰과 백오피스를 함께 다루며 대규모 프론트엔드 전환, 렌더링 성능과 배포 안정성, 프로모션 운영 도구를 개선해 왔습니다. 초기에는 Python(Django REST Framework) 백엔드 개발에도 참여했고, 백오피스에서는 Svelte 기반 개발을 병행했습니다.
Next.js 16 App Router 전면 전환 (2026)
Pages Router 구조에서는 React Server Components(RSC)와 Partial Prerendering(PPR)을 쓸 수 없었고, 상품 상세를 정적 생성으로 돌린 뒤 서버 디스크가 차오르는 문제까지 겹쳐 렌더링 구조 자체를 바꿀 필요가 있었습니다. 팀에서 검토 항목으로만 두고 있던 전환을 PoC로 먼저 시작해, 두 라우터의 렌더링 모델 차이를 문서로 공유하고 두 라우터를 병존시켜 점진 이관하는 방향을 검증한 뒤 팀 검토를 거쳐 본 작업에 착수했습니다. Next.js 16 업그레이드는 별도 PR로 먼저 분리해 핵심 흐름의 e2e 테스트를 통과시킨 뒤 반영했습니다.
이후 인프라, 공용 컴포넌트, 페이지, 서버·클라이언트 경계 재정비 순으로 단계를 나눠 107개 페이지를 이관했습니다. i18next는 클라이언트 전용이라 번역을 쓰는 컴포넌트가 모두 클라이언트로 묶여 있었는데, next-intl로 교체하면서 기존 API와 같은 형태의 호환 계층을 두어 호출부는 import 한 줄만 바꾸도록 했습니다. 서버에서 렌더링하는 영역과 클라이언트 상호작용 영역을 구분하는 패턴을 팀 규칙으로 정리하고, React Compiler 도입에 맞춰 수동 메모이제이션도 걷어냈습니다. 전환 브랜치는 QA 서버에 먼저 배포해 팀원들과 결제 퍼널 중심으로 검증했고, 전환 작업 중 다른 팀원들이 기존 코드에 반영한 변경도 빠짐없이 옮겨 합쳤습니다.
전환 전후를 같은 조건에서 비교하는 성능 측정 도구를 만들어 결과를 측정했습니다. 클라이언트 JS 번들은 절반 이하(gzip 기준 54% 감소)로 줄고 홈의 레이아웃 흔들림(CLS)은 0이 됐습니다. 반면 RSC 스트리밍 응답이 추가돼 총 전송량이 늘고, 상품 상세의 주요 콘텐츠 표시 시간(LCP)이 뒤로 밀리는 트레이드오프도 확인됐습니다. 이를 수치와 함께 팀에 공유했고, 상품 상세 LCP는 아래 렌더링 성능 작업의 스트리밍 분리와 이미지 정책 조정으로 개선했습니다.
렌더링 성능과 배포 안정성 개선 (2025~2026)
상품 목록에는 상태 재설계와 윈도우 가상화를 적용해 최초 렌더링 요소를 최대 95%(1,403개 → 64개) 줄이고 CLS 0을 달성했습니다. 서버 메모리가 계속 증가하던 문제는 힙 스냅샷에서 참조 경로를 추적해, SSR 중 생성된 TanStack Query의 긴 gcTime 타이머가 요청별 QueryClient를 붙잡는 것이 원인임을 확인했습니다. 서버에서는 캐시 수명을 즉시 정리하도록 조정해 메모리 추이를 안정화했습니다. 이 과정은 원인 모를 메모리 누수, 추측 대신 측정부터 했다에 정리했습니다.
App Router 전환 후에는 홈과 주요 페이지를 섹션 단위 Suspense 스트리밍 구조로 바꾸고, 여러 서버가 캐시를 공유하도록 Redis 외부 캐시를 연결해 서버별 캐시 미스를 줄였습니다. 이미지 품질과 로딩 정책은 결과물을 직접 비교해 조정했고, 초기 이미지 전송량을 주요 라우트에서 57~95%, LCP를 16~29% 개선했습니다. 관련 과정은 3년간 아무도 건드리지 않던 이미지 q=100을 다시 측정했다에 정리했습니다.
이 과정에서 프로덕션 빌드에서만 나타나는 정적 셸 붕괴와 하이드레이션 오류를 프로덕션 빌드를 로컬에 띄워 추적했고, Next.js의 Suspense 경계 충돌 버그와 서버·클라이언트 첫 렌더 불일치가 원인임을 밝혀 각각 여분의 경계 제거와 마운트 후 렌더로 해결했습니다. 재발을 막기 위해 규칙을 문서와 위반 시 실패하는 테스트로 남겼습니다.
배포 중에는 이전 버전의 정적 자산 요청이 새 서버로 향해 404가 발생했습니다. 버전별 정적 자산을 CDN에 함께 유지해 404를 없앴고, 빌드 시 외부 API 의존을 끊어 API 장애가 빌드 실패로 이어지지 않게 한 뒤 배포 직후 주요 경로를 워밍업하는 단계를 추가했습니다.
프로모션 Content CMS 플랫폼 구축 (2026)
마케팅/운영팀이 프로모션 페이지를 만들 때마다 개발자에게 의존했고, 개발팀이 차세대 시스템 개발에 집중해야 하는 시점에는 프로모션마다 개발자 한 명이 일주일씩 붙는 방식을 유지할 수 없었습니다. 운영팀이 직접 만들 수 있는 도구가 필요해, 전년도에 만든 기획전 JSON 모듈 시스템과 메인 화면 교체 구조(아래 '코드 배포 없이 운영하는 전시 시스템')를 발전시켜, 이미지·HTML 같은 정적 블록과 동적 위젯을 조합할 수 있는 블록 기반 에디터를 만들고 실서비스 컴포넌트와 CSS를 재사용하는 WYSIWYG 프리뷰를 구축했습니다.
기획전 본문은 텍스트 필드 하나에 HTML로 저장되는 구조였고 스키마를 바꾸기 어려웠습니다. 그래서 블록 편집기의 데이터(블록 트리)를 JSON으로 직렬화해 같은 HTML 본문 안에 주석으로 함께 저장했습니다. nugu 몰은 주석이 있으면 블록으로 렌더링하고 없으면 기존 HTML을 그대로 보여주므로, 기존 HTML 기획전과 블록 기반 기획전이 데이터 마이그레이션 없이 공존할 수 있었고, Zod 스키마 검증과 URL 정제로 저장 데이터의 안정성도 보완했습니다. 이 설계는 마이그레이션 없이 기존 HTML에 블록 CMS를 추가한 방법에 정리했습니다.
이후 카운트다운, 쿠폰, 래플 등 20여 종의 임베드 컴포넌트로 범위를 넓혔습니다. 운영자가 캠페인을 직접 조립할 수 있게 된 뒤에는 클라이언트에서 렌더링하던 CMS 본문을 서버에서 React 트리로 합성하도록 전환했습니다. 콘텐츠와 주요 섹션이 첫 HTML에 포함되면서 프로모션 페이지도 App Router의 스트리밍 구조를 활용할 수 있게 됐습니다. 개발팀에 접수되는 프로모션 개발 요청은 도입 전 6개월 20건에서 도입 후 5개월 6건으로 줄었고, 남은 요청도 페이지 제작이 아니라 편집기가 아직 지원하지 않는 기능을 추가하는 건이었습니다.
BFF·MSA 전환에 맞춘 프론트엔드 API 경로 이관 (2026)
백엔드 팀이 Django 모놀리스를 도메인별 서비스와 BFF(프론트 전용 중간 서버)로 분리하는 동안, 제 역할은 nugu 몰의 API 호출 경로를 새 BFF로 안전하게 옮기는 것이었습니다. 검색, 주문·장바구니·문의, 쿠폰 순으로 도메인을 나누고, 쿠폰처럼 범위가 넓은 도메인은 위험이 낮은 조회 화면부터 쓰기가 있는 화면까지 작은 PR로 쪼개 순서대로 교체했습니다. 금액 필드의 타입이나 에러 코드 체계처럼 두 백엔드가 다른 부분은 응답 변환과 에러 통일 계층에서 흡수해 화면 코드에 번지지 않게 했습니다.
검증은 BFF 응답을 MSW로 모킹한 단위 테스트와 결제 흐름 e2e, 아래 로컬 풀스택 환경의 머지 전 e2e로 했습니다. 프론트 타입은 Django 서버를 띄워 백엔드 명령으로 생성하고 있어 nugu 몰 빌드가 백엔드 코드에 묶여 있었는데, OpenAPI 스펙에서 직접 타입을 동기화하도록 파이프라인을 분리하고 타입 갱신이 누락된 PR을 막는 CI 검사를 추가해 nugu 몰을 백엔드와 독립적으로 빌드·배포할 수 있게 했습니다.
백오피스 어드민 재구축 (2025~2026)
레거시 Svelte 어드민을 대체할 신규 어드민 모노레포(백오피스·파트너오피스)를 React 19, TanStack Router/Query, Vite 기반으로 처음부터 설계했습니다. 공통 UI 패키지와 OpenAPI 타입 자동 생성 파이프라인을 갖춰 화면 추가 비용을 낮췄고, 고객 상담 관리, 카페24 외부상품 수집·승인, 캠페인 이벤트 관리 등 운영 기능을 새로 구축했습니다.
주문 상세 화면의 API를 BFF로 옮길 때는 전환 전후 코드가 같은 테스트를 통과하도록 두 경로를 모두 모킹한 회귀 테스트를 두어 동작이 같은지 검증했고, 서버 에러 코드를 다국어 사용자 메시지 체계로 정규화했습니다.
로컬 개발환경과 머지 전 e2e 구축 (2026)
모놀리스 시절에는 로컬에서 Django 서버 하나만 띄우면 전체 흐름을 재현할 수 있었지만, 서비스 분리 후 결제·주문 흐름이 BFF와 여러 하위 서비스를 거치면서 로컬 재현이 어려워졌습니다. 팀은 단일 QA 서버를 공유해 검증했는데, 여러 기능이 동시에 개발되면 배포 순서를 조율해야 했고 테스트 데이터가 서로 오염됐습니다.
Django와 BFF, 하위 서비스, Kafka, OpenSearch 중 필요한 것만 골라 한 명령으로 띄우는 로컬 환경을 만들어 팀 개발 환경으로 안내하고, 그 위에 DB를 초기화하고 핵심 e2e를 돌리는 머지 전 검사를 붙여 모든 PR의 필수 검사로 정했습니다. 백엔드 유닛 테스트 CI는 단계별 소요 시간을 계측한 뒤 마이그레이션이 끝난 테스트 DB를 캐시해 3분 가까이 걸리던 셋업을 수 초로 줄였고, 프론트 전용 변경은 백엔드 테스트를 건너뛰게 했습니다.
Bootstrap에서 Tailwind CSS v4로 전환 (2026)
SCSS, styled-jsx, Bootstrap이 섞인 스타일 구조를 Tailwind CSS v4로 전면 이관했습니다. 유틸리티 클래스 변환 도구와 시각적 회귀 검증 루프를 만들어, 검증 루프가 잡아낸 100건 이상의 UI 차이를 추적해 정리했습니다.
CSS 번들은 413KB에서 157KB로 약 62% 감소했고, react-bootstrap 제거로 First Load JS(shared)도 916KB에서 850KB로 7% 줄었습니다. 이 과정에서 AI 에이전트와 검증 루프를 활용해 작업 방식이 바뀐 경험은 점진적으로 준비하던 Tailwind CSS 마이그레이션의 80%가 사흘 만에 끝났다에 정리했습니다.
Claude Code 팀 환경 구축과 에이전트 검증 체계 (2026)
몰과 어드민 두 레포에 Claude Code 프로젝트 설정을 처음 도입하고 팀 공유 자산으로 키웠습니다. 프로젝트 안내 문서와 코딩 컨벤션·e2e 테스트 레이어·PR 작성 규칙, 역할별 커스텀 에이전트를 만들고, 파일 편집 시 포매터와 타입 체크가 자동 실행되는 훅과 브라우저 디버깅용 MCP 서버를 연결했습니다. 설정 파일을 심링크로 미러링해 Claude Code와 다른 코딩 에이전트가 같은 규칙과 스킬을 공유하게 했고, 이 구조 위에 팀원들이 작업 파이프라인·배포·외부 베스트 프랙티스 스킬을 추가해 갔습니다.
반복 작업은 스킬(재사용 가능한 작업 절차)로 만들었습니다. Tailwind 자동 변환과 후속 수정, 핵심 e2e 실행, 피그마 디자인을 읽어 기획전 CMS HTML 초안을 만드는 스킬, PR 리뷰 봇 코멘트를 수용·이의·보류로 분류해 답글과 수정까지 처리하는 스킬 등입니다. e2e 스킬은 팀원들이 워크트리 환경에 맞게 직접 고쳐 썼고, CMS 초안 스킬은 초안 작성까지만 맡기고 검수와 수정은 사람이 하도록 역할을 한정했습니다.
에이전트가 만든 대량 변경은 사람이 전부 눈으로 확인할 수 없어 검증 수단을 함께 만들었습니다. 위 Tailwind 전환의 시각적 회귀 도구와 App Router 전환의 성능 비교 도구·e2e가 그 예이고, PR 규칙에 머지 전 e2e 게이트와 백엔드 API 변경 시 타입 재생성 체크를 넣어 에이전트가 만든 PR도 같은 검증을 거치게 했습니다. 반복 실행은 스킬에 맡기고, 결과가 맞는지는 검증 루프와 사람이 판단하는 구분을 유지했습니다.
코드 배포 없이 운영하는 전시 시스템 (2025)
어드민에서 옵션 필드를 조합해 만들던 기획전 UI는 동작하지 않는 조합이 숨어 있었고, 새 옵션이 생길 때마다 DB 마이그레이션이 필요했습니다. 사용례를 분석해 모듈 타입을 정의하고 레이아웃 설정을 JSON 필드로 일원화해, 운영자에게는 모듈별로 유효한 옵션만 보이도록 재설계했습니다.
이어서 메인 화면 자체를 설정으로 교체하는 구조를 만들었습니다. 프로모션 기간에 맞춰 메인 페이지와 탭이 자동 전환되고, 더현대 백화점관처럼 별도 테마의 브랜드관도 배포 없이 열 수 있게 됐습니다. 이 구조가 이듬해 Content CMS 플랫폼으로 발전했습니다.
주문서 개선과 e2e 회귀 테스트 (2025)
상태가 얽혀 있던 주문서를 react-hook-form과 컨텍스트로 재구조화하고, 클라이언트 유효성 검사를 서버 규칙과 일치시켰습니다. 쿠폰·포인트·배송지 조합을 검증하는 Playwright e2e를 구축해 결제 흐름의 회귀를 막았습니다.
상품에 적용 가능한 쿠폰 중 할인이 가장 큰 것을 골라 보여주는 최대할인 쿠폰 기능은 QA에서 만료 쿠폰이나 발급 대상이 아닌 고객에게 쿠폰이 노출되는 이슈가 여러 건 올라왔습니다. 개별 이슈를 따로 고치는 대신 상품 API 응답의 쿠폰 정보가 캐시돼 고객별 조건을 반영하지 않는 구조가 공통 원인임을 찾아 백엔드 팀에 공유하고, 프론트 필터로 막을 증상과 발급 로직을 고칠 증상을 나눠 대응해 안정화했습니다.
이전 주요 성과 (2023~2025)
스타일링 서비스 TF에서 프론트엔드 리드를 맡아 주니어 개발자와 페어 프로그래밍·코드리뷰를 진행했습니다. 동영상 스트리밍과 가상화 기반 피드를 구축했고, 출시 4개월 후 약 40명의 인플루언서가 4,000개 이상의 콘텐츠를 등록해 평균 10%의 장바구니 전환율을 기록했습니다.
매달 이어지는 프로모션 이벤트의 반복 UI와 API를 공통 모듈로 추상화해 개발 속도를 높였습니다. 이외에도 Next.js 12→14 업그레이드, Storybook 기반 공용 컴포넌트 통합, jest→vitest 전환, 카페24 몰·어드민의 자사 플랫폼 이관을 수행했습니다.
에버온 (새 창에서 열림) (2022.03 ~ 2022.10)
에버온에서 프론트엔드 개발자로 근무하며 차세대 백오피스 기능 구축을 담당했습니다. React Admin과 MUI를 중심으로 프론트엔드를 개발했고, 필요 시 Node(Express), Java(Spring Boot) 영역과도 협업하며 제품 전체 흐름을 이해하는 경험을 쌓았습니다. Keycloak을 이용한 RBAC SSO를 구현하고, Dooray! 그룹웨어 연동과 nivo 그래프 모듈을 이용한 통계 대시보드를 구축했습니다. 게시판으로 관리되던 고객 문의를 칸반보드 UI로 이관해 관리 환경을 개선했고, SVN으로 관리하던 소스코드를 Gitlab으로 이관해 소스코드 관리 환경도 개선했습니다.
포시에스 (새 창에서 열림) (2019.06 ~ 2022.02)
포시에스에서 소프트웨어 엔지니어로 근무하며 OZReport HTML5 뷰어 솔루션 개발을 담당했습니다. IE8부터의 브라우저 호환성과 스크린리더 접근성을 지원했고, 동일 로직을 쓰는 C++, C#, Applet, ActionScript 제품 간 기능 포팅을 경험했습니다. 인증 바코드·인감/카드 스캔(opencv-js, zxing) 등 외부 솔루션 연동과 뷰어 동기화 중계 서버 모듈도 개발했습니다.
기타 경험
동국대학교 멀티미디어공학과에서 CS 기초를 다지고, 쌍용교육센터 Python/Java 실무 과정 수료와 미래융합정보기술 QA 인턴을 거치며 개발·품질 양쪽의 기본기를 쌓았습니다. 영국 워킹홀리데이 경험을 통해 낯선 환경에서 스스로 문제를 해결하고 적응하는 역량을 키웠습니다.
소프트 스킬
저는 함께 성장하는 팀 문화를 지향합니다. 요구사항은 언제든 바뀔 수 있다는 점을 염두에 두고 먼저 질문하며, 상황을 빠르게 공유하고, 혼자 해결하기 어려운 문제는 적절한 타이밍에 도움을 요청합니다. 팀 안에서 업무 경계를 과도하게 나누기보다 제품 관점에서 필요한 일을 함께 해결하는 태도를 중요하게 생각합니다.
토이 프로젝트
📏 옷자 otja(2026) (새 창에서 열림)에서는 중고거래 때마다 옷 치수를 재서 적는 일이 번거로워, A4 용지나 카드처럼 크기를 아는 물체와 함께 찍으면 사진에서 실측 치수를 계산해 주는 앱을 만들어 App Store와 Google Play에 출시했습니다.
🥣 지옥밥 HellBowl(2026) (새 창에서 열림)에서는 "음식 남기면 지옥 가서 다 먹어야 한다"는 미신을 소재로, 남긴 음식 사진을 한 그릇에 비벼 보여주는 웹앱을 만들었습니다.
🎸 비인기곡외판원노동조합 밴드 사이트(2026) (새 창에서 열림)에서는 취미 밴드의 공식 사이트를 만들어 밴드 소개와 공연 정보를 웹에서 확인할 수 있도록 했습니다.
🌐 wcag-handbook(2026) (새 창에서 열림)에서는 WCAG 2.2와 KWCAG 매핑 정보를 함께 정리해 접근성을 학습할 수 있는 페이지를 만들었습니다.
🔔 모바일 청첩장(2025) (새 창에서 열림)에서는 모바일 결혼 청첩장을 직접 만들어서 공유했습니다.
👕 메디쿼터스 자사몰 상품 모아보는 페이지(2025) (새 창에서 열림)에서는 Google OAuth 인증, 검색, 찜하기, 브랜드 탐색 기능을 제공해 임직원이 할인 상품을 빠르게 찾을 수 있도록 구현했습니다.
🍅 domado(2024) (새 창에서 열림)는 개인적으로 뽀모도로를 사용하기 위해 만든 macOS 위젯 앱으로, Electron으로 시작해 Tauri로 리팩터링하며 설치 파일(dmg)을 약 134MB에서 9MB로 줄였습니다.
🧗 Pick Your Holds(2022) (새 창에서 열림)에서는 사진 촬영 후 클라이밍 문제를 만들어 이미지를 공유할 수 있는 웹앱을 만들었으며, 초기 vanilla JS(jQuery)로 만들고 React로 마이그레이션했습니다.
🇰🇷 react-simple-south-korea-map-chart(2022) (새 창에서 열림)는 지역 통계 시각화를 쉽게 적용할 수 있도록 만든 React 컴포넌트로 npm에 배포했습니다.