MyApplio

Project Case Study

MyApplio

이력서와 지원 현황, 면접 준비를 하나의 흐름으로 이어주는 AI 기반 구직 워크스페이스입니다. Next.js 16과 Supabase 위에 올렸고, Gemini로 이력서 PDF 가져오기와 채용 공고 탐색, 커버레터 초안 작성을 처리합니다. 공고를 클릭 한 번으로 저장하는 크롬 확장 프로그램도 함께 제공합니다.

라이브 프로젝트 보기
카테고리
SaaS / AI Job Search Workspace
클라이언트
SERVITH (Internal product)
유형
Web App (SaaS) + Chrome Extension
역할
1인 개발로 제품 기획부터 DB와 RLS 설계, AI 파이프라인, 결제, 크롬 확장, 마케팅 사이트까지 맡았습니다.
목표
이력서와 지원 현황, 마감일, 면접이 서로 다른 도구에 흩어지지 않도록 구직 과정 전체를 하나로 연결합니다.
범위
대시보드 24개 섹션, API 라우트 25개 그룹, 공개 이력서 공유, SEO 랜딩 및 비교 페이지, 블로그, Manifest V3 크롬 확장으로 구성했습니다.

Overview

MyApplio는 AI가 거드는 구직 워크스페이스입니다. 랜딩 페이지에는 "Resume to offer · AI assisted" 라는 한 줄을 걸었고, 그 아래에 "Resumes, applications, interviews. Nothing falls through." 라는 약속을 두었습니다.

대부분의 구직자는 스프레드시트와 이력서 파일, 이메일, 그리고 수십 개의 브라우저 탭에 흩어진 채로 구직을 이어갑니다. 도구 하나가 한 단계씩만 맡고 있고, 서로 무슨 일이 있었는지 알지 못합니다. MyApplio는 단계 사이를 잇는 일 자체가 제품이라는 생각에서 출발했습니다. 저장해 둔 공고가 지원 건이 되고, 지원 건은 이력서를 끌어다 쓰고, 이력서는 공고에 맞춰 다듬어지며, 면접 준비는 그 둘의 맥락을 그대로 물려받습니다.

Problem

*

공고를 미처 기록하기 전에 사라지거나, 상세 내용 없이 스프레드시트에 붙여넣기만 하게 됩니다

*

이력서가 거의 똑같은 파일 여러 개로 갈라지면서 어느 것이 최신인지 알 수 없게 됩니다

*

커버레터를 지원할 때마다 빈 화면에서 다시 시작합니다

*

마감일과 후속 연락을 기억에 의존합니다

*

진행이 멈춘 지원 건을 그것을 만들어 낸 자료와 이어 볼 방법이 없습니다

Information Architecture

대시보드는 하나의 목록이 아니라 실제 구직 과정에 등장하는 대상을 중심으로 짰습니다.

1.

수집ai-job-search로 공고를 찾고, 크롬 확장으로 클릭 한 번에 담아 둡니다

2.

파이프라인applications, companies, roles, people, events, notes, links

3.

자료resume, cv, cover-letter, 그리고 공고와 이력서를 견줘 보는 match

4.

준비interview-prep, review, ready, goals

5.

공개 영역resume-directory, resume-search, 공유할 수 있는 공개 이력서 페이지

Technical Implementation

Stack

영역구현비고
프레임워크Next.js 16.2.6 + React 19.2.3App Router, React Compiler 사용
데이터·인증Supabase (Postgres, Auth, SSR)마이그레이션 193개, 데모 계정 읽기 전용까지 RLS로 관리
서버 상태TanStack React Query대시보드 캐시와 무효화 처리
AIGoogle Gemini 2.5 Flash / Flash-LiteSDK 없이 REST를 직접 호출
요청 제한Upstash Redis + RatelimitAI 엔드포인트 남용을 막습니다
결제PolarHTTP 직접 호출, 웹훅은 standardwebhooks로 검증
문서 처리pdfjs-dist, jsPDF, html2canvas, ExcelJSPDF 가져오기와 PDF·스프레드시트 내보내기
알림web-push (VAPID) + Supabase pg_cron사용자 타임존에 맞춘 발송, 기기 실패 시 백오프 적용

작업에 따라 모델 등급을 나눴습니다

