GWLEE.KR — 2026
me@gwlee.kr

포트폴리오.

일곱 개의 장으로 무엇을 왜 그렇게 만들었는지, 판단과 결과를 실제 화면과 함께 정리했습니다.

$ gwlee portfolio --open  →  ✓ ready
scroll
00
[00] map

전체 지도:일곱 개의 장, 2021 – 2026

(주)그리드원 프론트엔드 — 노선도와 장별 안내

사내 첫 독립 프론트엔드부터 오픈소스 기여까지, 5년의 작업을 일곱 개의 장으로 묶었습니다. 각 주제는 서로 이어진 하나의 흐름입니다.

노선도 — 주제별 작업 기간 2021–2026 노선도형 기간 띠
01
[01] streaming-chat

스트리밍 챗 UI:자체 구현에서 라이브러리 내부 확장까지

2023 – 2026
국회 파일럿 → K-water GPT · 한국지역난방공사 납품 → GO-RAG

스트리밍 챗 화면은 응답이 이어지는 내내 갱신을 반복합니다. 도착 중인 마크다운도 읽을 수 있게 렌더해야 하고, 생성은 언제든 멈출 수 있어야 합니다. 2023년의 수동 SSE 파싱에서 어댑터 구조를 거쳐 라이브러리 내부 확장까지, 3년의 판단을 담았습니다.

01-A수동 SSE 파싱에서 BFF 어댑터로

표준 EventSource는 GET 전용이라 POST로 여는 LLM 스트림에 사용할 수 없었습니다. 2023년 국회 파일럿에서 fetch 기반 SSE 파서를 직접 구현해 프레임 구분 · 이벤트 경계 · 연결 수명까지 다뤘고, 백엔드가 늘어난 지금은 형식 변환을 BFF 어댑터 한 곳에 모아 화면은 Vercel AI SDK 프로토콜 하나만 다룹니다.

스트리밍 중계 구조 스트리밍 중계 구조 — 형식 변환과 프레임 조립을 BFF에 모아, 화면은 한 가지 스트림 형식만
형식 변환과 프레임 조립을 BFF에 모아, 화면은 한 가지 스트림 형식만 다룹니다

01-B요소별 렌더 시점

마크다운 문법은 완성된 문서를 전제로 합니다. 요소마다 미완성의 위험이 달라 렌더 시점을 분리했습니다. 코드는 열리는 즉시 증분 하이라이트되고, 다이어그램은 완성을 감지한 뒤에만 렌더되며, 수식은 완성되는 순간 원문에서 수식으로 전환됩니다.

스트리밍 중 — 코드 블록 증분 하이라이트
스트리밍 중 — 도착한 코드가 증분 하이라이트, 생성은 언제든 중지
인용 클릭 — 페이지 이동과 문장 하이라이트
인용 클릭 — 뷰어가 해당 페이지로 이동해 문장 좌표를 하이라이트

01-C라이브러리 도입과 내부 확장

2년 넘게 자체 구현으로 운영하다 assistant-ui를 도입했고, 라이브러리에 없는 개념이 필요해지자 렌더 primitive의 그룹핑 상태머신을 패치해 참조문서 그룹을 새 개념으로 추가했습니다. 도메인 특화 개념이라 업스트림 PR 대신 최소한의 패치로 구현했습니다. 라이브러리가 0.12에서 그룹 렌더를 공개 API로 열자 패치를 걷어내고 그 API로 옮겼습니다. 인용을 클릭하면 문서 뷰어가 해당 페이지로 이동해 문장 좌표를 하이라이트합니다. 뷰어에는 포맷별 처리가 없습니다.

참조문서 접이식 카드
라이브러리 패치로 추가한 참조문서 그룹 — 접이식 카드에 검색된 청크
인용 클릭 — 문서 뷰어 하이라이트
인용 클릭 — 뷰어가 해당 페이지로 이동해 문장 좌표를 하이라이트
Next.jsassistant-uiVercel AI SDKremark/rehypeKaTeXShikimermaid
02
[02] performance

런타임 성능 개선:렌더링 병목의 계측과 제거

2024 – 2026
재현 → 계측 → 특정 → 전후 검증

납품 현장에서만 느린 화면이 있었습니다. 사내 회선에서는 0.2초에 열려 재현되지 않았고, Slow 4G 시뮬레이션에서야 13초로 재현됐습니다. 측정으로 병목을 특정하고, 변경 전후를 같은 조건으로 검증해 반영했습니다.

