Frontend Engineer · Platform & Build Architecture

636→158초
CI 파이프라인 총시간 (4.0배)
195→3건
순환 의존 (−98%)
4→1파드
통합 빌드 아키텍처 (배포 단위)
2→0회/일
통합 빌드 전면 차단 (구조적 제거)
v1.20.3
@module-federation/vite upstream PR 머지·릴리스

깨지면 사람보다 파이프라인이 먼저 알게 만든다.

오태훈. 온프레미스 클라우드 관리 플랫폼(B2B 어드민)에서 여러 팀의 프론트엔드 앱을 하나의 제품으로 묶는 플랫폼 계층을 3년간 담당했습니다. 도구의 오탐과 제 자신의 진단 오류까지 실측으로 검증하고 정정하는 것을 습관으로 삼습니다.

Public Artifacts
Stack

기술 스택

앱 4 · 공통 패키지 3 · 원격 저장소 6을 단일 이미지로 통합하는 환경에서 쓰는 것들.

언어
TypeScriptJavaScript
프레임워크
React 18Vue 3
상태·데이터
TanStack QueryZustandPiniaWebSocketSSE
빌드
ViteWebpackesbuildModule Federationpnpm 모노레포
테스트·품질
VitestStorybook (portable stories)SonarQubedependency-cruiser
CI·인프라
GitLab CIJenkinsDockerKubernetes (on-prem 배포 대상)POSIX ShellSentry (소스맵 업로드 경로)
AI 개발 도구
LLM 게이트웨이 구축·운영Ollama (로컬 모델)Claude CodeCodex
Open Source · Module Federation
v1.20.3upstream 릴리스 반영

빌드는 성공하는데 배포하면 죽는 결함, upstream에서 고쳤다

CI가 원리적으로 못 잡는 조용한 실패 — 이슈 등록부터 릴리스 반영까지 하루.

문제
eager: true shared 사용 시 프로덕션 빌드 산출물이 부팅 시점에 크래시. 빌드는 EXIT 0·경고 0으로 정상 종료 — 배포 후 런타임에만 드러난다.
접근
5개 버전 영향 매트릭스로 결함 도입 버전을 실측 정정(1.16.1 → 1.17.0). 재현 필요조건 3가지를 분리해 파일 6개 최소 재현으로 축소. 원인이 번들러가 아니라 플러그인의 정규식 후처리임을 산출물 수준에서 특정 — 네임스페이스 import가 "함수 호출이 없다"는 이유로 삭제되고 있었다.
결과
첫 수정안이 기존 테스트를 깨뜨리자 판정 기준 자체를 "호출되는가"에서 "참조되는가"로 교체. PR 머지 → v1.20.3 릴리스, upstream 테스트 1,017개 통과. "빌드 성공"과 "산출물이 동작함"은 다른 명제다.
자세히 — 결함의 구조와 규명 과정

결함의 구조 (단순화한 요지)

// 플러그인 후처리: Vite preload 헬퍼를 지우려는 정규식이 모듈 경로를 보지 않고
  // `{ _ as X }` 형태의 import를 전부 매칭한 뒤, X의 "함수 호출"이 없으면 문장째 삭제한다.
  // 네임스페이스 import는 값으로만 참조되므로 여기 걸려 지워졌다.
  if (!hasCall(local, chunk)) dropImportStatement()          // 판정: 호출되는가

  // 수정(v1.20.3): 판정 기준을 "참조되는가"로 교체 — 기존 동작 보존, 결함만 제거
  if (!new RegExp(`\\b${local}\\b`).test(chunk)) dropImportStatement()

과정

  • 사내 빌드에서 증상 발견 — 기존 보고 이슈 0건인 미보고 결함. 사내 코드 주석의 "1.16.1부터"가 실측으로는 1.17.0부터임도 함께 정정
  • 초기 합성 재현이 실패한 원인을 청크 토폴로지 차이로 좁혀, 재현 필요조건 3가지(eager shared · 다중 entry · 앱 소스의 런타임 직접 import)를 분리
  • 빌드 중 정규식 콜백에 로그를 심어 삭제되는 문장을 직접 포착 — 어느 후처리 단계인지까지 특정
  • 메인테이너가 1.5시간 만에 머지한 별도 수정이 호출부만 제거한 것임을 지적하고 근본 수정 PR로 연결
  • 회귀 테스트가 fix 없이는 실패함을 확인하고, 배포 tarball에 수정 판정식이 실제로 들어갔는지까지 검증
