김민준

복잡한 흐름을 나누고 안정적인 화면을 만듭니다.
실시간 통신, 폼 검증, 지도 기반 화면처럼 상태 변화가 많은 기능을 다뤄온 프론트엔드 개발자입니다.

프로젝트

프로젝트에서 맡은 역할과 문제를 해결한 과정을 소개합니다.

01AI Team Building

DoDream

AI 기반 추천으로 사이드 프로젝트와 스터디 팀 빌딩을 돕는 플랫폼입니다. 채팅, 모집글 작성/수정, 마이페이지 기능을 담당했습니다.

  • Next.js
  • TypeScript
  • WebSocket
  • Zod
  • React Hook Form
  • useChat 커스텀 훅으로 실시간 통신 로직과 UI를 분리
  • Zod 스키마로 모집글 폼 데이터 정합성과 타입 안정성 강화

복잡한 로직을 분리해 유지보수하기 쉬운 채팅 구조 만들기

문제
  • 실시간 통신 로직이 UI 컴포넌트와 강하게 결합되어 코드 규모가 커지고 유지보수성이 떨어졌습니다.
  • 실시간 스트림 데이터와 과거 대화 내역이 섞여 일관된 상태 업데이트가 어려웠습니다.
해결 과정
  • useChat 커스텀 훅으로 소켓 통신과 이벤트 리스너를 추상화해 UI와 비즈니스 로직을 분리했습니다.
  • 과거 대화 내역은 TanStack Query로 서버 상태를 동기화했습니다.
  • 실시간 메시지는 로컬 상태에 즉시 반영하는 전략을 적용했습니다.
결과
  • 채팅방 컴포넌트를 간결하게 유지하고 복잡한 상태 변화를 한곳에서 관리했습니다.
  • 실시간 채팅 로직을 모듈화해 기능 확장 시 사이드 이펙트를 줄였습니다.
DoDream 채팅방 데이터 구조
DoDream 채팅방 데이터 구조
DoDream 실시간 채팅 시퀀스 다이어그램
DoDream 실시간 채팅 시퀀스 다이어그램

Zod 스키마를 활용한 런타임 데이터 정합성 보장

문제
  • 기술 스택, 기간, 인원처럼 구조가 복잡한 모집글 폼에서 타입 불일치와 런타임 오류 위험이 있었습니다.
  • 유효하지 않은 데이터가 서버로 전송되면 불필요한 API 비용과 서버 측 예외 처리 부담이 생겼습니다.
해결 과정
  • Zod 스키마와 React Hook Form을 연동해 입력 단계부터 유효성을 제어했습니다.
  • 필드 변경과 제출 시점에 클라이언트 검증을 실행해 유효한 데이터만 서버로 보냈습니다.
  • Zod 스키마에서 TypeScript 타입을 추론해 전체 데이터 흐름의 정적 안정성을 높였습니다.
결과
  • 데이터 정합성과 클라이언트·서버 간 교환 규칙을 명확히 해 타입 불일치로 인한 런타임 오류를 줄였습니다.
  • 서버 요청 전 1차 필터링으로 네트워크 낭비를 막고 사용자에게 즉각적인 피드백을 제공했습니다.
DoDream 모집글 작성 페이지
DoDream 모집글 작성 페이지
DoDream 백엔드 Swagger Request Schema
DoDream 백엔드 Swagger Request Schema
02Mobility Safety

LittleRiders

학원, 셔틀버스 기사, 보호자가 원생의 승하차와 셔틀 위치를 실시간으로 확인하는 통합 관리 서비스입니다.

  • React
  • SSE
  • Naver Map API
  • Map
  • Figma
  • SSE 기반 실시간 위치 추적과 지도 마커 표시 기능 구현
  • Map 자료구조와 Polyline 재사용으로 마커 중첩 및 브라우저 프리징 해결

Map 자료구조를 이용한 실시간 마커 중첩 및 데이터 관리 최적화

문제
  • 같은 장소에서 여러 원생이 승하차하면 마커가 수직으로 겹쳐 가장 위 마커 외에는 클릭하거나 정보를 확인하기 어려웠습니다.
  • 같은 좌표에도 데이터 수만큼 마커 객체를 만들어 브라우저 메모리를 불필요하게 사용했습니다.
해결 과정
  • 위도와 경도를 조합한 문자열을 Map의 key로 사용했습니다.
  • 새 원생 데이터가 들어올 때 좌표가 Map에 있는지 먼저 확인했습니다.
  • 기존 좌표라면 새 마커를 만들지 않고 마커 객체의 배열에 원생 정보만 추가했습니다.
결과
  • 마커 중첩 현상을 제거했습니다.
  • 마커를 클릭하면 해당 지점의 원생 명단을 한 번에 보여주는 커스텀 클러스터링 효과를 구현했습니다.