02-A계측과 폰트 프리로드 재설계

Turbopack이 라우트별 번들 리포트를 제공하지 않게 되어 빌드 매니페스트를 직접 파싱해 계측했습니다(116개 라우트, 실측 대조 오차 10% 이내). 주 폰트 서브셋만으로 같은 Slow 4G 조건에서 LCP가 13초에서 6.2초로 줄었습니다. next/font의 preload를 끄는 설정 두 줄로 재설계해 초기 폰트 전송이 90.5% 줄었고, woff2 변환 · 서브셋으로 폰트 자산을 52.1MB에서 5.9MB로 정리했습니다.

폰트 preload 전후 실측 (2026.07) 폰트 preload 전후 전송 워터폴 — 초기 폰트 전송 −90.5%
변경 전후의 초기 로드 폰트 요청 — CDP 네트워크 로그, 캐시 초기화 후 5회 접속 중앙값

02-B대량 렌더링과 리렌더 억제

약 2천 개 아이콘 선택 UI를 가상 그리드로 바꿔 DOM 노드 −97%(11,637 → 339), 렌더 완료 5.3배(160 → 30ms), 목록 복귀 15배(137 → 9ms) — 아이콘 1,951개, 전후 실측 9회 중앙값. 관리 화면의 대형 트리는 지연 로딩과 무한스크롤로 바꿨습니다. 키 입력마다 번지던 리렌더는 memo 경계와 원시값 props로 억제했습니다.

가상 그리드로 교체한 아이콘 피커
가상 그리드 아이콘 피커 — 보이는 영역만 렌더
지연 로딩 · 무한스크롤 관리 트리
지연 로딩 · 무한스크롤로 바꾼 관리 트리 — 노드 선택 시 상세
React ProfilerLighthouseCDPnext/font
03
[03] monorepo

모노레포와 개발 환경:사내 첫 Next.js 앱에서 21개 앱 모노레포까지

2023 – 2026
첫 커밋부터 설계 · 구축 · 운영

시작은 앱 하나였습니다. 세 번의 구조 전환을 거쳐, 지금은 하나의 모노레포에 21개 앱이 공통 패키지를 공유하며 각자 배포됩니다. 개발 환경과 CI까지 함께 만들었습니다.

03-A공통 패키지와 제품 구조

인증 · API 클라이언트 · 설정 · 디자인 시스템을 공통 패키지 4종으로 분리했고, 새 앱은 스캐폴딩 제너레이터로 같은 규약 위에서 출발합니다. 전 제품의 인증은 별도의 IdP가 맡습니다. 현행 공공 납품은 이 메인 코드베이스를 그대로 사용하고, K-water GPT · On-AI는 이전 세대에서 파생됐습니다. 동적 메뉴는 셸에 등록하는 API로만 렌더되고, 셸을 우회하는 구현은 앱 소스를 파싱해 규약 위반을 잡는 거버넌스 테스트가 차단합니다.

제품 관계도 제품 관계도 — 21개 앱 모노레포를 중심으로 IdP와 납품 코드베이스가 연결
AI-OCR 대시보드
모노레포의 앱들 — AI-OCR 대시보드
에이전트 빌더
에이전트 빌더 — 내 에이전트
게시판 홈
게시판 · 협업
GO-RAG 홈
GO-RAG 홈 — 같은 공통 패키지와 디자인 시스템 위에서 각자 다른 도메인

03-B중앙 설정 서버와 런타임 레이아웃

설정을 코드 밖으로 꺼내 중앙 설정 서버(platform-core)에 두고, 바뀐 값은 각 앱에 SSE로 실시간 반영됩니다. 고객사별 UI 차이는 코드 분기 없이 런타임 레이아웃 설정으로 수용합니다. 감사 로그와 세션 리플레이는 PostHog를 하나의 이미지로 묶은 분석 서비스(analytics-service)가 맡고, 브라우저 수집은 개인정보 마스킹이 기본입니다.