Architecture · Vite ↔ Webpack
수십 곳고객사 프로덕션 무장애 가동

이종 번들러 Module Federation — 돌아가던 MFA에 Vite를 붙이고, 운영 데이터로 다시 설계했다

"Vite를 쓰려면 전체를 마이그레이션해야 한다"는 팀 내 전제를 POC 하나로 반박했다.

문제
기존 솔루션은 Webpack + Vue 3이고, 팀은 합류 전인 2023년부터 Webpack 내장 Module Federation으로 Remote를 운영하고 있었다. 신규 Host는 React + Vite로 만들려 했는데 "Vite를 쓰려면 전체를 Vite로 마이그레이션해야 한다"는 전제가 붙어 기술 전환 자체가 막혀 있었다.
접근
그 전제를 검증부터 했다 — @module-federation/vite로 Vite(Host) ↔ Webpack(Remote) 런타임 통신이 성립함을 POC로 먼저 입증하고 Host 측 Vite MF 도입을 주도했다. React Query와 Vue Query가 단일 Query Client를 공유하도록 통합해 두 프레임워크가 같은 API 캐시를 참조한다. 이후 타 팀 소유 Remote의 빌드 설정을 webpack 내장 ModuleFederationPlugin에서 @module-federation/enhanced(MF 2.0)로 전환하고 런타임을 0.21.6 → 2.8.1로 올렸으며, remote 로딩을 remoteEntry.js 직접 참조에서 mf-manifest.json 기반으로 이관했다 — manifest의 publicPath가 루트로 내려오는 환경은 런타임 플러그인으로 방어하고 remoteEntry 경로는 폴백으로 남겼다.
결과
2025년 3월 릴리스 이후 수십 개 고객사 프로덕션에서 장애 없이 가동 중. 전체 재작성 없이 신규는 Vite, 기존은 Webpack을 유지하는 점진적 경로를 확보한 것이 핵심 결과이고, 이 경로로 이후 Remote 2종이 각 팀 손으로 Vite에 이전했다. 개발 서버 HMR이 10초대에서 1초 미만으로 바뀐 것은 그 덕에 따라온 이득이다. 이어 6개월 운영 데이터로 런타임 유연성의 비용(파드 4개 상주·월 2~3건 통합 장애)을 정량화해 통합 빌드 아키텍처 전환을 설계했다 — 자신이 붙인 구조의 비용을 데이터로 측정해 배포 단위를 다시 그리는 것도 같은 사이클의 일부다.
자세히 — 구조도와 운영 중 잡은 결함
Host React 18 · Vite · ESM 번들러 경계 (ESM ↔ webpack) Remote A — Vue 3 · Webpack Remote B — Vue 3 · Webpack Remote C — Vue 3 · Webpack remoteEntry 런타임 로드 shared scope — 단일 TanStack Query Client (React ↔ Vue가 같은 API 캐시 참조)
이종 번들러 구조(2025년 3월 도입 시점) — Host(Vite·ESM)가 경계 너머의 Webpack Remote 3개를 런타임에 로드하고, 상태는 하나의 shared scope로 공유한다. 이후 Remote 2종이 각 팀 손으로 Vite에 이전해 현재 Webpack Remote는 1개다 — 경계를 넘는 통신 구조 자체는 그대로다.

운영 중 잡은 결함

  • shared 버전 오보 — Host가 실제 번들한 것과 다른 버전을 공유 스코프에 광고해, singleton 승자 선정이 왜곡될 수 있던 상태를 빌드 산출물 manifest와 설치 트리 실측 대조로 규명·수정. 재발 방지 가드를 빌드에 내장하고 일부러 깨뜨려 실제로 차단됨을 역방향 검증
  • 로컬은 통과·CI만 실패하는 빌드 — 플러그인의 의존 버전 조회가 패키지 매니저 hoist 승자(설치 형태에 따라 달라지는 비결정 값)로 풀린다는 점을 규명. 컨테이너 없이 hoist 디렉터리만 조작해 CI 실패를 로컬에서 결정적으로 재현하고, 실제 번들되는 사본에서 읽은 버전을 주입해 비결정성 의존 자체를 제거
  • 메모리 누수 — React와 Vue의 생명주기 차이로 발생한 구독 누수를 cleanup 로직 분리(unmount 시 리스너 정리·구독 해제)로 해결