LittleRiders 마커 중첩 개선 화면
LittleRiders 마커 중첩 개선 화면
LittleRiders 지도 기능 시퀀스 다이어그램
LittleRiders 지도 기능 시퀀스 다이어그램

Polyline 인스턴스 재사용 로직으로 브라우저 프리징 방지

문제
  • 주행 시간이 길어질수록 지도 렌더링이 느려지고 일정 시간이 지나면 브라우저가 멈췄습니다.
  • 1초마다 좌표가 갱신될 때 전체 경로를 다시 그리며 기존 Polyline 위에 새 인스턴스를 계속 만들고 있었습니다.
  • 주행이 지속될수록 선 객체가 쌓여 메모리 부하가 커졌습니다.
해결 과정
  • Polyline 객체를 useRef로 관리해 컴포넌트 생명주기 동안 단 하나의 인스턴스만 유지했습니다.
  • initPolyline에서 인스턴스를 먼저 만들고, 위치 갱신 시에는 기존 경로에 좌표만 추가하도록 바꿨습니다.
  • Polyline 목록과 표시/숨김 함수는 제거하고 지도 API의 getPath 메서드로 선을 연장했습니다.
결과
  • 여러 Polyline을 쌓아 관리하던 구조를 단일 인스턴스와 좌표 목록 중심의 구조로 단순화했습니다.
LittleRiders 실시간 지도 화면
LittleRiders 실시간 지도 화면
개선 전
const [polyline, setPolyline] = useState<naver.maps.Polyline>();
const [polylineList, setPolylineList] = useState<naver.maps.Polyline[]>([]);

const newPolyLine = new naver.maps.Polyline({
  path,
  strokeColor: COLOR_PALETTE.darkgreen,
  strokeWeight: 10,
  strokeOpacity: 0.7,
  strokeLineCap: 'round',
});

newPolyLine.setMap(realTimeMap);
setPolyline(newPolyLine);
setPolylineList((prev) => [...prev, newPolyLine]);
개선 후
const polyline = useRef<naver.maps.Polyline>();
const latLngList = useRef<naver.maps.LatLng[]>([]);

const initPolyline = (map: naver.maps.Map) => {
  const polylineT = new naver.maps.Polyline({
    map,
    path: [],
    clickable: true,
    strokeColor: '#5347AA',
    strokeWeight: 5,
  });
  polyline.current = polylineT;
};

latLngList.current.push(curLatLng);
polyline.current?.getPath().push(curLatLng);
변경 커밋 보기 ↗
03Automation Tool

webp-tools

이미지 최적화 반복 작업을 줄이기 위해 만든 GUI 기반 WebP 변환 자동화 도구입니다.

  • AI
  • WebP
  • Image Optimization
  • LCP
  • 원본 비율을 유지하며 지정 너비 기준으로 자동 변환
  • 이미지 용량 평균 95% 절감, LCP 2초 이상에서 1초 미만으로 개선

이미지 최적화 자동화 프로그램으로 LCP 단축 및 운영 공수 제거

문제
  • 고용량 PNG와 JPG가 그대로 배포돼 Layout Shift와 LCP 지연이 발생했습니다.
  • 이미지마다 너비가 달라 크기와 비율을 수동으로 변환해야 했습니다.
  • 콘텐츠 팀의 반복적인 수동 변환 작업이 운영 리소스를 계속 소모했습니다.
해결 과정
  • 팀 전체가 수동으로 처리하는 대신 AI를 활용한 자동 변환 도구를 빠르게 만들고 배포하자고 제안했습니다.
  • 반복 로직을 프로토타이핑해 GUI 기반 WebP 변환 도구를 제작했습니다.
  • 입력한 너비에 맞춰 원본 비율을 유지하며 자동 변환하도록 구현했습니다.
결과
  • 이미지 용량을 평균 95% 줄이고 페이지 로딩을 최대 2초 이상에서 1초 이내로 단축했습니다.
  • 팀의 수동 변환 작업을 없애 불필요한 운영 공수를 줄였습니다.
webp-tools 이미지 변환 GUI
webp-tools 이미지 변환 GUI
webp-tools 변환 결과 화면
webp-tools 변환 결과 화면

기술과 작업 방식

흐름이 복잡한 화면을 유지보수하기 쉽게 정리합니다.

타입과 검증
TypeScript와 React, Next.js로 웹 서비스를 만듭니다. Zod와 React Hook Form을 연동해 입력 단계부터 데이터 정합성을 확인합니다.
상태와 실시간 흐름
Zustand와 TanStack Query로 클라이언트 상태와 서버 데이터를 관리합니다. WebSocket, SSE, 지도 API를 연결하며 복잡한 상태 변화를 정리했습니다.
기록과 공유
5년간 700회 이상의 기술 포스팅과 스터디 자료를 작성했습니다. 배운 내용을 제 언어로 정리하고, 복잡한 기술 개념을 이해하기 쉽게 전달합니다.

연락

함께할 기회나 나누고 싶은 이야기가 있다면 메일을 보내주세요.