감사 개요 — 기간별 지표와 일별 추세
감사 개요 — 기간별 지표와 일별 추세
세션 상세 — 리플레이 플레이어와 이벤트 마커
세션 상세 — 리플레이 플레이어와 이벤트 마커 진행바
런타임 레이아웃 콘솔
런타임 레이아웃 콘솔 — 편집하면 프리뷰에 즉시, 활성화하면 각 앱이 재기동 없이 SSE로
GO-RAG — 기본 템플릿
기본 템플릿의 GO-RAG
GO-RAG — 다른 템플릿 활성화
같은 앱에 다른 템플릿 — 로고 위치 · 앱 스위처 · 툴바 구성 · 색상이 설정만으로

03-C개발자 스코프 라우팅

공유 인프라(인증 서버 · 설정 서버 · 프록시)는 하나만 두고, 개발자 PC에는 모노레포만 남겼습니다. git 사용자명 기반으로 서브도메인을 동적으로 발급해, 자기 이름의 주소로 접속하면 운영과 같은 인증 흐름을 거쳐 각자의 로컬 dev 서버로 라우팅됩니다. AI 에이전트가 작업한다는 전제로 디렉터리별 작업 규칙 문서(AGENTS.md)를 두고, 산출물은 lint · 계약 검사 · E2E 게이트를 통과한 뒤 리뷰합니다.

개발자 스코프 라우팅 개발자 스코프 라우팅 — 공유 인프라 하나, 개발자 PC에는 모노레포만

03-D사내 첫 GitLab CI

사내 GitLab에 CI를 최초로 도입했습니다. 지금은 20개 레포지토리가 쓰는 표준이 됐고, 누적 파이프라인은 5,000개를 넘었습니다(2026.08 기준). 브랜치가 배포 환경에 대응하고, 이미지는 CI 전용으로 새로 구축한 레지스트리에 저장합니다.

파이프라인 상세 — 전 스테이지 통과(이관 뒤 GitLab 19.3)
순환 의존 · 미사용 코드 검사까지 포함한 CI 스테이지 구성 (GitLab 19.3)
파이프라인 목록
파이프라인 목록 — 누적 5,000+ (2026.08)
Next.jsTurborepoYarn BerryRedisPostgreSQLDockerGitLab CIHarborTraefik
04
[04] auth-delivery

인증과 공공 납품:공공 납품에서 자체 인증 서버까지

2023 – 2026
우정사업본부 · 한국방송통신전파진흥원 · 한국수자원공사 · 한국지역난방공사 · 행정안전부 · 한국가스기술공사 · 한국부동산원

기관마다 제약이 달랐습니다. 망이 분리되어 있거나, 보안 심사를 받거나, 문서가 DRM으로 암호화되어 있었습니다. 제약을 하나씩 풀다가 2026년에는 인증 서버를 직접 만들게 됐습니다.

04-A토큰 노출 차단과 DRM 복호화

보안 심사에서 반복해 나온 지적을 구조로 풀었습니다. 리버스 프록시의 forward auth가 JWT를 프록시 뒤에서 붙이기 때문에 토큰이 브라우저로 내려가는 일 자체가 없습니다. 권한 판정 결과는 TTL 60초로 캐시하되 권한이 바뀌면 권한 버전을 올려 즉시 무효화하고, 정책이 등록되지 않은 경로는 fail-closed로 차단합니다. 기관 PC에서 올라오는 DRM 문서는 전담 서비스가 C++ 네이티브 모듈을 FFI로 호출하고 워커로 병렬화해 복호화합니다.

현행 토큰 흐름 — forward auth 토큰 흐름 — 브라우저 구간에는 토큰이 없고 JWT는 프록시 뒤에서만
브라우저 구간에는 토큰이 존재하지 않고, JWT는 프록시 뒤에서만 붙습니다

04-B자체 IdP

국가정보원 국가 망 보안체계(N2SF) 가이드라인을 준용해 oidc-provider를 기반으로 어댑터 · 정책 · 화면 · 감사 계층을 직접 구현해 OAuth2/OIDC 인증 서버를 만들었고, 레거시 인터페이스와 호환성을 유지해 소비 앱 수정 없이 교체했습니다. 로그인 · 동의 · 회원가입 화면은 인증 서버 레포지토리 안에서 React SSR로 만들었습니다.

IdP 로그인 카드
IdP 로그인 — 인증 서버 레포지토리 안의 React SSR
가입 위저드 인증 코드 단계
가입 위저드 — 유효 시간 · 재전송 쿨다운 표시

04-C업로드 대기열

