큐시즘 33기 밋업 프로젝트에서 KKIUM이라는 서비스를 개발했다.
KKIUM은 취업 준비생의 흩어진 경험을 AI로 구조화하고, 이를 공고 분석과 자기소개서 작성까지 연결해주는 AI 기반 커리어 관리 서비스다. 사용자는 노션이나 PDF 등 기존에 정리해둔 경험 자료를 가져오고, AI가 분석한 경험을 바탕으로 공고와 자기소개서 문항에 맞는 경험을 추천받을 수 있다.
내가 주로 담당한 영역은 경험 관리와 경험 추가 플로우였다.

경험 추가 플로우는 단순한 입력 폼이 아니었다. 사용자는 직접 경험을 입력할 수도 있고, PDF 파일을 업로드하거나 Notion과 연동해 기존 자료를 불러올 수도 있었다. 이후 AI 분석 결과를 기반으로 기본 정보, 핵심 경험, 결과 정보가 단계별로 채워지고, 사용자는 이를 확인하고 수정한 뒤 경험으로 저장한다.
가장 기억에 남는 문제는 Notion OAuth 이후 업로드한 PDF 파일이 사라지는 문제였다.
사용자가 PDF 파일을 업로드한 뒤 Notion 연동을 진행하면 외부 인증 페이지로 이동하게 된다. 이때 현재 페이지가 언마운트되면서 React state에 저장되어 있던 File 객체가 초기화되었다. 사용자는 파일을 업로드했다고 생각했지만, 인증을 마치고 돌아오면 파일 정보가 사라지는 문제가 발생했다.
처음에는 localStorage를 떠올렸지만, File 객체를 저장하기 위해 base64로 변환하면 용량이 커지고 변환 비용도 발생했다. 아직 분석 전인 파일을 백엔드에 임시 저장하는 것도 적절하지 않다고 판단했다.
그래서 IndexedDB를 사용해 브라우저에 File 객체를 임시 저장하고, OAuth 이후 페이지로 복귀했을 때 다시 복구하는 방식으로 해결했다. 또한 IndexedDB는 명시적으로 삭제하지 않으면 데이터가 남기 때문에, 분석 완료나 파일 삭제처럼 더 이상 보존할 필요가 없는 시점에 임시 데이터를 정리하도록 처리했다.
이 문제는 별도 트러블슈팅 글로 더 자세히 정리했다.
관련 글: React state는 페이지 밖을 모른다
프로젝트 후반에는 Lighthouse와 Chrome DevTools를 기반으로 성능 최적화를 진행했다.
처음에는 Lighthouse 점수를 올리는 것에만 집중하기 쉬웠지만, 실제로는 각 지표를 나누어 보는 것이 중요했다. FCP, LCP, Speed Index, TBT, CLS를 확인했고, 특히 초기 렌더링에 필요하지 않은 리소스와 폰트 전송량을 줄이는 데 집중했다.
먼저 폰트 최적화를 진행했다. 기존 NanumSquare 폰트 파일은 .ttf 형식이었고, 전송량이 큰 편이었다.

이를 .woff2로 전환한 뒤 폰트 파일 전송량은 크게 줄었다.

NanumSquare 폰트 4종의 총 전송량은 기존 .ttf 기준 약 2,872KiB였고, .woff2 전환 이후 약 780KiB로 감소했다. 약 2,092KiB, 비율로는 약 72.8%의 폰트 전송량을 줄일 수 있었다.
다음으로 경험 페이지와 경험 추가 페이지에 코드 스플리팅을 적용했다. 경험 추가 페이지는 업로드, 기본 정보 입력, 핵심 경험 입력, 결과 확인, 분석 중, 완료 화면 등 여러 단계로 구성되어 있다. 사용자가 처음 진입했을 때 모든 단계의 코드가 필요하지 않기 때문에, Next.js의 next/dynamic을 사용해 단계별 컴포넌트를 지연 로딩하도록 분리했다. 경험 관리 페이지에서도 DnD 정렬 기능이나 다이얼로그처럼 사용자 액션 이후에 필요한 컴포넌트를 초기 렌더링 경로에서 제외했다.
다만 dynamic import가 항상 정답은 아니었다. 작고 항상 화면에 노출되는 컴포넌트까지 분리하면 오히려 추가 요청이 생기고, 로딩 상태가 잠깐 보이며 UX가 어색해질 수 있었다. 그래서 초기 화면에 반드시 필요한 작은 컴포넌트는 정적 import로 유지하고, 사용자 액션 이후 필요한 컴포넌트 위주로 분리했다.
로딩 UI도 함께 개선했다. 단순 spinner나 Lottie보다 실제 콘텐츠 구조와 유사한 skeleton UI가 체감 로딩에 더 적합하다고 판단했다. 경험 카드 목록이나 입력 폼처럼 구조가 명확한 화면에는 skeleton을 적용했고, 분석 중이나 완료 화면처럼 성격이 다른 화면에는 어색한 fallback이 나오지 않도록 조정했다.
동일한 배포 환경의 /experience 페이지를 기준으로 Lighthouse를 다시 측정한 결과, Performance 점수는 63점에서 94점으로 상승했다.


성능 최적화를 진행하며 단순히 Lighthouse 점수를 올리는 것보다, 어떤 리소스가 초기 렌더링에 필요한지 구분하는 과정이 더 중요하다는 것을 배웠다. 모든 컴포넌트를 무작정 지연 로딩하는 것이 아니라, 사용자에게 즉시 필요한 UI와 나중에 필요한 UI를 나누어 판단하는 기준을 세울 수 있었다.
이번 KKIUM 프로젝트는 좋은 PM과 팀원들을 만나 즐겁게 몰입할 수 있었던 프로젝트였다.
각자의 역할에 책임감을 가지고 함께 고민해준 덕분에, 단순히 기능을 구현하는 것을 넘어 하나의 서비스를 완성해가는 경험을 할 수 있었다.
개인적으로도 애정을 많이 가지고 진행한 프로젝트였기 때문에, 이후에도 운영과 유지보수를 이어가고 싶은 마음이 컸다. 팀 사정상 프로젝트를 계속 발전시키지는 못하게 되었지만, 그만큼 아쉬움이 남는 프로젝트이기도 하다.
그래도 이번 경험을 통해 좋은 사람들과 함께 만드는 프로젝트가 얼마나 큰 동기와 에너지가 되는지 다시 느낄 수 있었다. 다음에도 좋은 사람들과 함께 의미 있는 서비스를 만들어가고 싶다.