반갑습니다,

프론트엔드 개발자

김지훈

입니다.

아래로 스크롤해 주세요

ABOUT

소개

더 나은 사용자 경험은 작은 관찰에서 시작된다고 생각합니다.

기술적완성도와함께사용자의편의를고민하는프론트엔드개발자김지훈입니다.마이크입력상태를알기어려운순간이나알림이오지않아다시웹을확인해야하는상황처럼,사소하지만신경쓰이는문제를그냥지나치지않습니다.

이러한문제를해결하는과정에서브라우저가생각보다다양한역할을있음을배우고있습니다.사용자가지금어떤동작을하고있고어떤과정이진행중인지분명하게보여주는방법을고민하며,주어진환경안에서이를구현할있는방식을찾아가고있습니다.

복잡해지기쉬운로직은번에구현하기보다,역할에따라나누어정리하려고합니다.제가작성한코드의구조가정돈되어있고부분의역할이분명할보람을느낍니다.

PROJECTS

프로젝트

슬라이드 1
슬라이드 2
슬라이드 3
슬라이드 4
슬라이드 5
슬라이드 6
01 / 06

카페, 도서관 등 학습 및 작업 공간에서의 경험을 기록하고 공유하는 서비스입니다. 공간의 분위기, 소음, 혼잡도, 집중도 등을 기록해 나의 몰입 패턴을 분석해 볼 수 있고, 다른 사용자의 기록도 함께 둘러볼 수 있습니다.

  • Turborepo 기반 모노레포로 앱과 디자인 시스템 패키지를 분리하고, Storybook과 Chromatic을 활용해 디자이너와 컴포넌트 단위로 피드백을 주고받았습니다.[Storybook]
  • @base-ui/react 헤드리스 컴포넌트를 기반으로 공통 컴포넌트를 구축하면서, 입력 필드와 오류 메시지 연결, 상태 변화 고지, 다이얼로그 포커스 관리 등 스크린 리더 사용자를 고려한 접근성을 처리했습니다.
  • FSD 아키텍처를 적용해 views, features, entities, shared 레이어로 역할을 나누고, 같은 레이어 내 슬라이스 간 직접 참조를 금지해 의존성 방향을 단방향으로 유지했습니다.
  • 카카오맵 SDK로 커스텀 오버레이와 마커 클러스터링을 구현하고, 지도 바운드가 바뀔 때마다 새 핀 데이터를 불러오도록 했습니다.[PR]
  • Geolocation API로 현재 위치를 지도 초기 좌표로 활용하고, Web Share API를 사용해 게시글 공유 기능을 구현했습니다.
  • SSE로 배지 알림을 실시간으로 수신하고, Next.js API Route를 BFF로 활용해 인증 쿠키를 유지한 채 스트림을 버퍼링 없이 전달했습니다.[PR]
TypeScriptNext.jsTanStack QueryTanStack QueryZustandZustandReact Hook FormZodTurborepoTurborepoStorybookSentry
슬라이드 1
슬라이드 2
슬라이드 3
슬라이드 4
슬라이드 5
01 / 05

음성 대화와 채팅을 AI가 분석해 객관적인 레포트로 제공하는 서비스입니다. 대화가 끝난 후 제공되는 레포트를 통해 사용자는 자신의 논리와 대화 흐름을 되돌아볼 수 있습니다.

  • Web Audio API로 마이크 볼륨을 실시간으로 분석해 사용자가 발화 여부를 즉시 확인할 수 있도록 했습니다.[관련 포스트]
  • MediaRecorder로 녹음한 WebM을 서버 없이 브라우저에서 MP3로 변환하기 위해 FFmpeg WebAssembly를 도입했습니다.
  • 채팅과 AI 분석 결과 스트리밍에 각각 다른 WebSocket이 필요해, 연결 및 구독 로직을 추상 클래스로 공통화하고 달라지는 부분만 재정의했습니다.
  • 시간이 걸리는 AI 분석을 기다리게 하지 않고 메인 화면으로 이동시킨 뒤, 분석 완료 시 WebSocket 알림을 받아 TanStack Query 캐시를 무효화해 레포트 목록이 자동 갱신되도록 했습니다.
  • 서버가 내려주는 64비트 ID가 JSON.parse 과정에서 정밀도를 잃는 문제를 발견하고, Axios 응답 변환 단계에서 ID를 문자열로 파싱하도록 했습니다.
  • 레포트 카드 스와이프를 구현하면서, 초기 이동 방향으로 스와이프 의도를 판별해 수평 제스처일 때만 세로 스크롤을 차단하고, 키보드 내비게이션을 함께 지원했습니다.
  • 초기 로드 크기를 줄이기 위해 라우트별로 번들을 분리하고, 용량이 큰 FFmpeg WebAssembly는 녹음 기능을 사용하는 시점에만 동적으로 로드하도록 했습니다. 이미지 WebP 변환과 폰트 서브셋도 함께 적용했습니다.
  • 오디오 변환, 녹음, WebSocket 재연결 로직에 대한 단위 테스트를 작성해 수정 시에도 기존 동작이 깨지지 않도록 했습니다.
