18 KiB
18 KiB
INFINITH — Developer Handoff Document
Version: 2.0 | Updated: 2026-04-01 | Status: Phase 1 Backend Complete, Frontend Integration Pending
1. Architecture Overview
[Frontend: React + Vite + TailwindCSS]
│
├── src/lib/supabase.ts (API client)
│
▼
[Supabase Edge Functions (Deno)]
│
├── generate-report ──── Orchestrator (Pipeline Entry)
│ │
│ ├── 1) scrape-website ─── Firecrawl API
│ │ ├── /v1/scrape (구조화 JSON 추출)
│ │ ├── /v1/map (사이트맵 탐색)
│ │ └── /v1/search (리뷰 검색)
│ │
│ ├── 2) analyze-market ─── Perplexity API (sonar)
│ │ ├── 경쟁 병원 분석
│ │ ├── 키워드 트렌드
│ │ ├── 시장 분석
│ │ └── 타겟 오디언스
│ │
│ └── 3) AI 리포트 합성 ─── Perplexity API (sonar)
│
├── enrich-channels ──── Phase 2 (Background Enrichment)
│ ├── Instagram ─── Apify (instagram-profile-scraper)
│ ├── Google Maps ── Apify (crawler-google-places)
│ └── YouTube ───── Apify (youtube-channel-scraper) ⚠️ 수정 필요
│
▼
[Supabase PostgreSQL]
├── scrape_results (스크래핑 캐시)
└── marketing_reports (최종 리포트)
2. Supabase Project
| Item | Value |
|---|---|
| Project Ref | wkvjclkkonoxqtjxiwcw |
| Region | Seoul (ap-northeast-2) |
| Dashboard | https://supabase.com/dashboard/project/wkvjclkkonoxqtjxiwcw |
| API URL | https://wkvjclkkonoxqtjxiwcw.supabase.co |
| Edge Functions | https://wkvjclkkonoxqtjxiwcw.supabase.co/functions/v1/{function-name} |
| CLI | npx supabase (글로벌 설치 불필요) |
| Access Token | infinith-cli (Supabase Dashboard > Account > Access Tokens) |
Database Tables
-- supabase/migrations/20260330_create_tables.sql
scrape_results (
id UUID PRIMARY KEY,
url TEXT NOT NULL,
clinic_name TEXT,
data JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT NOW()
)
marketing_reports (
id UUID PRIMARY KEY,
url TEXT NOT NULL,
clinic_name TEXT,
report JSONB NOT NULL DEFAULT '{}', -- 최종 AI 리포트
scrape_data JSONB DEFAULT '{}', -- 원본 스크래핑 데이터
analysis_data JSONB DEFAULT '{}', -- 시장 분석 데이터
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
)
- RLS 활성화됨.
service_rolekey로 Edge Function 호출 시 전체 접근 가능 anonrole은marketing_reportsSELECT만 가능
Supabase Secrets (Edge Functions 환경변수)
Edge Function에서 Deno.env.get()으로 접근:
# 시크릿 설정 명령어
npx supabase secrets set FIRECRAWL_API_KEY=fc-cdae60d9535d46b086ee0f44a09ab185
npx supabase secrets set PERPLEXITY_API_KEY=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
npx supabase secrets set APIFY_API_TOKEN=apify_api_1ArgFPTjHhDxhyd9UkNVOF3WCABfA21GcXmv
npx supabase secrets set GEMINI_API_KEY=AIzaSyBUnPozy-crOLFwVepcamAnG8WWp2x1KZY
# 자동 제공 (설정 불필요)
# SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, SUPABASE_ANON_KEY
3. Edge Functions — 상세 스펙
3.1 scrape-website
| Item | Detail |
|---|---|
| 파일 | supabase/functions/scrape-website/index.ts |
| 엔드포인트 | POST /functions/v1/scrape-website |
| Auth | --no-verify-jwt (인증 불필요) |
| 외부 API | Firecrawl (api.firecrawl.dev) |
| 소요시간 | ~15-20s |
Request:
{ "url": "https://viewclinic.com", "clinicName": "뷰성형외과" }
Response:
{
"success": true,
"data": {
"clinic": { "clinicName", "address", "phone", "services[]", "doctors[]", "socialMedia{}" },
"siteLinks": ["url1", "url2"],
"siteMap": ["url1", "url2"],
"reviews": [{ "title", "url", "description" }],
"scrapedAt": "ISO timestamp",
"sourceUrl": "https://viewclinic.com"
}
}
처리 흐름:
- Firecrawl
/v1/scrape— 메인 URL에서 병원 정보 구조화 추출 (JSON schema 정의됨) - Firecrawl
/v1/map— 사이트 전체 페이지 URL 수집 (limit: 50) - Firecrawl
/v1/search— "{병원명} 리뷰 평점 후기 강남언니 바비톡" 검색
3.2 analyze-market
| Item | Detail |
|---|---|
| 파일 | supabase/functions/analyze-market/index.ts |
| 엔드포인트 | POST /functions/v1/analyze-market |
| 외부 API | Perplexity (api.perplexity.ai, model: sonar) |
| 소요시간 | ~10-15s (4개 쿼리 병렬) |
Request:
{
"clinicName": "뷰성형외과",
"services": ["코성형", "눈성형", "리프팅"],
"address": "강남구",
"scrapeData": { ... }
}
Response:
{
"success": true,
"data": {
"clinicName": "뷰성형외과",
"services": [...],
"address": "강남구",
"analysis": {
"competitors": { "data": {...}, "citations": [...] },
"keywords": { "data": {...}, "citations": [...] },
"market": { "data": {...}, "citations": [...] },
"targetAudience": { "data": {...}, "citations": [...] }
},
"analyzedAt": "ISO timestamp"
}
}
4개 병렬 Perplexity 쿼리:
competitors— 주변 경쟁 병원 5곳 (이름, 시술, 온라인 평판, 마케팅 채널)keywords— 네이버/구글 검색 키워드 트렌드 20개market— 시장 규모, 성장률, 트렌드 분석targetAudience— 연령/성별/관심사/채널 분석
3.3 generate-report (Orchestrator)
| Item | Detail |
|---|---|
| 파일 | supabase/functions/generate-report/index.ts |
| 엔드포인트 | POST /functions/v1/generate-report |
| 외부 API | 내부적으로 scrape-website + analyze-market + Perplexity 호출 |
| 소요시간 | ~45s (전체 파이프라인) |
Request:
{ "url": "https://viewclinic.com", "clinicName": "뷰성형외과" }
Response:
{
"success": true,
"reportId": "uuid",
"report": {
"clinicInfo": { ... },
"executiveSummary": "경영진 요약",
"overallScore": 72,
"channelAnalysis": {
"naverBlog": { "score", "status", "posts", "recommendation" },
"instagram": { "score", "status", "followers", "recommendation" },
"youtube": { "score", "status", "subscribers", "recommendation" },
"naverPlace": { "score", "rating", "reviews", "recommendation" },
"gangnamUnni": { "score", "rating", "reviews", "recommendation" },
"website": { "score", "issues[]", "recommendation" }
},
"competitors": [{ "name", "strengths[]", "weaknesses[]", "marketingChannels[]" }],
"keywords": {
"primary": [{ "keyword", "monthlySearches", "competition" }],
"longTail": [{ "keyword", "monthlySearches" }]
},
"targetAudience": { "primary": {...}, "secondary": {...} },
"recommendations": [{ "priority", "category", "title", "description", "expectedImpact" }],
"marketTrends": [...]
},
"metadata": {
"url": "...",
"clinicName": "...",
"generatedAt": "ISO timestamp",
"dataSources": { "scraping": true, "marketAnalysis": true, "aiGeneration": true }
}
}
파이프라인 순서:
scrape-website호출 → 병원 데이터 수집analyze-market호출 → 시장 분석- Perplexity
sonar모델로 최종 리포트 JSON 합성 marketing_reports테이블에 저장
3.4 enrich-channels (Phase 2 — Background)
| Item | Detail |
|---|---|
| 파일 | supabase/functions/enrich-channels/index.ts |
| 엔드포인트 | POST /functions/v1/enrich-channels |
| 외부 API | Apify Actors (3개 병렬) |
| 소요시간 | ~27s |
Request:
{
"reportId": "uuid",
"clinicName": "뷰성형외과",
"instagramHandle": "viewplastic",
"youtubeChannelId": "@viewplastic",
"address": "강남구"
}
Apify Actors 사용:
| Actor | Actor ID | 용도 | 검증 |
|---|---|---|---|
| Instagram Profile | apify~instagram-profile-scraper |
팔로워, 게시물, 바이오 | ✅ 정상 작동 (6s) |
| Google Maps | compass~crawler-google-places |
평점, 리뷰, 영업시간 | ✅ 정상 작동 (10s) |
| YouTube Channel | streamers~youtube-channel-scraper |
영상 목록, 조회수 | ⚠️ 빈 데이터 반환 — 다른 Actor 또는 YouTube Data API v3 필요 |
동작: 기존 marketing_reports의 report 필드에 channelEnrichment 객체를 추가 저장
4. Frontend 통합 가이드
현재 상태
| 파일 | 상태 | 설명 |
|---|---|---|
src/lib/supabase.ts |
✅ 완성 | generateMarketingReport(), scrapeWebsite() 함수 |
src/pages/AnalysisLoadingPage.tsx |
✅ 완성 | 실제 API 호출 + 프로그레스 UI |
src/hooks/useReport.ts |
⚠️ Mock 데이터 | mockReport 반환 중 — 실제 API 연동 필요 |
src/pages/ReportPage.tsx (or similar) |
⚠️ 확인 필요 | useReport() 결과 렌더링 |
프론트엔드 환경변수 (.env)
VITE_SUPABASE_URL=https://wkvjclkkonoxqtjxiwcw.supabase.co
VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIs...
API 호출 방식
Edge Functions는 --no-verify-jwt로 배포되어 있어 Authorization 헤더 불필요:
// src/lib/supabase.ts
const response = await fetch(
`${supabaseUrl}/functions/v1/generate-report`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url, clinicName }),
}
);
TODO: useReport() 실제 연동
AnalysisLoadingPage에서 /report/view-clinic으로 navigate할 때 location.state에 report 데이터를 전달 중:
navigate('/report/view-clinic', {
replace: true,
state: { report: result.report, metadata: result.metadata },
});
useReport() 훅에서 이 state를 받아 사용하도록 변경 필요.
TODO: Progressive Loading (Phase 2)
Phase 1 (~45s): generate-report → 즉시 리포트 표시
Phase 2 (~27s): enrich-channels → 백그라운드에서 채널 데이터 보강
→ 완료 시 리포트 UI에 실시간 반영
구현 방식: Phase 1 리포트 렌더 후 enrich-channels 비동기 호출 → Supabase Realtime 또는 polling으로 업데이트 감지
5. API & Service 연결 현황
Connected (연결 완료, 코드 구현됨)
| # | Service | 용도 | API Key 위치 | Dashboard |
|---|---|---|---|---|
| 1 | Firecrawl | 웹사이트 스크래핑 (scrape/map/search) | .env + Supabase Secret |
Dashboard |
| 2 | Perplexity | 시장 분석 + 리포트 생성 (sonar) | .env + Supabase Secret |
API Settings |
| 3 | Apify | Instagram/Google Maps 채널 데이터 | .env + Supabase Secret |
Console |
| 4 | Supabase | DB + Edge Functions + Auth | .env (VITE_*) |
Dashboard |
Connected (MCP로 연결, 코드 미사용)
| # | Service | 용도 | MCP Config |
|---|---|---|---|
| 5 | Gemini (nano-banana-pro) | AI 이미지 생성/편집 | claude_desktop_config.json |
| 6 | Figma MCP | 디자인 에셋 읽기, 브랜드 변수 | VS Code Extension |
| 7 | Slack MCP | 팀 알림, 채널 메시징 | claude_desktop_config.json |
| 8 | Notion MCP | 문서/DB 관리 | VS Code Extension |
| 9 | Google Drive | 파일 저장/공유 | VS Code Extension |
| 10 | Ahrefs | SEO/키워드 분석 (GSC 연동) | VS Code Extension |
| 11 | Claude in Chrome | 브라우저 자동화 | Chrome Extension |
| 12 | Firebase | (미사용, 연결만) | VS Code Extension |
Not Connected (연동 필요)
| # | Service | 용도 | 우선순위 | 문서 |
|---|---|---|---|---|
| 13 | YouTube Data API v3 | 채널 통계, 영상 분석 | P0 | Docs |
| 14 | Naver Search API | 블로그/카페/뉴스 검색 | P0 | Developers |
| 15 | Claude/Anthropic API | AI 리포트 생성 (Perplexity 대체 가능) | P1 | Docs |
| 16 | Creatomate | 템플릿 기반 영상/이미지 생성 | P1 | API Docs |
| 17 | Instagram Graph API | 공식 게시/인사이트 | P1 | Docs |
| 18 | Google Search Console | SEO 성과 추적 | P1 | Docs |
| 19 | Google Analytics 4 | 웹 트래픽 분석 | P1 | Docs |
| 20 | Naver Place/Map API | 플레이스 리뷰/위치 | P2 | Naver Cloud |
| 21 | Google Maps Places API | 구글 리뷰/평점 (Apify 대체중) | P2 | Docs |
| 22 | TikTok API | 숏폼 게시/분석 | P2 | Docs |
| 23 | Canva Connect API | 템플릿 Autofill (Enterprise) | P2 | Docs |
| 24 | Brandfetch | 브랜드 로고/컬러 추출 | P2 | Docs |
6. 측정된 파이프라인 타이밍
Phase 1: generate-report 전체 (~45초)
├── scrape-website ~15-20s
├── analyze-market ~10-15s (4 Perplexity 병렬)
└── AI report 합성 ~10-15s
Phase 2: enrich-channels (~27초, 백그라운드)
├── Instagram (Apify) ~6s
├── Google Maps (Apify) ~10s
└── YouTube (Apify) ~11s (⚠️ 빈 데이터)
Total: ~72초 (사용자 체감: 45초 → 리포트 표시)
7. 알려진 이슈 & 해결 필요
| # | 이슈 | 상세 | 해결 방향 |
|---|---|---|---|
| 1 | Gemini API 429 | 프로젝트 spending cap $10 초과. generate-report에서 Perplexity로 대체 완료 |
AI Studio에서 한도 증가 또는 Perplexity 유지 |
| 2 | YouTube Apify 빈 데이터 | streamers~youtube-channel-scraper Actor가 빈 배열 반환 |
YouTube Data API v3 연동 또는 다른 Apify Actor 탐색 |
| 3 | useReport() Mock | useReport() 훅이 mockReport 반환 중 |
location.state에서 실제 데이터 읽도록 변경 |
| 4 | JWT 미검증 | Edge Functions가 --no-verify-jwt로 배포 |
프로덕션 전에 Supabase Auth 연동 + JWT 검증 활성화 |
| 5 | Instagram 핸들 자동 감지 | scrape-website에서 추출한 socialMedia.instagram을 enrich-channels에 자동 전달 필요 |
generate-report orchestrator에서 연결 |
8. 프로젝트 구조
remix_-infinith---infinite-marketing/
├── src/
│ ├── components/
│ │ ├── Hero.tsx # 랜딩 히어로 (URL 입력)
│ │ ├── icons/ # 커스텀 아이콘
│ │ └── ...
│ ├── hooks/
│ │ └── useReport.ts # ⚠️ Mock 데이터 → 실제 연동 필요
│ ├── lib/
│ │ └── supabase.ts # ✅ Supabase 클라이언트 + API 함수
│ ├── pages/
│ │ ├── AnalysisLoadingPage.tsx # ✅ 분석 로딩 (실제 API 호출)
│ │ └── ...
│ └── ...
├── supabase/
│ ├── functions/
│ │ ├── scrape-website/ # ✅ Firecrawl 스크래핑
│ │ ├── analyze-market/ # ✅ Perplexity 시장 분석
│ │ ├── generate-report/ # ✅ 파이프라인 오케스트레이터
│ │ └── enrich-channels/ # ✅ Apify 채널 enrichment
│ └── migrations/
│ └── 20260330_create_tables.sql # DB 스키마
├── docs/
│ ├── API_CONNECTORS.md # API 레지스트리 (v1.0)
│ ├── DESIGN_SYSTEM.md # 디자인 시스템
│ └── DEVELOPER_HANDOFF.md # 이 문서
├── .env # 환경변수 (Git 제외)
└── package.json
9. Edge Functions 배포 가이드
# 1. Supabase CLI 로그인
npx supabase login
# 2. 프로젝트 연결
npx supabase link --project-ref wkvjclkkonoxqtjxiwcw
# 3. Secrets 설정 (최초 1회)
npx supabase secrets set FIRECRAWL_API_KEY=fc-cdae60d9535d46b086ee0f44a09ab185
npx supabase secrets set PERPLEXITY_API_KEY=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
npx supabase secrets set APIFY_API_TOKEN=apify_api_1ArgFPTjHhDxhyd9UkNVOF3WCABfA21GcXmv
# 4. 개별 함수 배포
npx supabase functions deploy scrape-website --no-verify-jwt
npx supabase functions deploy analyze-market --no-verify-jwt
npx supabase functions deploy generate-report --no-verify-jwt
npx supabase functions deploy enrich-channels --no-verify-jwt
# 5. DB 마이그레이션
npx supabase db push
# 6. 로컬 테스트
npx supabase functions serve --env-file .env
10. 개발 우선순위 로드맵
Phase 1 — 즉시 (Frontend ↔ Backend 연결)
useReport()훅을 실제 API 데이터로 교체generate-report호출 후enrich-channels자동 호출 연결- 리포트 페이지에서
channelEnrichment데이터 렌더링 - YouTube Data API v3 연동 (Apify 대체)
- 에러 핸들링 강화 (재시도, timeout, 사용자 피드백)
Phase 2 — Content Studio
- Naver Search API 연동 (블로그/카페 검색)
- 콘텐츠 캘린더 생성 로직 (리포트 기반)
- Creatomate API 연동 (이미지/영상 생성)
- Gemini 이미지 생성 연동 (nano-banana-pro MCP)
Phase 3 — 자동화 & 배포
- Instagram Graph API (자동 게시)
- Supabase Auth 연동 (사용자 인증)
- Edge Function JWT 검증 활성화
- Google Analytics / Search Console 연동
- 자동 리포트 스케줄링
11. 테스트 데이터
검증에 사용한 실제 병원:
| 병원 | URL | 비고 | |
|---|---|---|---|
| 뷰성형외과 | https://viewclinic.com |
viewplastic (14,094 followers) |
전체 파이프라인 테스트 완료 |
Last updated: 2026-04-01