Architecture · Build & Deploy
파드 4 → 1배포 단위 통합

통합 빌드 아키텍처 — 파드 4개를 1개로 합치고, 런타임 통합은 남겼다

마이크로 프론트엔드는 배포 빈도가 높은 조직에서 값을 낸다. 저빈도 온프레미스 모델에서는 아니었다.

문제
런타임 통합만으로 운영한 첫 6개월간 K8s 파드 4개 상주, 공통 컴포넌트 4중 중복, 월 2~3건 런타임 통합 장애가 남았다. 고객사 데이터센터에 직접 설치되는 제품이라 상주 파드 하나가 그대로 설치·운영 비용이다.
판단
운영 모니터링 데이터로 그 비용을 정량화해 판정 기준을 배포 빈도로 세웠다 — 독립 배포를 실제로 자주 하는 조직이라야 런타임 통합이 값을 낸다. 분기 단위로 릴리스하는 온프레미스 모델에서는 통합 빌드가 우수하다는 결론에 도달했고, 사내 표준으로 문서화했다.
조치
모노레포를 도입해 Remote 3종 + Host를 한 번에 빌드하고 산출물 전부를 단일 nginx 이미지에 적재했다. 바뀐 것은 배포 단위뿐이고 모듈 통합은 여전히 런타임 Module Federation이다 — 각 팀의 저장소와 독립 개발 흐름은 그대로 뒀다.
결과
앱별 독립 파드 4 → 단일 이미지·파드 1. 2026년 6~7월에 구현해 고객사 환경에 배포·운영 중이고, 같은 모노레포를 기반으로 솔루션 공통 디자인 시스템을 개발하고 있다. 아키텍처는 조직의 배포 빈도에 종속된다 — 유행이 아니라 그게 판정 기준이다.
스택
pnpm 모노레포Module FederationDockerKubernetesnginx
Deployment · Operations Automation
2회/일 → 0통합 빌드 전면 차단

반복 운영을 구조로 없앴다 — 하루 두 번 멈추던 배포를 0으로

사람이 매번 확인하던 일을 파이프라인과 스크립트로 옮겼다.

문제
한 팀의 dev tip이 깨지면 전 팀 배포가 막혔다 — 통합 빌드 전면 차단이 하루 2회. 타 팀 브랜치 상태를 사람이 확인하고 배포를 조율하고 있었다.
접근
소스 핀으로 결합을 끊었다 — 트리거한 솔루션만 브랜치 최신, 나머지는 마지막 성공 커밋으로 고정. 파이프라인 로직을 검증 가능한 POSIX 셸로 분리해 특성화 테스트 65건으로 고정하고, 커밋 1개로 되돌릴 수 있는 킬 스위치를 함께 설계했다.
자동화
실패 사실만 알리던 CI 리포트를, SonarQube Web API로 깨진 품질 게이트 조건과 신규 이슈를 조회해 MR 댓글에 표로 붙이도록 바꿨다. 초안이던 에러 키워드 매칭이 실제 실패 로그 4종(build·lint·e2e·coverage)에서 새는 것을 확인하고 러너 구간 절단 방식으로 재설계.
결과
통합 빌드 전면 차단 하루 2회 → 0회. 사람이 기억하던 것을 파이프라인이 기억하게 만드는 것까지가 조치다.
스택
JenkinsGitLab CIDockerPOSIX ShellSonarQube APIModule Federation
자세히 — 3일 멈춘 배포와, 사람이 하던 확인을 옮긴 자리

타 팀 변경으로 3일 멈춘 배포

  • 타 팀 서브모듈이 트리거한 빌드만 전부 실패했다 — 마지막 성공 커밋 기준 first-parent 이분탐색으로 원인을 특정: 타 팀이 추가한 postinstall이 매니페스트만 복사하는 Docker base 스테이지에서 자기 스크립트를 못 찾고 죽는다
  • 증상 경로를 막는 대신 빌드 레이어 전제를 바로잡아 당시 서브모듈 4개 전체의 재발을 차단. "스크립트 디렉터리 복사" 대안은 캐시 무효화를 근거로 기각하고 트레이드오프를 남겼다
  • 사고를 재현하지 못하면 스스로 실패하는 회귀 테스트를 함께 남겨, 검증이 조용히 썩지 않게 설계

