o2o-infinith-demo/docs/DEVELOPER_HANDOFF.md

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_role key로 Edge Function 호출 시 전체 접근 가능
  • anon role은 marketing_reports SELECT만 가능

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"
  }
}

처리 흐름:

  1. Firecrawl /v1/scrape — 메인 URL에서 병원 정보 구조화 추출 (JSON schema 정의됨)
  2. Firecrawl /v1/map — 사이트 전체 페이지 URL 수집 (limit: 50)
  3. 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 쿼리:

  1. competitors — 주변 경쟁 병원 5곳 (이름, 시술, 온라인 평판, 마케팅 채널)
  2. keywords — 네이버/구글 검색 키워드 트렌드 20개
  3. market — 시장 규모, 성장률, 트렌드 분석
  4. 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 }
  }
}

파이프라인 순서:

  1. scrape-website 호출 → 병원 데이터 수집
  2. analyze-market 호출 → 시장 분석
  3. Perplexity sonar 모델로 최종 리포트 JSON 합성
  4. 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_reportsreport 필드에 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 Instagram 비고
뷰성형외과 https://viewclinic.com viewplastic (14,094 followers) 전체 파이프라인 테스트 완료

Last updated: 2026-04-01