Status: Draft
Created: 2025-01-04
Author: Trey Team
현재 시스템은 10개의 고정된 라이브러리만 수동으로 관리하고 있습니다. 이를 확장하여:
- 새로운 오픈소스 라이브러리를 자동으로 발견
- 지표/랭킹을 동적으로 업데이트
- 상세페이지 콘텐츠를 자동 생성
- Playground 예제 코드를 자동 생성
하는 시스템을 구축합니다.
| 목표 | 설명 | 우선순위 |
|---|---|---|
| 자동 발견 | GitHub Trending, npm 인기 패키지에서 새 라이브러리 발견 | P0 |
| 지표 확장 | Bundle Size, Security Score 등 추가 지표 수집 | P1 |
| 콘텐츠 생성 | AI를 활용한 요약, 장단점, 사용 사례 자동 생성 | P1 |
| Playground 생성 | AI를 활용한 실행 가능한 예제 코드 자동 생성 | P2 |
새로운 라이브러리를 발견하기 위한 데이터 소스:
| 소스 | API | 가능한 데이터 | 비용 |
|---|---|---|---|
| GitHub Trending | 비공식 크롤링 또는 github-trending-api | 일간/주간/월간 트렌딩 | 무료 |
| npm Registry | registry.npmjs.org |
인기 패키지, 다운로드 수 | 무료 |
| Libraries.io | 공식 API | 의존성 분석, 인기도 점수 | 무료 티어 |
| GitHub Search | REST API | stars 조건 검색 | 무료 (rate limit) |
// lib/discovery/github-trending.ts
interface TrendingRepo {
name: string;
fullName: string;
description: string;
stars: number;
language: string;
url: string;
}
export async function discoverFromGitHubTrending(
language: string = 'typescript',
period: 'daily' | 'weekly' | 'monthly' = 'weekly'
): Promise<TrendingRepo[]> {
// GitHub Trending API (비공식)
const response = await fetch(
`https://api.gitterapp.com/repositories?language=${language}&since=${period}`
);
return response.json();
}
// 또는 GitHub Search API 사용
export async function discoverFromGitHubSearch(
topic: string,
minStars: number = 5000
): Promise<TrendingRepo[]> {
const response = await fetch(
`https://api.github.com/search/repositories?q=topic:${topic}+stars:>${minStars}&sort=stars&order=desc`,
{
headers: {
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
},
}
);
const data = await response.json();
return data.items;
}새로 추가할 라이브러리 선정 기준:
- ⭐ GitHub Stars > 5,000
- 📥 npm Weekly Downloads > 100,000
- 🔄 최근 6개월 내 커밋 활동 있음
- 📝 README.md 존재
- 🏷️ 관련 토픽 태그 (react, typescript, ui 등)
-- 발견된 라이브러리 후보 테이블
CREATE TABLE library_candidates (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
github_url TEXT NOT NULL UNIQUE,
npm_package TEXT,
name TEXT NOT NULL,
description TEXT,
stars INTEGER,
downloads INTEGER,
discovered_at TIMESTAMPTZ DEFAULT NOW(),
status TEXT DEFAULT 'pending', -- pending, approved, rejected
reviewed_at TIMESTAMPTZ,
rejection_reason TEXT
);현재 수집 중인 지표 + 추가 지표:
| 지표 | 소스 | 현재 상태 | 구현 방법 |
|---|---|---|---|
| ⭐ GitHub Stars | GitHub API | ✅ 구현됨 | - |
| 📥 npm Downloads | npm API | ✅ 구현됨 | - |
| 🕐 Last Commit | GitHub API | ✅ 구현됨 | - |
| 📦 Bundle Size | Bundlephobia API | ⏳ 추가 예정 | REST API |
| 🔒 Security Score | Snyk API / Socket.dev | ⏳ 추가 예정 | REST API |
| 📈 Growth Rate | 자체 계산 | ⏳ 추가 예정 | 이전 주 대비 증가율 |
| 🏆 종합 랭킹 | 복합 점수 | ⏳ 추가 예정 | 가중치 기반 점수 |
| 🏢 Used By | GitHub Dependents | ✅ 구현됨 (수동) | 자동화 필요 |
// lib/external/bundlephobia.ts
interface BundleSize {
size: number; // bytes
gzip: number; // gzip bytes
dependencyCount: number;
}
export async function getBundleSize(packageName: string): Promise<BundleSize> {
const response = await fetch(
`https://bundlephobia.com/api/size?package=${packageName}`
);
return response.json();
}// lib/utils/ranking.ts
interface RankingFactors {
stars: number;
downloads: number;
lastCommitDays: number;
bundleSizeKb: number;
securityScore: number; // 0-100
}
export function calculateRankingScore(factors: RankingFactors): number {
const weights = {
stars: 0.25,
downloads: 0.25,
activity: 0.20,
bundleSize: 0.15,
security: 0.15,
};
// 정규화 후 가중치 적용
const normalizedStars = Math.min(factors.stars / 50000, 1);
const normalizedDownloads = Math.min(factors.downloads / 10000000, 1);
const activityScore = Math.max(0, 1 - factors.lastCommitDays / 365);
const bundleScore = Math.max(0, 1 - factors.bundleSizeKb / 500);
const securityScore = factors.securityScore / 100;
return (
normalizedStars * weights.stars +
normalizedDownloads * weights.downloads +
activityScore * weights.activity +
bundleScore * weights.bundleSize +
securityScore * weights.security
) * 100;
}상세페이지에 필요한 콘텐츠:
| 콘텐츠 | 일반 코딩 | AI 필요 | 설명 |
|---|---|---|---|
| 기본 정보 | ✅ | GitHub/npm API에서 추출 | |
| README 파싱 | ✅ | Markdown 파싱 | |
| 설치 명령어 | ✅ | package.json에서 추출 | |
| 요약 설명 | ✅ | 한 문장으로 라이브러리 설명 | |
| 장단점 비교 | ✅ | 경쟁 라이브러리 대비 분석 | |
| 사용 사례 | ✅ | 언제 이 라이브러리를 쓰면 좋은지 | |
| 카테고리 분류 | ✅ | UI, State, Form 등 자동 분류 |
// lib/ai/content-generator.ts
import OpenAI from 'openai';
const openai = new OpenAI();
interface LibraryContent {
summary: string;
pros: string[];
cons: string[];
useCases: string[];
category: string;
tags: string[];
}
export async function generateLibraryContent(
readme: string,
packageJson: object
): Promise<LibraryContent> {
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{
role: 'system',
content: `당신은 프론트엔드 라이브러리 분석 전문가입니다.
주어진 README와 package.json을 분석하여 다음 정보를 JSON 형식으로 제공하세요:
1. summary: 한 문장으로 라이브러리 설명 (한국어)
2. pros: 장점 3-5개 (한국어)
3. cons: 단점 또는 주의사항 2-3개 (한국어)
4. useCases: 사용하기 좋은 상황 3개 (한국어)
5. category: UI | State | Form | Animation | Data | Utility 중 하나
6. tags: 관련 키워드 5개 (영어)
JSON만 반환하세요.`,
},
{
role: 'user',
content: `README:\n${readme.slice(0, 8000)}\n\npackage.json:\n${JSON.stringify(packageJson, null, 2)}`,
},
],
response_format: { type: 'json_object' },
temperature: 0.3,
});
return JSON.parse(response.choices[0].message.content!);
}- 캐싱: 생성된 콘텐츠는 DB에 저장, 변경 감지 시만 재생성
- 배치 처리: 하루 한 번 변경된 라이브러리만 처리
- 모델 선택: 단순 분류는 GPT-4o-mini, 복잡한 분석은 GPT-4o
// 변경 감지 로직
async function shouldRegenerateContent(libraryId: string): Promise<boolean> {
const library = await getLibrary(libraryId);
const lastGenerated = library.content_generated_at;
const lastCommit = new Date(library.trust_metrics.last_commit);
// 마지막 생성 이후 커밋이 있으면 재생성
return lastCommit > lastGenerated;
}Sandpack에서 실행 가능한 예제 코드 자동 생성:
// lib/ai/playground-generator.ts
interface PlaygroundCode {
files: {
[filename: string]: string;
};
dependencies: {
[packageName: string]: string;
};
}
export async function generatePlaygroundCode(
libraryName: string,
readme: string,
officialDocs?: string
): Promise<PlaygroundCode> {
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{
role: 'system',
content: `당신은 React 코드 예제 전문가입니다.
주어진 라이브러리의 기본 사용 예제를 Sandpack에서 실행 가능한 형태로 작성하세요.
규칙:
1. App.tsx 파일 하나에 모든 코드 포함
2. 필요한 import 문 포함
3. export default function App() 형식
4. 실제로 동작하는 코드만 작성
5. 한국어 주석으로 설명 추가
6. 가장 대표적인 기능 1-2개만 시연
JSON 형식으로 반환:
{
"files": {
"/App.tsx": "코드 내용"
},
"dependencies": {
"패키지명": "버전"
}
}`,
},
{
role: 'user',
content: `라이브러리: ${libraryName}\n\nREADME:\n${readme.slice(0, 6000)}${officialDocs ? `\n\n공식 문서:\n${officialDocs.slice(0, 4000)}` : ''}`,
},
],
response_format: { type: 'json_object' },
temperature: 0.2,
});
return JSON.parse(response.choices[0].message.content!);
}생성된 코드의 품질 보장:
// lib/ai/code-validator.ts
export async function validatePlaygroundCode(
code: PlaygroundCode
): Promise<{ valid: boolean; errors: string[] }> {
// 1. TypeScript 컴파일 체크
const tsErrors = await checkTypeScript(code.files['/App.tsx']);
// 2. 필수 요소 체크
const hasDefaultExport = code.files['/App.tsx'].includes('export default');
const hasImports = code.files['/App.tsx'].includes('import');
// 3. 의존성 존재 여부 체크
const depsValid = await checkDependencies(code.dependencies);
return {
valid: tsErrors.length === 0 && hasDefaultExport && hasImports && depsValid,
errors: tsErrors,
};
}┌─────────────────────────────────────────────────────────────┐
│ Daily Cron Job (GitHub Actions) │
│ 매일 KST 07:00 실행 │
└─────────────────────────────────────────────────────────────┘
│
┌────────────────────┼────────────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Discovery │ │ Metrics │ │ Content Gen │
│ (일반 코딩) │ │ (일반 코딩) │ │ (AI + 코딩) │
├─────────────────┤ ├─────────────────┤ ├─────────────────┤
│ • GitHub Search │ │ • GitHub API │ │ • OpenAI API │
│ • npm Registry │ │ • npm API │ │ • README 파싱 │
│ • Trending API │ │ • Bundlephobia │ │ • 예제 코드 생성 │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
└────────────────────┼────────────────────┘
▼
┌─────────────────┐
│ Supabase │
│ Database │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Static Build │
│ (Next.js) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Netlify │
└─────────────────┘
| 서비스 | 무료 티어 | 예상 사용량 | 예상 비용 |
|---|---|---|---|
| GitHub API | 5,000 req/hr | ~3,000/월 | 무료 |
| npm API | 무제한 | ~3,000/월 | 무료 |
| Bundlephobia | 무제한 | ~100/월 | 무료 |
| OpenAI GPT-4o | - | ~50만 토큰/월 | $10-20 |
| OpenAI GPT-4o-mini | - | ~100만 토큰/월 | $1-2 |
| Supabase | 50K rows, 500MB | 충분 | 무료 |
| Netlify | 300 빌드/월 | ~30/월 | 무료 |
예상 총 비용: $10-25/월
- 변경 감지 기반 재생성: 전체가 아닌 변경된 것만 처리
- 모델 티어링: 단순 작업은 mini 모델 사용
- 캐싱: 생성된 콘텐츠 DB 저장
- GitHub Search API 연동
- npm Registry API 연동
- library_candidates 테이블 생성
- 발견 스크립트 작성
- 수동 승인 워크플로우
- Bundlephobia API 연동
- 랭킹 점수 계산 로직
- trust_metrics 스키마 확장
- 대시보드 UI 업데이트
- OpenAI API 연동
- 콘텐츠 생성 프롬프트 개발
- 콘텐츠 캐싱 로직
- 상세페이지 UI 업데이트
- Playground 코드 생성 프롬프트 개발
- 코드 검증 로직
- Sandpack 연동 테스트
- 실패 시 폴백 처리