사람이 하던 확인을 옮긴 자리

  • 서비스 상태 수동 확인 → 헬스체크. 호스트 1대·점검 항목 9개 규모에 맞는 최소 구성(cron + 셸 + 상태 변화 시에만 알림)을 택하고, 정상·실패·접속불가 3경로를 직접 주입해 확인
  • 자기 판정의 철회. 사내 위키에 직접 게시한 "서비스 자동 기동 미등록" 판정 3건이 조사 방법 결함에 의한 오진임을 스스로 발견해 철회하고, 오진 과정 자체를 재사용 가능한 판정 절차로 남겼다
  • subtree 전환으로 끊긴 blame 복구. 근본 원인을 계보 단절로 규명하고 히스토리 재작성 없이 git replace --graft로 복구 — 원격 저장소 5개 재동기화 비용 없이 코드 소유권 추적성 회복
  • ESLint 커스텀 규칙. 팀 컨벤션을 규칙으로 자동화해 형식적 지적을 리뷰에서 제거
Performance · CI Pipeline
4.0배파이프라인 단축

CI 636초 → 158초 — 채택한 조치만큼 철회한 조치가 산출물

잡을 빠르게 만드는 것과 파이프라인을 빠르게 만드는 것은 다른 문제였다.

규명
정적분석 350초 중 269초가 분석이 아니라 파일 트리 순회 — pnpm 심볼릭 링크가 실파일 7.5만 개를 33만 경로로 부풀리고 있었다. CPU를 두 배로 늘려도 총시간이 그대로인 원인을 스케줄링(큐잉 76초 + 스테이지 직렬화 82초)으로 특정해 사장시간 82초 → 3초.
규율
직접 넣은 조치 1건을 실측으로 철회하고, 다른 1건은 산술이 반대임을 확인해 착수 전에 기각. 절감폭 −68%짜리 안은 "이후 모든 테스트가 실행 순서를 의식해야 하는 영구 부채"라는 이유로 의도적 보류. 대조군 표준편차가 목표 효과를 압도하자 "측정 불가"를 계산으로 판정하고 중단. 좋은 수치가 항상 채택 근거는 아니다.
결과
파이프라인 636초 → 158초(4.0배), 정적분석 잡 350초 → 80초(4.4배).
자세히 — 병목별 측정 분해와 철회 기록

병목별 분해

병목원인 (실측)조치효과
정적분석 스캔제외 설정이 분석 대상에서만 빼고 순회 자체는 막지 않음 — pnpm 심볼릭 링크가 실파일 7.5만 개를 33만 경로로 부풀린다스캔 루트를 실제 대상만 열거 (순회 → 약 2.8만 경로)350 → 80초
캐시 아카이빙4개 잡이 동일한 2.5GB 캐시를 각각 push쓰기를 임계 경로 밖 잡으로 한정잡당 −35~39초
테스트 환경전역 jsdom 설정이 파일 단위 환경 선언과 충돌 — DOM 불필요한 167개 파일이 비용 지불기본값 반전 + 누락 독블록 6개 보강 (전수 실행으로 확인)91 → 59초
러너 자원호스트 14코어 중 4개만 VM에 할당VM 8코어로 확장 (공용 머신이라 메모리는 불변)vitest 124 → 58초
스케줄링슬롯 부족 76초 큐잉(queued_duration으로 확인) + 의존 없는 잡의 스테이지 직렬화 82초concurrent 확장 + needs: []사장 82 → 3초

