← 블로그 · Projects
[케이스 스터디] ym_guide — 청년 정책 정보의 탐색 비용을 줄이는 큐레이션 제품 설계기
#Next.js #TypeScript #Supabase #케이스 스터디 #정부 API #추천 시스템
ym_guide — 청년 정책 정보의 탐색 비용을 줄이는 큐레이션 제품 설계기
토리스(Toris Inc.)가 설계·개발·운영하는 청년 혜택 큐레이션 플랫폼 ym_guide의 기술 케이스 스터디다. 공공 데이터를 원료로 삼되 공공 포털이 풀지 못한 “탐색 비용” 문제를 제품으로 푸는 과정 — 데이터 가공 계층 설계, 질문 기반 추천 시스템, Supabase 백엔드 구성 — 을 정리한다.
제품 스냅샷
| 항목 | 내용 |
|---|---|
| 제품명 | ym_guide |
| 개발 착수 | 2025.12 |
| 기술 스택 | Next.js, TypeScript, Tailwind CSS, Supabase (PostgreSQL) |
| 데이터 소스 | 온라인청년센터 청년정책 OPEN API |
| 핵심 가치 | 몇 개의 질문만으로 본인이 받을 수 있는 금융·정책·복지 혜택을 큐레이션 |
1. 어떤 사용자의 어떤 문제인가 — 제품 가설
청년 대상 정책·복지 혜택은 이미 충분히 많고, 데이터도 공공 API로 공개되어 있다. 문제는 공급이 아니라 탐색이다. 대학 졸업 후 취업을 준비하는 청년이 “내가 받을 수 있는 혜택이 뭐가 있지?”라는 질문에 답하려면, 기관별로 흩어진 포털을 돌며 자격 요건을 하나하나 자신의 조건과 대조해야 한다. 정보가 없어서가 아니라 자신에게 해당하는 정보를 골라내는 비용이 너무 커서 혜택을 놓치는 구조다.
이 문제는 개발자 본인이 청년 당사자로서 직접 겪은 문제였고, ym_guide의 제품 가설은 여기서 나왔다.
나이·거주지·소득 같은 몇 개의 질문에 답하는 것만으로, 수백 건의 정책 중 본인에게 해당하는 것만 걸러서 보여줄 수 있다면 정책 탐색 비용을 극적으로 줄일 수 있다.
기존 공공 포털과의 차별점은 데이터가 아니라 인터페이스다. 같은 데이터 위에서 “정책 목록을 검색하게 하는 것”과 “사용자에게 질문하고 결과를 큐레이션해 주는 것”은 완전히 다른 제품이다. ym_guide는 후자에 베팅했다.
2. 제약 조건
- 인력: 기획·개발·디자인·운영 1인. 자체 백엔드 서버를 운영할 여력이 없어 BaaS(Supabase)를 채택했다.
- 예산: 인프라 비용 0원 목표. Vercel + Supabase 무료 티어, 무료 공공 API로 구성했다.
- 데이터 소유권 없음: 정책 데이터의 원천은 정부 API다. 데이터의 구조·품질·갱신 주기를 통제할 수 없다는 것이 이 제품의 가장 큰 구조적 제약이며, 아키텍처의 상당 부분이 이 제약에 대한 대응이다.
- API 호출 제한: 공공 API의 호출 제한이 있어, 사용자 요청마다 원천 API를 때리는 구조는 처음부터 불가능했다.
3. 기술 설계와 트레이드오프
3.1 데이터 가공 계층 — 통제할 수 없는 데이터를 통제 가능한 형태로
온라인청년센터의 청년정책 OPEN API가 데이터 원천이다.
// API 호출 예시
const fetchPolicyData = async (params: PolicyParams) => {
try {
const response = await fetch(
`https://www.youthcenter.go.kr/opi/youthPlcyList.do?openApiVlak=${API_KEY}&pageIndex=1&display=10`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
);
const data = await response.json();
// 데이터 가공
return processPolicyData(data);
} catch (error) {
console.error('API 호출 실패:', error);
return [];
}
};
정부 API 응답은 그대로 제품에 쓸 수 없었다. 구조가 복잡하고, 필드 형식이 일관되지 않으며, 추천에 필요한 자격 조건 정보가 정형화되어 있지 않다. 대응으로 세 가지 설계 결정을 내렸다.
- 단일 변환 함수로 경계 고정 — 모든 원천 데이터는
processPolicyData계층을 거쳐 내부 도메인 모델로 변환된다. API 스펙이 바뀌어도 수정 범위가 이 경계 안으로 갇힌다. - 타입 우선 설계 — 내부 정책 모델의 TypeScript 타입을 먼저 정의하고, 변환 함수가 그 타입을 보장하게 했다. 이후 추천 로직·UI가 전부 이 타입 위에서 동작하므로, 데이터 형식 문제가 런타임이 아닌 컴파일 타임에 걸린다.
- 실패를 흡수하는 에러 처리 — 원천 API 실패가 빈 결과로 우아하게 강등되도록 하여, 통제 불가능한 외부 장애가 제품 전체 장애로 번지지 않게 했다.
또한 API 호출 제한 제약 때문에, 사용자 요청 경로에서 원천 API를 직접 호출하지 않고 가공된 정책 데이터를 자체 저장소에 적재해 두고 서비스하는 구조로 호출량을 통제했다.
3.2 추천 시스템 — 필터링에서 점수 기반으로
추천 파이프라인은 네 단계다.
- 사용자에게 간단한 질문 (나이, 거주지, 소득 등)
- 답변을 필터링 조건으로 변환
- 정책 데이터에서 조건에 부합하는 후보 추출
- 우선순위 점수로 정렬해 표시
1차 구현은 단순 필터링이었고, 실패했다. 조건에 맞는 정책을 전부 나열하는 방식은 결과가 너무 많거나 너무 적었고, 사용자 입장에서 “그래서 나한테 제일 중요한 게 뭔데?”라는 질문에 답하지 못했다. 필터링은 배제의 도구이지 추천의 도구가 아니라는 것을 확인한 것이다.
2차 구현에서 점수 기반 추천으로 재설계했다. 각 정책에 대해 사용자 특성과의 적합도를 점수화하고, 사용자 특성에 따라 축별 가중치를 다르게 적용해 정렬한다. ML 기반 추천도 검토했지만 버렸다 — 신규 서비스에는 학습에 쓸 사용자 행동 데이터가 없고, 정책 추천은 “왜 이 정책이 추천되었는가”를 설명할 수 있어야 신뢰를 얻는 도메인이다. 규칙 기반 점수 시스템은 설명 가능하고, 피드백을 받았을 때 가중치를 즉시 조정할 수 있다는 점에서 이 단계의 올바른 선택이었다.
3.3 백엔드 — Supabase 채택 근거
1인 체제에서 백엔드에 요구한 것은 세 가지였다: 인증, 사용자 데이터 저장(북마크), 그리고 운영 부담 최소화. 자체 API 서버(Node/Express 등) 구축 대안은 인증·보안·배포 운영 비용이 1인 체제에 과하다는 이유로 배제했고, Supabase를 채택했다.
- 내장 인증 — 소셜 로그인 포함 인증 시스템을 직접 구현하지 않는다.
- PostgreSQL + RLS — Row Level Security로 “사용자는 자기 북마크만 읽고 쓴다”는 접근 제어를 DB 레벨에서 강제한다. 별도 API 서버 없이 클라이언트-DB 직결 구조를 안전하게 만드는 핵심 장치다.
- 실시간 기능 — 이후 기능 확장 시 별도 인프라 없이 활용 가능하다.
// Supabase 클라이언트 설정
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
// 북마크 저장
const saveBookmark = async (policyId: string, userId: string) => {
const { data, error } = await supabase
.from('bookmarks')
.insert({ policy_id: policyId, user_id: userId });
if (error) {
console.error('북마크 저장 실패:', error);
}
return data;
};
3.4 북마크와 마이페이지 — 재방문의 근거 만들기
정책 탐색은 일회성 행위가 아니다. 신청 기간을 기다리거나 조건 충족 시점을 기다리는 정책이 있기 때문에, 관심 정책을 저장하고 다시 찾아오게 하는 북마크·마이페이지가 제품의 리텐션 구조에서 필수였다. Supabase 인증과 북마크 테이블 스키마 설계가 이 기능의 기반이며, 스키마를 초기에 신중하게 설계하는 것이 이후 기능 확장 비용을 결정한다는 것을 확인했다.
3.5 UI/UX 원칙
타깃이 청년층이므로 모바일 우선은 전제 조건이었다. 설계 원칙은 네 가지로 고정했다.
- 간단하고 직관적인 인터페이스 — 질문 플로우는 짧을수록 완주율이 높다
- 모바일 우선 디자인
- 빠른 로딩 속도
- 명확한 정보 전달 — 정책의 자격 요건·신청 방법이 요약 없이 흐려지면 제품 가치가 사라진다
4. 사용자와의 검증 — 질문 설계는 사용자가 결정했다
이 제품에서 가장 중요한 설계 결정은 기술이 아니라 **“사용자에게 무엇을 물을 것인가”**였고, 이것은 책상에서 결정하지 않았다.
- 질문 설계의 사용자 테스트: 어떤 질문을, 몇 개나, 어떤 순서로 물어야 하는지를 사용자 테스트로 검증했다. 개발자가 필요하다고 생각한 질문과 사용자가 답할 수 있는·답하려는 질문 사이에는 간극이 있었다. 질문이 많을수록 필터 정확도는 올라가지만 이탈도 늘어난다 — 이 트레이드오프의 균형점을 테스트로 찾았다.
- 추천 결과에 대한 피드백 수집: 추천 결과가 사용자 기대와 어긋나는 사례를 수집해 점수 가중치에 반영하는 루프를 돌렸다. 3.2의 “필터링 → 점수 기반” 재설계 자체가 이 피드백 루프가 만든 가장 큰 변경이다.
- 개발자 = 타깃 사용자: 청년 당사자인 개발자 본인이 첫 검증 대상이었다. 자신이 아는 정책이 자신의 조건 입력에서 정확히 추천되는지가 추천 로직의 스모크 테스트 역할을 했다.
이 과정에서 확인한 것은, 큐레이션 제품의 품질은 알고리즘 정교함보다 입력 설계(질문)의 품질에 먼저 좌우된다는 점이다. 잘못된 질문 위의 정교한 알고리즘은 정확하게 틀린 답을 낸다.
5. 운영과 현재 상태
- 배포: Vercel 자동 배포로 운영 부담을 최소화했다.
- 데이터 갱신: 정책 데이터 갱신이 현재 수동 프로세스라는 것이 가장 큰 운영 부채다. 정책 정보는 시효가 있는 데이터이므로, 갱신 자동화가 기술 로드맵의 최우선 순위다.
- 비용: 무료 티어 조합으로 인프라 비용 없이 운영 중이다.
로드맵은 우선순위 순으로 다음과 같다.
- 정책 데이터 갱신 자동화 — 수동 업데이트를 스케줄 기반 자동 갱신으로 전환. 신뢰성 문제이므로 최우선.
- 사용자 피드백 시스템 내재화 — 추천 결과에 대한 피드백을 제품 안에서 수집해 가중치 개선 루프를 상시화.
- 추천 알고리즘 고도화 — 피드백 데이터가 축적된 이후 머신러닝 기반 추천 검토. 데이터 축적이 선행 조건이다.
6. 다음 제품에 재사용할 교훈
- 공공 데이터 제품의 경쟁력은 데이터가 아니라 인터페이스다. 같은 API 위에서도 “검색하게 하는 것”과 “질문하고 큐레이션하는 것”은 다른 제품이다. 데이터 소유권이 없다면 탐색 비용 절감에서 가치를 만들어야 한다.
- 통제할 수 없는 데이터는 변환 경계와 타입으로 가둔다. 원천 데이터의 품질·구조·갱신을 통제할 수 없을수록, 내부 도메인 모델과 단일 변환 계층의 가치가 커진다.
- 필터링은 추천이 아니다. 조건에 맞는 것을 나열하는 것과 사용자에게 중요한 순서로 보여주는 것 사이에는 점수화·가중치라는 설계가 필요하다.
- 질문 설계는 사용자 테스트의 영역이다. 입력 폼의 문항 하나하나가 완주율과 추천 품질을 동시에 결정하는 제품 결정이며, 개발자의 직관으로 정할 수 없다.
- 1인 체제에서 BaaS + RLS는 백엔드 운영 비용을 구조적으로 제거한다. Supabase의 RLS는 API 서버 없는 아키텍처를 보안적으로 성립시키는 핵심이었고, 이 패턴은 이후 제품에서 기본값이 되었다.
- 수동 운영 프로세스는 반드시 부채로 기록한다. “일단 수동으로”는 출시를 앞당기는 유효한 선택이지만, 데이터 시효가 있는 제품에서는 자동화 전까지 신뢰성 리스크가 계속 쌓인다.