GitHub API를 이용해 최근 빠르게 떠오르는 저장소를 1일, 7일, 30일 기준으로 모아 보여주는 Next.js 앱입니다. 후보 저장소를 Search API로 모으고, stargazer timestamp를 기준으로 기간별 증가량을 계산해서 날짜별 hot snapshot으로 보관합니다.
/: 가장 최근success상태 스냅샷 표시/archive/[date]:YYYY-MM-DD형식의 특정 날짜 스냅샷 표시/api/cron/trending:Authorization: Bearer <CRON_SECRET>인증이 필요한 수집 엔드포인트- 홈/아카이브에서
1일,7일,30일기간 탭 전환 UI 제공 - GitHub Search API 기반 후보 수집과 stargazer timestamp 기반 점수 계산
- 스냅샷이 없으면 빈 상태 화면 표시
- 존재하지 않는 아카이브 날짜는 404 화면 표시
- Next.js 16 App Router
- React 19
- TypeScript
- Supabase Postgres
- Vercel Cron
- GitHub REST API
- Vitest + Testing Library
- 스케줄러 또는 수동 호출이
/api/cron/trending을 실행합니다. - 서버가 GitHub Search API로 최근 생성/최근 활동 저장소 후보를 모읍니다.
- 후보 저장소별로 stargazer timestamp를 읽어
1일,7일,30일star 증가량을 계산합니다. - 기간별 hot score를 계산해 각 창의 랭킹을 만듭니다.
- 결과를 Supabase의
repositories,hot_snapshots,hot_snapshot_items에 저장합니다. - 공개 페이지는 최신 또는 날짜별
successhot snapshot을 서버에서 읽어 렌더링합니다.
repositories: GitHub 저장소 기준의 정규화된 메타데이터hot_snapshots: 하루 단위 hot ranking 수집 실행 정보와 상태hot_snapshot_items: 특정 날짜와 기간 창의 순위, 점수, star 증가량
hot_snapshots.status는 running, success, failed 세 값을 사용합니다.
src/
app/
api/cron/trending/route.ts
archive/[date]/page.tsx
page.tsx
components/trending/
lib/
github/
snapshots/
summaries/
supabase/
supabase/
migrations/
tests/
docs/
-
의존성을 설치합니다.
npm install
-
Supabase 프로젝트를 만든 뒤, supabase/migrations/20260329133000_initial_schema.sql의 내용을 SQL Editor에서 실행합니다.
이어서 supabase/migrations/20260405_hot_rankings_schema.sql도 실행합니다.
-
환경 변수 파일을 만듭니다.
cp .env.example .env.local
PowerShell에서는 아래 명령을 사용할 수 있습니다.
Copy-Item .env.example .env.local -
.env.local에 필요한 값을 채웁니다. -
개발 서버를 실행합니다.
npm run dev
-
브라우저에서
http://localhost:3000을 엽니다.
처음 실행하면 성공한 스냅샷이 없어서 빈 상태 화면이 보일 수 있습니다. 이 경우 아래의 수동 크론 호출로 첫 데이터를 적재하면 됩니다.
SUPABASE_URL: Supabase 프로젝트 URLSUPABASE_SERVICE_ROLE_KEY: 서버 전용 읽기/쓰기 키GITHUB_TOKEN: Search API와 stargazer 조회에 사용하는 GitHub 토큰CRON_SECRET: 크론 엔드포인트 보호용 시크릿. 코드상 최소 16자 이상이어야 합니다.
SUPABASE_SERVICE_ROLE_KEY는 서버에서만 사용해야 하며 브라우저로 노출되면 안 됩니다.
npm run devnpm testnpm run lintnpm run buildnpm run start
개발 서버가 켜져 있고 환경 변수가 채워져 있다면 아래처럼 크론 엔드포인트를 직접 호출할 수 있습니다.
curl -H "Authorization: Bearer <CRON_SECRET>" http://localhost:3000/api/cron/trendingPowerShell 예시는 아래와 같습니다.
Invoke-WebRequest -Headers @{ Authorization = "Bearer <CRON_SECRET>" } http://localhost:3000/api/cron/trending성공하면 JSON 응답으로 snapshotId, status, itemCount를 받습니다. 같은 UTC 날짜에 이미 성공한 스냅샷이 있으면 status는 skipped가 될 수 있습니다.
snapshot_date는 서버의 UTC 날짜 문자열로 저장됩니다.captured_at은 실제 수집 시각이며 UI에서는 KST로 포맷해서 보여 줍니다.vercel.json의 스케줄0 0 * * *는00:00 UTC, 한국 시간으로는 오전 9시입니다.
즉, 운영 스케줄에서는 보통 snapshot_date와 한국 날짜가 자연스럽게 맞지만, 로컬에서 임의 시각에 수동 실행하면 UTC 기준 날짜로 저장됩니다.
- 프로덕션에서도 동일한 환경 변수를 설정해야 합니다.
- 배포 설정은 vercel.json에 있으며, 하루 한 번
/api/cron/trending을 호출하도록 되어 있습니다. - 크론 엔드포인트는 인증 헤더가 없으면 401을 반환합니다.
- 공개 페이지는 클라이언트에서 별도 fetch를 하지 않고 서버에서 Supabase를 읽어 렌더링합니다.