철회·보류 기록

  • pnpm store 이전 — 폐기. 정적분석은 목표대로 빨라졌지만 테스트 잡이 165 → 241초로 악화 — 매 잡 1,256개 패키지 재다운로드가 디스크를 처닝해 테스트 전 구간을 1.7배 늦춤
  • node_modules 캐시 제거 — 착수 전 보류. restore −6초 대비 install +10~20초로 산술이 반대
  • 테스트 격리 해제(−68%) — 의도적 보류. 깨지는 18개 파일의 원인을 모듈 레지스트리 재사용 하나로 수렴시킨 뒤, 비용이 코드가 아니라 이후 모든 테스트가 실행 순서를 의식해야 하는 영구 부채임을 밝힘
  • 워커 풀 threads 전환 — 되돌림. 잡은 빨라졌지만 web-worker가 workerData 존재만으로 자신을 워커로 오판해 로컬은 통과하고 CI만 깨졌다. 원인을 규명한 뒤 격리를 되찾기 위해 forks로 복귀 — 이 파이프라인에서 "로컬 통과·CI 실패"가 나온 두 번째 경로다
  • 후속 안 CI 검증 — 측정 불가 판정. 대조군 표준편차 35초가 목표 효과 15초를 압도, 검정력 80%에 한 쪽당 80회 이상 필요함을 계산하고 중단. 대신 분산 자체(같은 잡이 2.3배 흔들림)가 러너 경합이라는 별개 문제임을 분리 기록
Architecture · Dependency Graph
195 → 3순환 의존

리포트를 받아 적지 않고 원본 데이터를 코드와 대조했다

「잠재결함 928건」이라는 정적분석 리포트에서 먼저 규명한 것은 도구의 측정 범위 결함이었다.

규명
분석 도구가 Vue SFC 251개(Understand 리포트 기준, 화면 계층 전부)를 한 건도 읽지 않았고 alias import를 해석하지 못한다는 측정 범위 결함을 리포트 원본 데이터 파싱으로 규명. 「미사용 함수」 1,320건 중 표본 10파일에서 진짜는 1건, 보안 경고 131건의 실질 취약점은 0건이었다.
조치
실제 조치 대상만 P0~P3로 추려 에픽 1건 + 티켓 14건으로 재구성. 라우터 순환을 끊는 내비게이션 late-binding 서비스를 도입하고, 계층 역전을 해소하고, 경계 ESLint 규칙이 루트 파일로 새던 우회 구멍을 막았다.
결과
벤더와 동일한 산식 기준으로 순환 의존 195건 → 3건, 기술부채비율 3.84% → 3.02%. 남은 3건은 Module Federation으로 타 팀 앱에 노출된 상태 미러 계약이라 의도한 잔여분으로 기록했다. 받은 결론이 아니라 원본 데이터가 판정 근거다.
스택
dependency-cruiserSonarQubeTypeScript ASTESLint
자세히 — 게이트 설계 근거와 벤더 산식 역산

재발 방지 게이트를 known-violations로 고른 이유

  • 숫자 상한은 통과한다. 하나 고치고 하나 새로 만들면 총계가 같아 게이트가 열린다
  • 경로 정규식 예외는 과잉 면제된다. 의도한 순환 하나를 빼주려던 예외가 그 파일이 낀 다른 순환까지 통째로 면제한다. 그래서 순환 경로 자체를 기억하는 known-violations 방식을 골랐다
  • 게이트도 검증 대상이다. 새 순환을 실제로 잡는지 프로브를 심어 확인했다 — 예외로 등록된 파일이 낀 새 순환도 잡힌다. 기존 lint 잡에 한 줄로 붙여 파이프라인 비용 증가를 15초로 묶었다(별도 잡은 install·캐시로 35~40초를 더 낸다)

번들 산출물 실측으로 리팩터를 착수 전에 기각했다

  • host 앱의 barrel(index.ts) 233개 전면 정리 요구에 대해, tsconfig paths를 해석하는 정적 분석 스크립트로 barrel 경유 import 735건을 계량화하고 636건(387파일)을 자동 치환하는 코드모드를 작성해 A/B 빌드를 3회씩 반복 측정
  • 결과는 반대였다 — 번들 크기가 오히려 0.07% 증가하고 청크가 169 → 172개로 파편화. Rollup이 ESM 재수출을 이미 tree-shake하므로 barrel 자체는 번들 비용이 아니고, 제거 시 청크 파편화가 Module Federation 환경에서 오히려 손해다
  • 실제 비용이 중첩 barrel 23개(2홉 이상 import 76건의 원인 전부)에 집중됨을 규명해 정리 범위를 233 → 23개로 축소. 코드모드까지 만들어 놓고 데이터를 근거로 쓰지 않는 것도 결과다

