피지크허브
여러 단체와 접수 채널에 흩어진 국내 피트니스·보디빌딩 대회 정보를 공식 출처 기준으로 수집·정규화해 종목, 지역, 단체, 접수 상태별로 탐색하게 한 서비스입니다. 수집 파이프라인, 검수 도구, SEO 랜딩과 자체 분석 대시보드까지 1인 개발·운영하고 있습니다.
Product · Data · Web · Operations / 2026.05 — 현재
흩어진 일정을 한곳에 모으는 것만으로는 신뢰할 수 있는 정보 서비스가 되지 않았습니다. 출처가 서로 다른 정보를 같은 기준으로 비교하고, 확실하지 않은 값은 확실하지 않은 상태로 관리하며, 사용자가 원문과 접수 경로를 다시 확인할 수 있어야 했습니다.
Overview
피지크허브는 국내 피트니스·보디빌딩 대회 일정을 한곳에서 비교하고 출전 계획을 세울 수 있도록 만든 정보 서비스입니다. 사용자는 대회를 종목, 유형, 지역, 단체와 접수 상태로 탐색하고, 상세 정보에서 공식 출처와 접수 페이지를 확인할 수 있습니다. 국내 일정을 중심으로 시즌의 흐름을 이해하는 데 필요한 주요 해외 대회도 함께 제공합니다.
2026년 5월부터 제품 기획, 도메인 조사, 데이터 모델, 수집기, 공개 웹, 운영 어드민과 이용 분석까지 전 과정을 혼자 개발하고 운영하고 있습니다. Next.js와 TypeScript로 공개 서비스를 만들고, Prisma와 PostgreSQL에 정규화된 일정과 출처·검수 정보를 저장했습니다.
담당 범위
- 단체·등록 서비스별 일정 수집기와 정규화 규칙
- 출처, 원문, 필드별 신뢰도와 검수 상태를 포함한 데이터 모델
- 검색·필터·저장·공유·접수 링크로 이어지는 모바일 중심 탐색 경험
- 종목·유형·지역·단체별 SEO 랜딩과 대회 상세 구조화 데이터
- 탐색 퍼널, 리텐션, 유입과 봇 트래픽을 구분하는 자체 분석 시스템
- 검수 큐, 문의와 분석 지표를 확인하는 운영 어드민
Problem
국내 피트니스·보디빌딩 대회 정보는 한 가지 공식 채널에 모여 있지 않습니다. 단체 홈페이지, 접수 서비스, 게시판과 공식 소셜 계정에 나뉘어 있고, 출처마다 날짜·지역·종목을 적는 방식도 다릅니다. 참가자는 여러 채널을 직접 돌아다니며 일정을 비교하고 접수 여부를 다시 확인해야 했습니다.
정보를 모은 뒤에도 다음 문제가 남았습니다.
- 같은 종목이 단체마다 다른 이름과 체급 구조로 표시됩니다.
IFBB Pro League와IFBB International처럼 이름은 비슷하지만 별개의 체계인 단체가 있습니다.- 일정, 장소와 접수 기간은 공지 이후 바뀌거나 일부만 공개될 수 있습니다.
- ‘내추럴’, 프로 퀄리파이어와 국가대표 선발 같은 표시는 이름만으로 단정하기 어렵습니다.
- 검색을 통해 들어온 사용자가 오래된 일정이나 근거 없는 정보를 보게 되면 출전 결정에 직접 영향을 줄 수 있습니다.
따라서 목표는 가장 많은 정보를 자동으로 가져오는 것이 아니었습니다. 공식 출처를 기준으로 서로 다른 정보를 비교 가능한 구조로 바꾸고, 불확실성과 검수 상태까지 운영할 수 있는 탐색 제품을 만드는 것이 핵심이었습니다.
Process
수집기보다 먼저 불확실성을 담는 모델을 만들었습니다
대회 제목과 날짜만 저장하면 화면은 빠르게 만들 수 있지만, 값이 바뀌거나 출처가 충돌했을 때 무엇을 믿어야 하는지 설명할 수 없습니다. 일정 모델에 정규화된 값과 함께 원문, 출처 유형과 URL, 수집 시각, 파서 이름·버전과 원문 해시를 보존했습니다.
날짜, 접수와 장소에는 각각 low, medium, high 신뢰도를 기록하고, 전체 데이터에는 수집·검수 상태와 품질 이슈를 별도로 뒀습니다. 종목도 보디빌딩·클래식 피지크·맨즈 피지크·비키니 같은 기본 분류와 성별·연령·경력·체급 조건을 나눠 저장했습니다. 원문을 잃지 않으면서 화면과 검색에 필요한 공통 기준을 만드는 방식입니다.
출처마다 다른 수집 방식을 하나의 파이프라인으로 묶었습니다
공식 홈페이지, 등록 앱과 게시판은 HTML 구조와 제공 정보가 서로 달라 하나의 범용 파서로 처리하기 어려웠습니다. 출처별 수집기를 만들고 각 수집기가 공통 일정 초안을 반환하게 했습니다. 파이프라인은 결과를 중복 제거하고 시즌과 단체 조건으로 미리 본 뒤 PostgreSQL에 upsert합니다.
공식 출처를 우선하고, 집계 사이트에서 찾은 일정은 발견과 검토를 위한 후보로만 사용했습니다. 코드에서도 aggregator 출처와 보조 수집 데이터는 공식 원본 검수 전 DB 동기화를 막았습니다. 수집량을 늘리는 것보다 공개 정보의 근거를 유지하는 쪽을 선택했습니다.
자동 수집과 사람의 검수를 분리하지 않았습니다
날짜가 없거나 신뢰도가 낮은 정보, 장소·접수 링크 같은 핵심 필드가 빠진 대회를 어드민 검수 큐에서 찾을 수 있게 했습니다. 원문과 정규화 결과, 품질 이슈를 비교하고 pending, needs-review, approved, rejected 상태로 관리합니다.
파서가 읽을 수 있는 것과 운영자가 신뢰할 수 있는 것을 같은 의미로 보지 않았습니다. 검수 상태와 품질 이슈를 데이터에 함께 남겨 새 출처를 추가하거나 파싱 규칙을 고칠 때 확인이 필요한 항목을 추적할 수 있게 했습니다.
데이터 분류를 탐색과 검색 유입 구조로 재사용했습니다
홈과 대회 목록에서는 같은 분류 체계를 종목·유형·지역·단체 탐색에 사용했습니다. 필터 조합을 URL에 보존해 결과를 공유할 수 있게 하고, 관심 대회는 로그인 없이 브라우저에 저장하도록 했습니다. 상세 페이지에서는 일정·장소·접수 상태와 함께 공식 공지 또는 접수 페이지로 이어지는 경로를 우선했습니다.
동일한 taxonomy로 종목 8개, 대회 유형 10개, 국내 지역 17개와 단체 8개를 합친 43개의 고정 랜딩 페이지를 만들고 sitemap에 포함했습니다. 페이지마다 검색 의도에 맞는 제목과 설명, canonical URL, 관련 탐색 링크를 제공하고 대회 상세에는 검증 가능한 장소 정보가 있을 때 Event 구조화 데이터를 추가했습니다. SEO용 페이지를 별도로 복제하지 않고 제품의 데이터 구조가 검색 정보 구조가 되도록 했습니다.
캐시와 현재 날짜의 책임을 나눴습니다
대회 목록은 모든 사용자에게 같은 공용 데이터지만 D-day와 접수 상태는 날짜가 지나면 달라집니다. 시즌 원본 데이터는 Next.js Data Cache에 장기 보관하고, 홈·목록·taxonomy 페이지 HTML은 하루 단위 ISR을 적용했습니다. 예정 대회와 접수 상태는 캐시된 원본 위에서 한국 날짜를 기준으로 다시 계산했습니다.
DB 조회를 줄이면서도 어제의 ‘접수 중’ 상태가 계속 남지 않도록, 변하지 않는 원본과 시간에 따라 달라지는 표현을 분리했습니다.
제품 질문을 직접 확인할 분석 시스템을 만들었습니다
일반 페이지뷰만으로는 사용자가 원하는 대회를 찾았는지 알기 어려웠습니다. 검색·필터, 목록에서 대회 열기, 상세 진입, 저장·공유와 접수 링크 클릭을 별도 이벤트로 정의했습니다. 세션의 최초 유입 정보를 유지하고 이벤트에 멱등 키를 부여해 재전송 중복을 막았습니다.
어드민에서는 목록 조회부터 접수 링크 클릭까지의 탐색 퍼널, 재방문과 코호트, 유입 채널, 검색 결과 0건과 문의 흐름을 확인합니다. 검색 봇과 Headless Chrome 등 의심 트래픽을 사람 이용과 분리하고, 원문 IP와 User-Agent는 90일 뒤 비식별화하도록 운영 정책도 함께 구성했습니다.
Solution
출처를 잃지 않는 일정 데이터 파이프라인
출처별 수집기, 공통 정규화 모델, preview와 dry-run, DB 동기화와 검수 큐를 연결했습니다. 정규화된 결과만 남기는 대신 원문과 파서 정보를 보존해 오류를 추적하고 다시 검수할 수 있습니다. 집계·보조 소스 데이터는 공식 원본 검수 전 DB 동기화에서 제외해 수집 편의보다 출처의 추적 가능성을 우선했습니다.
출전 계획을 위한 공개 탐색 서비스
Next.js 기반 공개 웹에서 전체 일정과 다축 필터, 대회 상세, 관심 대회 저장과 공유를 제공합니다. 종목·유형·지역·단체별 랜딩과 내부 링크, sitemap과 구조화 데이터를 같은 taxonomy에서 생성해 사용자의 탐색 경로와 검색엔진의 정보 구조를 일치시켰습니다.
검수와 의사결정을 위한 운영 도구
운영 어드민에서 데이터 품질과 누락 필드를 검수하고, 문의와 이용 행동을 함께 확인합니다. 자체 분석은 트래픽 규모만 보여 주지 않고 탐색→상세→접수 흐름, 검색 실패와 재방문을 구분해 다음 제품 결정을 위한 근거로 사용합니다.
Results
- 서로 다른 공식 홈페이지·등록 앱·게시판의 데이터를 공통 일정 모델로 변환하고, 출처와 필드별 신뢰도·검수 상태를 추적하는 수집 체계를 구축했습니다.
- 종목·유형·지역·단체의 네 가지 축으로 일정을 탐색하고, 상세 정보에서 공식 출처와 접수 경로를 다시 확인하는 공개 서비스를 출시·운영하고 있습니다.
- 동일한 taxonomy를 필터와 43개의 고정 SEO 랜딩, 내부 링크와 sitemap에 재사용해 제품 탐색 구조와 검색 유입 구조를 하나의 데이터 정의로 관리합니다.
- 사람과 봇 트래픽을 구분한 자체 분석 대시보드에서 대회 탐색 퍼널, 저장·공유·접수 의도, 리텐션과 검색 실패를 확인할 수 있게 했습니다.
- 기획부터 데이터 수집, 사용자 경험, 검색 노출과 운영 분석까지 1인 제품의 전체 피드백 루프를 직접 구성했습니다.
Learnings
데이터 제품에서는 ‘모름’을 표현하는 구조가 필요했습니다
자동 추정값과 확정값을 구분하려면 원문, 필드별 신뢰도와 검수 상태를 함께 보존해야 했습니다. 이 구조를 통해 추정이 개입했거나 정보가 부족한 필드를 다시 확인하고, 자동화를 확대하면서도 사람이 검수해야 할 경계를 추적할 수 있었습니다.
SEO는 메타데이터보다 분류 체계에서 시작했습니다
사용자가 검색하는 종목·지역·단체 기준과 제품의 탐색 기준이 같을 때 랜딩 페이지와 내부 링크를 자연스럽게 만들 수 있었습니다. taxonomy를 하나의 기준으로 사용해 화면, URL과 검색 문구가 서로 다른 의미를 갖는 문제를 줄였습니다.
분석에도 데이터 품질 관리가 필요했습니다
페이지뷰에 봇이 섞이거나 재전송 이벤트가 중복되면 작은 서비스의 지표는 쉽게 왜곡됩니다. 멱등 수집, 봇 분류와 지표 정의 문서를 먼저 갖춰야 기능 변경의 효과를 같은 기준으로 비교할 수 있었습니다.
다음 단계는 수집기의 자동 실행과 실패 알림, 출처 변경 감지를 보강해 일정의 최신성을 더 적은 수작업으로 유지하는 것입니다. 이후 실제 탐색·접수 데이터를 바탕으로 어떤 단체와 필터의 정보 품질을 먼저 개선할지 우선순위를 정할 계획입니다.