큰 파일을 올리는 동안에도 사용자는 화면을 옮겨 다닙니다. 업로드 상태를 Service Worker가 소유하고 IndexedDB에 저장하게 해 라우팅과 새 탭에도 이어지는 대기열을 만들었고, 청크 단위 재시도와 취소 전파까지 담았습니다.

업로드 대기열 — 파일 3개 진행 중
업로드 대기열 — 페이지를 옮겨도 Service Worker가 상태를 소유, 파일별 진행률 유지

04-D납품 화면

1세대 코드베이스에서는 기관별로 분기해 브랜딩과 화면 구성을 달리 납품했고, 지금은 분기 없이 단일 코드베이스로 납품합니다. K-water GPT 납품은 국내 공공기관 중 RAG 기반 업무 시스템을 정식 오픈한 최초 사례로 보도됐습니다(인공지능신문, 2025.02).

우정사업본부 RPA 포털 — 홈 대시보드
우정사업본부 RPA 포털 (표시 데이터는 촬영용 목업)
KCA RPA 포털 — 성과관리 대시보드
한국방송통신전파진흥원 RPA 포털 — 같은 1세대 코드베이스에서 분기, 다른 브랜딩 · 화면 구성
K-water GPT
K-water GPT — 국내 공공기관 RAG 정식 오픈 최초 사례로 보도(2025.02)
한국지역난방공사 On-AI
한국지역난방공사 On-AI — 홈
oidc-providerTraefikService WorkerIndexedDBFastifynodemailer
05
[05] ui-agent

UI 생성 에이전트:요구사항에서 사이트맵 설계, 화면 생성까지

2026
프론트엔드 · 백엔드 개발

요구사항 명세(SRS)와 유스케이스(UC) 문서를 받아 사이트맵을 설계하고, 화면마다 컴포넌트 구성을 정한 뒤 Next.js 코드를 생성합니다. LLM의 생성을 어디까지 허용하고 어떻게 판정할지를 가장 오래 고민했습니다. 기준은 프론티어 모델과 인터랙티브하게 작업해 직접 다듬은 골든 페이지입니다.

05-A생성의 통제

LLM이 편집할 수 있는 위치를 marker 구간으로 한정하고 import는 규칙으로 주입합니다. 존재하지 않는 모듈을 불러오는 일 자체가 생기지 않습니다. 컴포넌트 레지스트리는 pgvector 벡터 검색으로 조회하고, 호출마다 흔들리는 LLM 한글 출력은 자모 분해 유사도 매칭으로 흡수합니다.

생성 파이프라인 — 단계마다 검증 생성 파이프라인 — 요구사항에서 라이브 프리뷰까지, 단계마다 검증 게이트
실패 시 해당 페이지만 재시도합니다

05-BJSON 스트림과 실시간 트리

완성되지 않은 JSON을 증분 파싱해 노드가 도착하는 대로 트리에 붙입니다. 구조 데이터는 일부만 도착한 상태에서도 항상 올바른 트리여야 합니다. 수정 요청이 반영되면 변경된 노드만 하이라이트하고 첫 변경 노드로 스크롤합니다.

생성 진행 중 — 실시간 사이트맵 트리
생성 진행 중 — 도착 중인 JSON을 증분 파싱해 트리가 실시간으로 자랍니다
수정 반영 직후 — 변경 노드 하이라이트
수정 요청 반영 직후 — 변경 노드 하이라이트, 첫 변경 노드로 스크롤

05-C판정과 검증 루프

판정은 LLM에 맡기지 않고, 기준을 코드로 정의했습니다. 실패 유형 45종 게이트와 Playwright DOM 실측을 거치고, 상호작용 컴포넌트는 9단계 시나리오로 검사합니다. ts-morph 상주 인스턴스 풀로 생성 코드 재검증 시간이 초 단위에서 밀리초 단위로 줄었고(매 검증마다 tsc를 새로 실행하던 기존 구조 대비 실측), 재시도는 전역 중단 대신 페이지 단위 상한으로 관리합니다.

생성 완료 — 검증 · 폴리싱 요약
생성 완료 — 챗에 남는 검증 · 폴리싱 요약 (노드 88 · UC 매핑 151 · 이슈 0)
라이브 프리뷰로 뜬 생성 대시보드
생성 결과 — 라이브 프리뷰로 동작하는 대시보드
Next.jsTypeScriptFastifyVercel AI SDKvLLMpgvectorts-morphPlaywright
06
[06] design