벤더 산식을 역산해 다시 측정했다

  • 외부 벤더의 기술부채 등급 산식을 리포트 데이터만으로 역산해 TypeScript AST 기반 자체 재측정 파이프라인을 구축
  • 벤더 리포트가 Vue SFC 271개(벤더 등급 리포트 기준, 전체 LOC의 21%)를 누락했음을 입증
  • 벤더와 동일한 산식으로 다시 측정한 기준에서 순환참조 195 → 3건, 기술부채비율 3.84% → 3.02%. 자체 측정 파이프라인은 벤더가 못 읽던 alias import까지 해석하므로 모집단이 다르다 — 대외 수치는 벤더 산식으로 통일한다
Test Infrastructure · Storybook
264장8테마 비주얼 회귀 baseline

Storybook을 보여주는 도구에서 막아주는 게이트로

storybook build가 "번들이 만들어지는가"만 보고 스토리 런타임 실패를 통과시키던 구멍을 막았다.

문제
Storybook 두 벌 중 하나는 CI 검증도 배포도 없었고, storybook build는 번들 생성만 확인해 스토리 런타임 실패를 통과시켰다. 조사 중 공통 컴포넌트 패키지 테스트 23개가 CI에서 한 번도 돌지 않고 있었다는 사실도 발견했다 — 전 잡이 host만 --filter하고 있었다.
접근
중복 Storybook 한 벌을 철거하고(1,370줄) 설정만 있고 무동작인 죽은 의존성 3종을 제거했다. 렌더 스모크는 portable stories(composeStories)로 전 스토리를 jsdom에 실제 마운트한다 — 권장 경로 addon-vitest는 CI에 브라우저 인프라를 요구해 배제했다. 비주얼 회귀는 솔루션 4종 × 라이트/다크 8테마에서 컴포넌트 17개 대표 샷 136장으로 시작해 현재 264장까지 늘리고, 리눅스 컨테이너 baseline으로 고정했다.
검증
게이트가 실제로 무는지 역방향으로 확인했다 — 스토리를 고의로 throw 시켜 exit=1, 스킨 CSS 색 294개를 치환해 정확히 해당 조합 17장만 실패하고 나머지는 전부 통과함을 확인. 로컬 macOS에서는 안 드러나는 IPv6 바인딩 버그 (vite preview가 ::1에만 붙어 CI 컨테이너에서 타임아웃)도 사전에 검출했다. baseline 갱신 절차를 문서로 고정해 "스킨을 의도적으로 바꾸면 잡이 상시 빨간불"이 되는 방치 경로를 차단했다.
결과
공통 컴포넌트 패키지 CI 검증 0 → 전량, 비주얼 회귀 264장.
스택
Storybookportable storiesVitestjsdomGitLab CI
자세히 — 배제한 권장 경로, 매니저 브랜딩, 계약 구멍

왜 addon-vitest를 배제했나

  • 권장 경로인 @storybook/addon-vitest는 browser mode와 Playwright를 요구한다 — 게이트 1개를 위해 브라우저 런타임을 CI에 들이는 비용은 이 규모에서 과하다고 판단해 대체 경로를 택했다
  • 같은 목적은 portable stories로 jsdom에서 달성했고, 브라우저 기반 E2E 실행 레이어는 별도 축으로 분리했다 — 판정의 전제가 규모이므로 규모가 달라지면 다시 평가한다

매니저 브랜딩과 사이드바 명명

  • 색을 하드코딩하는 대신 디자인 토큰 JSON을 직접 해석했다 — 매니저는 esbuild 번들이라 Vite alias와 ?inline을 쓸 수 없다
  • 사이드바 명명을 디렉터리 미러로 규칙화했다

별건으로 분리한 계약 구멍

토큰이 주입돼도 antd 기본색이 이기는 스킨 계약 구멍도 별건으로 특정했다.

Test Infrastructure · Compiler Plugin
70~85 인일스스로 반증한 자기 결론

E2E 식별자 자동 부여 — 가장 자신 있던 결론을 스스로 반증했다

이미 발행한 문서를 정정하고 주입 축을 컴파일 타임으로 재설계. 남길 만한 것은 결과가 아니라 검증 과정이다.