TypeScriptReactViteViteTanStack QueryTanStack QueryAxiosJotaiJotaiVitestVitestWeb Audio APISTOMP
슬라이드 1
슬라이드 2
슬라이드 3
슬라이드 4
슬라이드 5
슬라이드 6
슬라이드 7
슬라이드 8
슬라이드 9
01 / 09

디지털 기기 사용이 낯선 시니어가 자신의 능력을 서비스로 개설하고 판매할 수 있도록 돕는 아웃소싱 플랫폼입니다. 서비스 등록부터 의뢰, 결제, 정산까지 외주 과정 전반을 지원합니다.

  • 채팅 메시지 타입을 주문 확인과 결제 완료까지 확장해 별도 화면 없이 채팅 안에서 거래 흐름을 이어갈 수 있도록 했습니다.
  • PortOne SDK로 결제를 연동하면서 사전 등록 → 결제 요청 → 서버 검증 단계마다 에러를 분리해 처리했습니다.
  • 메시지 전송 시 낙관적 업데이트를 적용해 임시 메시지를 먼저 렌더링하고, 서버로부터 전달된 확정 메시지를 텍스트 또는 fileUrl 기준으로 매칭하여 임시 메시지를 실제 메시지로 교체했습니다.
  • 발신자 기준으로 연속 메시지를 그룹화해 말풍선 모서리, 프로필 표시, 타임스탬프 위치를 일관되게 처리했습니다.
  • 다단계 폼을 단계별 독립 useForm 인스턴스로 분리해 관리하고, 회원가입 시 선택한 역할에 따라 나이 기준이 달라지도록 Zod 스키마를 팩토리 함수로 생성해 동적으로 검증했습니다.
  • 서비스 등록 시 입력한 개요를 바탕으로 AI가 소개글 초안을 생성하고, 반환된 HTML을 WYSIWYG 에디터에 바로 불러와 수정할 수 있도록 연결했습니다.
TypeScriptReactViteViteTanStack QueryTanStack QueryAxiosJotaiJotaiReact Hook FormZodSTOMP
슬라이드 1
슬라이드 2
슬라이드 3
슬라이드 4
슬라이드 5
슬라이드 6
01 / 06

전세 계약, 공과금 관리, 집 수리 등 학교에서 알려주지 않는 현실적인 주거 생활 문제를 청년들이 직접 묻고 배우며 해결할 수 있는 플랫폼입니다.

  • 앱이 실행 중이지 않아도 알림을 받을 수 있도록 FCM과 Service Worker를 사용해 백그라운드 푸시 알림을 구현했습니다.
  • iPhone 사용자가 업로드하는 HEIC 이미지를 서버 처리 없이 클라이언트에서 JPEG로 변환하고 압축하도록 했습니다.
TypeScriptReactVite PWAVite PWATanStack QueryTanStack QueryAxiosJotaiJotaiFirebaseFirebase
슬라이드 1
01 / 02

행동 활성화 이론을 바탕으로 일상 속 무기력 해소를 돕는 다이어리 및 캘린더 앱입니다.

  • React Native WebView로 SVG 라인 드로잉 애니메이션을 구현해 앱 시작 화면에 적용했습니다.[PR]
  • 공공 데이터 포털 API를 사용하여 캘린더에 공휴일을 연동하고, 결과를 캐싱해 반복 요청을 줄였습니다.[PR]
TypeScriptReact NativeTanStack QueryTanStack QueryAxiosRecoilWebView