AI 호출은 모두 Gemini REST 엔드포인트를 직접 fetch 하는 방식입니다. 무조건 상위 모델을 쓰지 않고, 호출하는 자리마다 필요한 등급을 골라 씁니다.

*

`gemini-2.5-flash` — 답이 열려 있는 생성 작업에 씁니다. 공고 탐색, 커버레터 작성, 이력서 생성, 면접 피드백이 여기에 해당합니다.

*

`gemini-2.5-flash-lite` — 형식이 정해진 대량 추출 작업에 씁니다. PDF 가져오기, 노트 가져오기, 공고 매칭, 이력서 코칭, 스킬 동기화가 여기에 해당합니다.

두 모델 모두 환경변수로 바꿀 수 있고 기본값을 코드에 두었기 때문에, 모델을 교체할 때 코드를 고치지 않고 설정만 바꾸면 됩니다.

이력서 PDF 가져오기는 2단계로 처리합니다

이력서를 가져오는 순간이 제품에서 이탈이 가장 많은 지점이라, 이 부분에 가장 공을 들였습니다. pdfjs-dist로 텍스트를 뽑아낸 다음 Gemini가 두 번 일합니다. 먼저 초안을 뽑고, 이어서 그 초안을 원본과 맞춰 보며 고치는 단계를 거칩니다. 비용과 실행 시간이 늘어나지 않도록 입력 텍스트에는 상한을 뒀고, 파일이 큰 경우 20~40초 정도 걸립니다.

AI 크레딧을 제품의 일부로 다뤘습니다

사용량은 믿고 넘어갈 것이 아니라 재야 할 대상입니다. 호출할 때마다 어떤 모델을 썼는지와 토큰 사용량을 기록하고, 가입과 구독 시점에 크레딧을 지급합니다. 만료는 매일 밤 pg_cron이 훑어서 처리하고, 설정 페이지의 지연 만료를 보조 장치로 함께 뒀습니다.

크론 서비스 없이 스케줄링합니다

vercel.json도 없고 크론 라이브러리도 쓰지 않았습니다. 예약 작업은 Supabase의 pg_cron과 pg_net으로 돌리고, SQL 스크립트로 저장소에 커밋해 두었으며, x-cron-secret 헤더로 인증합니다. 일일 이벤트 푸시는 DB의 IO 부담 때문에 의도적으로 매시간으로 늦췄고, 30분 밑으로는 내리지 말라는 경고를 주석에 남겨 두었습니다. 다음에 이 코드를 볼 사람이 읽을 자리에 운영상의 제약을 적어 둔 셈입니다.

보안

프로덕션에서는 HSTS를 켜고, X-Frame-Options: DENYnosniff, COOP, 그리고 꼭 필요한 권한만 남긴 Permissions-Policy를 next.config.ts에서 설정합니다. CSP는 미들웨어에서 요청마다 새 nonce와 함께 내려주고, 위반 사항은 별도 엔드포인트로 모읍니다.

크롬 확장

MyApplio Job Clipper는 서비스 워커와 사이드 패널을 갖춘 Manifest V3 확장입니다. LinkedIn, Indeed, Glassdoor, Workday 같은 사이트에서 공고를 초안 상태의 지원 건으로 담아 옵니다. 추출 로직만 82KB 남짓 되는데, 채용 사이트마다 공고 구조가 전부 다르기 때문입니다. 완성된 지원 건이 아니라 초안으로 담는 데에는 이유가 있습니다. 저장은 클릭 한 번이어야 하고, 그 순간 사용자에게 아무것도 묻지 않아야 하기 때문입니다.

What This Case Study Shows

*

단계 사이의 연결이 곧 가치가 되는 제품을 설계한 경험

*

작업별로 모델을 나누고 호출마다 사용량을 재고 입력에 상한을 두어, 프로덕션 AI를 감당할 만한 비용으로 운영하는 방법

*

촘촘한 RLS와 193개의 마이그레이션, DB에 내장된 스케줄링까지 Supabase를 깊이 활용한 사례

*

브라우저 확장과 웹 앱을 하나의 제품으로 묶어 내놓은 경험

*

보안과 비용의 경계를 문서가 아니라 코드에 남기는 방식


Live: https://myapplio.com/

Role: 1인 개발 (제품 기획 → 스키마·RLS → AI 파이프라인 → 결제 → 확장 → SEO)

PortalContact