반증
"호스트 1회 배선으로 타 팀 공수 70~85 인일 소거"라는 자기 결론을 적대적 검증으로 기각 — 런타임 정보로는 데이터 건수·권한·정렬에 흔들리지 않는 식별자를 만들 수 없다 (실측: 라우트당 동종 컴포넌트 26개 이상).
설계
Vue 컴파일러 nodeTransform으로 빌드 타임 주입. 템플릿 AST에서 업무 의미를 추출하는 9단계 폴백 + 위치 기반 스냅샷 병합으로 문구 수정이 테스트를 깨뜨리지 않게. 해결 안 되는 구간은 "해결했다" 대신 미보증 등급으로 정직하게 표기.
상태
Host 앱 범위로 설계·구현해 MR을 머지했으나 되돌렸고, 현재 운영에는 반영돼 있지 않다. 검증 빌드 측정치는 보증 등급 요소 자동 라벨 도달률 83.2%·식별자 충돌 0건이지만 프로덕션 성과로 주장하지 않는다. 남은 것은 과정이다 — 플러그인 테스트가 프로덕션과 다른 컴파일 옵션으로 돌던 사각지대를 발견하고 빌드 산출물 스냅샷 대조 검증을 추가해 숨은 결함 3건을 잡았다.
자세히 — 반증의 근거와 설계 장치

반증의 근거

  • 런타임 자동 ID의 소스 후보를 실측으로 차례로 기각 — 라벨 조합은 다국어·시트 동기화로 불안정, 대안으로 직접 제안한 i18n 키 파생도 키의 97.7%가 한국어 원문 문장이라 문구 수정 시 키가 바뀌어 안정성이 동일함을 확인하고 자기 추천을 정정
  • 중복 수가 데이터 건수·권한·정렬에 따라 실행 중 변동 — 원격 솔루션 라우트당 동종 컴포넌트 26개 이상 실측
  • 이미 발행한 문서를 즉시 정정 발행 — 결론이 틀렸으면 정정 기록을 남기는 것까지가 검증
템플릿 AST 노드 FALLBACK CHAIN 1 i18n 라벨 2 aria-label 3 v-model 경로 4 이벤트 핸들러명 5 아이콘명 먼저 맞는 것 채택 보증 등급 식별자 검증 빌드 측정치 전부 실패 (반복 렌더 구간) 미보증 등급으로 표기 수기 보완 큐로 이관
라벨 폴백 체인 — 9단계 중 본문에 기재한 5단계. 하나라도 업무 의미를 추출하면 보증 등급 식별자를 부여하고, 전부 실패하는 구간은 해결한 척하지 않고 미보증 등급으로 남겨 수기 보완 큐에 넘긴다.

설계 장치

  • 9단계 라벨 폴백 — 템플릿 AST에서 i18n 라벨 → aria-label → v-model 경로 → 이벤트 핸들러명 → 아이콘명 순으로 업무 의미를 추출, i18n 사전을 한→영 슬러그 변환에 재활용해 사전 구축 비용 0
  • 위치 기반 스냅샷 병합 — 슬롯(위치)을 키로 잡고 기존 ID를 유지해, 문구 수정이 E2E 로케이터를 조용히 깨뜨리는 경로를 구조적으로 차단
  • 1 노드 → N 인스턴스 대응 — v-for는 :key 접미로 런타임 고유화, 다중 인스턴스 컴포넌트는 호출처가 접두를 내려주는 testid prop 계약을 설계(검증 빌드 기준 자식 30종·호출처 101곳)
  • 미보증 2등급 체계 — 해결 안 되는 반복 렌더 구간은 "해결했다" 대신 미보증 등급으로 표기해 수기 보완 큐로 이관

검증

  • 플러그인 단위 테스트가 프로덕션과 다른 컴파일 옵션(prefixIdentifiers off)으로 돌고 있음을 발견 — 전체 3,500여 건 그린 상태에서 실제 빌드에는 주입되지 않던 케이스를 빌드 산출물 덤프·스냅샷 대조로 적발·수정
  • 검증 빌드에서 보증 등급 요소 자동 라벨 도달률 83.2%(완료 기준 80%) · ID 211개 충돌 0. 다만 이 MR은 되돌려졌고 소비처가 없어, 대체된 수기 작업 수는 주장하지 않는다
Selected Work

