프로젝트 · 2026.03 –

Bid Tracker

나라장터 입찰 수집·알림 시스템

조달청 공공데이터 API에서 입찰·사전규격·낙찰·계약 정보를 자동 수집하고, 사업 분야별로 분류해 새 공고를 알린다

스케줄러instrumentation 훅조달청 API8 endpointsAPI 클라이언트rate limit · retry멱등 upsert동기화 로그PostgreSQLPrisma대시보드 · 분석키워드 분류기포함 / 제외새 공고 알림Telegram
직접 구현저장소외부 시스템

문제

입찰 공고를 찾으려면 나라장터를 사람이 매일 반복해서 검색해야 했고, 놓치는 공고가 생겼다.

해결

조달청 공공데이터 API 8개 엔드포인트(입찰공고·사전규격·개찰·낙찰·계약)를 주기적으로 수집해 DB에 쌓고, 사업 분야 키워드로 자동 분류한 뒤 새 공고를 텔레그램으로 알린다.

주요 기능

  • 대시보드: 통계 카드, 최근 공고
  • 입찰공고 / 결과공고 / 사전규격: 카테고리 탭, 검색, 기간 필터, 상세와 첨부 규격서
  • 사업분석: 공고와 낙찰·계약 정보를 연결해 낙찰업체와 점수, 실제 낙찰자를 추적
  • 설정: 카테고리별 포함/제외 키워드, 자동 동기화 주기, 알림 봇, 동기화 진행 상황

설계 포인트

  • 앱 내장 스케줄러: Next.js instrumentation 훅에서 cron을 띄운다. 매 분 DB의 동기화 설정을 읽고, 실행 중 플래그로 중복 실행을 막는다.
  • 멱등 동기화: 모든 수집은 upsert로 처리하고, 실행 결과는 동기화 로그에 남긴다. 몇 번을 다시 돌려도 데이터가 중복되지 않는다.
  • API 클라이언트: 요청 간격 제한, 재시도, 전체 페이지 순회. 과거 수년치 데이터는 별도 스크립트로 일괄 적재했다.
  • 키워드 분류기: 공백과 대소문자를 정규화한 뒤 포함/제외 목록으로 매칭한다. 키워드가 바뀌면 기존 데이터 전체를 다시 분류한다.
  • 보안: API 경로는 내부망 IP 허용목록으로 제한한다. 정렬 컬럼은 화이트리스트로 받고, 페이지 범위에 상한을 둔다. 외부 호출 대상은 공공데이터 도메인으로 고정해 SSRF를 막는다.

스택

Next.js 16 (App Router) · React 19 · TypeScript · Tailwind CSS v4 · TanStack Query · Prisma · PostgreSQL · node-cron · nginx · systemd