디자인과 반응형 웹:회사 홈페이지부터 제품 화면까지

2021 – 2026
디자인 · UI 개발 · 반응형

회사 홈페이지의 디자인과 초기 코드베이스를 만들었고, 제품 화면의 반응형 규칙을 요소 단위로 설계합니다. 지금 보고 계신 이 사이트도 같은 원칙으로 직접 만들었습니다.

06-A회사 홈페이지 — gridone.co.kr

2023년 말 리뉴얼부터 지금까지 관여해 온 홈페이지입니다. 코드베이스 초기 구성과 디자인을 맡았습니다. 데스크톱부터 모바일까지 반응형으로 동작하며, 인포그래픽은 직접 그려 사용했습니다.

gridone.co.kr 데스크톱 히어로
gridone.co.kr — 데스크톱
같은 화면의 모바일 뷰
같은 화면의 모바일 반응형
도입사례 — 한국수자원공사 K-water
도입사례 섹션 — 한국수자원공사 K-water
기술 연혁 그래픽
기술 연혁 그래픽 — 직접 그린 인포그래픽
AI 에이전트 섹션
AI 에이전트 섹션
고객 실적 섹션 — 금융 · 공공 150+
고객 실적 섹션 — 금융 · 공공 150+
gridone.co.kr

06-B제품 화면의 반응형과 UI 개발

제품 상단바의 접힘 규칙을 요소별로 정했습니다. 로고는 폭 고정, 브레드크럼은 마지막 항목만, 툴바 버튼은 라벨을 숨기고 아이콘만 남깁니다. 시작은 농협은행 · 교보생명 RPA 포털 디자인과 UI 개발이었고, 교보 포털에서는 Parcel · Pug · Sass 빌드 파이프라인을 직접 구성했습니다(2021–2022).

농협은행 RPA 포털 관리자 대시보드 디자인 시안
농협은행 RPA 포털 관리자 대시보드 — 디자인 시안 (2021)
교보생명 RPA 포털 메인 화면 디자인 시안
교보생명 RPA 포털 메인 — 디자인 시안 (2022)
Next.jsTailwindFramer MotionFigmaPhotoshopIllustrator
07
[07] open-source

오픈소스:사외 공개 기여, krdscn/ui · vLLM Metal

사외에 공개한 작업과 기여
지금 바로 열어볼 수 있습니다

업무에서 shadcn/ui로 개발하다 공공 고객사의 KRDS(정부 디자인 시스템) 적용 요구를 받을 때마다 불편했습니다. 동료와 함께 KRDS 가이드라인을 shadcn/ui 방식의 컴포넌트로 옮기고 있습니다. npx shadcn add로 설치하면 소스가 그대로 프로젝트 코드가 됩니다.

41종
KRDS 공식 HTML 키트를 shadcn/ui 패턴으로 작성한 컴포넌트
109편
공식 KRDS 가이드라인을 본문 그대로 MDX로 옮긴 한국어 문서
9개
아이덴티티부터 피드백까지, KRDS 분류 그대로의 카테고리
krdscn/ui 문서 사이트
krdscn-ui.js.org — 우측 신청 폼은 설치되는 소스 그대로 동작하는 데모
krdscn/ui가 쓰인 iM뱅크 AI OCR Portal
krdscn/ui 적용 — iM뱅크 프로젝트 화면 데스크톱 (표시 데이터는 촬영용 목업)
같은 포털의 모바일 뷰
같은 포털의 모바일 반응형
vLLMvllm-project/vllm-metal

UI 생성 에이전트의 LLM 서빙을 검증하기에는 다른 트래픽이 섞이지 않는 로컬이 나았고, 개발용 Mac은 하드웨어로는 충분했습니다. 사용하려던 모델이 vLLM의 Apple Silicon 플러그인에서 지원되지 않아 지원을 직접 추가했습니다. Metal 커널 작성과 GPU 행(hang) 수정, 리뷰 반영을 거쳐 PR 5건이 머지됐고, 변경마다 벤치마크를 측정 조건과 함께 커밋에 남겼습니다.

merged pull requests · 5 of 5 approved
Next.jsReactRadix UIshadcn/uiMDXPlaywrightPythonMLXMetal