그 밖의 작업

  • 접근 제어(RBAC) 개편 — 설계 선행으로 무음 데이터 손실 차단. 플랫폼 작업과 병행해 제품 화면도 직접 만든다 — 실시간 모니터링(WebSocket)·서버 이벤트 스트리밍(SSE)·eCharts 대시보드. 권한 관리 화면군 개편에서는 코드 작성 전 기존 구현 전량 분석과 기획 대조로 요구사항의 논리 모순 4건을 해소하고, 저장 시 권한이 조용히 소실되는 경로 3종을 pass-through 설계로 차단. 프론트 설계 변경으로 백엔드 협의 항목 6건 → 3건
  • 통과하는 테스트 뒤에 숨은 결함 규명. 한 번도 동작한 적 없던 30초 타임아웃 안전망(setTimeout 콜백의 throw가 try/catch에 도달하지 못하는데 fake timer 특성으로 테스트는 통과), 로그아웃 무한 리로드 루프(HTTP-only 쿠키 + 세션 재검증 상태 불일치), 프로덕션 console·소스맵 유출(minifier 불일치로 이중 무력화된 설정. Sentry 업로드 경로에서 .map 삭제 후에도 sourceMappingURL 주석이 남아 소스맵 존재 힌트를 노출하던 것은 hidden으로 전환) — 수정 전 소스로 되돌려 신규 테스트가 전부 실패함을 확인하는 역방향 검증을 습관화
  • 사내 AI 개발 인프라 구축. 팀 공용 서버에 AI 게이트웨이 + 로컬 LLM 라우팅 환경을 구축. 계획서의 가용 메모리 전제(실측 237MB)는 실행 전 감사로, 관리자 기본 비밀번호 사내망 노출은 실제 로그인으로 실증해 자격증명을 연결하기 전에 차단
  • Vite 8(Rolldown/Oxc)·Vitest 4 마이그레이션. 마이그레이션 중 최상위 esbuild 옵션이 무시되고 Rolldown의 dropConsole이 console.error·warn까지 제거한다는 것을 확인해, 제거 대상을 선별하는 플러그인을 직접 작성. 앞서 이중으로 무력화돼 있던 프로덕션 console 제거 정책을 새 번들러에서도 유지했다
  • Strangler 마이그레이션 완주. 테이블 렌더 계층을 공통 라이브러리로 이관하는 작업을 소비처 21곳 규모로 완료하고, feature flag와 레거시 렌더 경로까지 제거해 단일 경로로 확정(순감 1,271줄). 컴포넌트 계층을 걷어낼 때 Vue attribute fallthrough 대상이 이동하는 2차 파급을 사전에 짚어 특성화 테스트로 고정 — 마이그레이션은 새 경로를 켠 시점이 아니라 옛 경로를 지운 시점에 끝난다
  • i18n 동기화 무음 삭제 규명. 다국어 파이프라인이 수동 편집분을 경고 없이 삭제하는 구조적 결함을 규명 — 초기 관측치의 74%가 diff 오탐(줄 이동)임을 시트 덤프·로직 재현으로 걸러내 실제 영향을 5건으로 특정, 과거 동일 원인의 키 266개 소실 이력까지 추적
Experience

경력 · 교육

경력
오케스트로 · Frontend Engineer 2023.09 ~ 현재 온프레미스 클라우드 관리 플랫폼(B2B 어드민) — 프론트엔드 플랫폼·빌드 아키텍처 [금융 도메인] KB IQ+ 레거시 시스템 개선(2023.10 ~ 2023.12) — KB 통합관리포털, ActiveX 제거·표준 웹 전환, JSP + Vue.js
자이트론 · 자율주행 SW 개발팀 인턴 2020.09 ~ 2020.12 모형차 기반 자율주행 SW 개발 — YOLO 기반 사람 트래킹, 자율주행 대회 베이스코드 제작 (Python · ROS · AutoWare)
교육
삼성 청년 SW 아카데미(SSAFY) 8기 2022.07 ~ 2023.06 1년 과정 수료 — 기본 6개월 + 심화 6개월, 팀 프로젝트 4건
강남대학교 IoT전자공학과 2014.03 ~ 2021.02 고용노동부장관상 수상(AI 스마트 양식 시스템 '만선') · 한국정보처리학회 논문 게재
자격
SQLD SQL 개발자 · 2022.12