Commit Graph

60 Commits (3f1a25e2983fd54bbaa089968f69e615d30c06e2)

Author SHA1 Message Date
Haewon Kam 3f1a25e298 docs: add Sprint 0 Vision Analysis to pipeline improvement plan
Vision analysis addresses the critical gap that text-only scraping
misses ~40% of clinic website information (founding year in banners,
doctor photos, certification marks, social icons in images).

Sprint 0 adds: Firecrawl screenshot → Gemini Vision → structured
data extraction for founding year, doctors, certifications, services,
social icons, floating buttons, brand colors, slogans.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:46:56 +09:00
Haewon Kam ed37f23f78 feat: extract social links from JS-rendered buttons on clinic website
Added A4 parallel Firecrawl call with actions: [wait 3s, scrape]
to execute JavaScript and extract social button href URLs from
header/footer. This is the most reliable source — most Korean
clinics have Facebook/Instagram/YouTube/Blog icons in their nav.

Results merged as Source 3 (buttonHandles) alongside HTML links,
JSON extraction, and API searches.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:41:27 +09:00
Haewon Kam 80c57147e7 feat: Sprint 1 — 7 data quality quick wins
WP-1: YouTube channel ID regex {20,} → {22} (exactly 24 chars)
WP-2: Naver Place category filtering in enrich-channels (성형/피부)
WP-3: Google Maps stores mapsUrl separately from clinicWebsite
WP-4: Naver Blog separates officialBlogUrl from search results
WP-5: 강남언니 rawRating + normalized rating (≤5 → ×2), Firecrawl
      prompt explicitly states "out of 10, NOT out of 5"
WP-6: Perplexity model centralized in _shared/config.ts (env override)
WP-7: Apify Instagram timeout 30s → 45s

Frontend: transformReport uses mapsUrl and officialBlogUrl when available

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:35:40 +09:00
Haewon Kam 1071328574 docs: pipeline improvement plan with 15 work packages and verification checklist
Comprehensive audit of discover→collect→generate pipeline found:
- 16 silent failures, 8 data quality issues, 0 error recovery, 6 API issues
- Organized into 4 sprints (15 WPs, ~11h total)
- Each WP has file locations, changes, and verification criteria
- Checkbox format for progress tracking

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 23:26:22 +09:00
Haewon Kam 29c1faf49e fix: correct OtherChannels URLs — Google Maps, Naver Blog, Naver Place
Google Maps: was using gm.website (clinic's own site) → now always
generates maps.google.com/search URL

Naver Blog: was linking to first search result post (random personal
blog) → now links to Naver blog search results page

Naver Place: np.link was the clinic's own website, not Naver Place →
now generates map.naver.com search URL. Also fixed collect-channel-data
to search with "성형외과" suffix and match by category (성형/피부) to
avoid same-name dental clinics.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 21:25:26 +09:00
Haewon Kam a02c83155e fix: remove duplicate Facebook link at bottom — now only on page name
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 16:28:46 +09:00
Haewon Kam 4928d24ace feat: consistent ExternalLink on all channel names — Facebook + OtherChannels
Facebook pageName now links to facebook.com/{url} with ExternalLink icon.
OtherChannels: moved ExternalLink from right-end to inline with channel
name, matching the Instagram/YouTube pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 16:23:29 +09:00
Haewon Kam 2a35108149 fix: '의료진 3명' → '전문의 3명' — staffCount는 강남언니 등록 의사 수
staffCount is the number of registered doctors from 강남언니, not total
staff. Label changed from 의료진(medical staff) to 전문의(specialists)
to accurately reflect the data source. Diagnosis message also updated.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 16:21:10 +09:00
Haewon Kam 66b4826f55 feat: add clickable source links to all report sections
YouTubeAudit: handle links to youtube.com/@{handle} with ExternalLink icon
InstagramAudit: handle links to instagram.com/{handle} with ExternalLink icon
ClinicSnapshot: domain is now clickable link, phone is tel: link
OtherChannels: Google Maps generates search URL, Naver Blog links to
  first blog post or search results (previously empty string)
transformReport: fills missing URL fields for Google Maps and Naver Blog

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 11:02:35 +09:00
Haewon Kam bb7b08e35c docs: comprehensive AI prompts catalog v2 — all pipeline prompts with engineering learnings
Includes every prompt in production across 3 pipeline phases:
- Phase 1 (discover): 7 data sources with exact prompts
- Phase 2 (collect): 5 API calls + 4 market analysis queries
- Phase 3 (generate): full report generation prompt template

Added prompt engineering learnings:
- Short prompts outperform long ones on Perplexity sonar
- sonar > sonar-pro for channel search
- English clinic name in parentheses improves international results
- Verify strategy: keep unverified handles as candidates

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 10:01:23 +09:00
Haewon Kam 1fb1de8303 fix: keep unverified Instagram handles as candidates for collection
Instagram HEAD requests often fail (rate limiting, blocking) causing
valid handles to be dropped. Now all discovered handles are kept
(verified or not) and Apify attempts collection on all of them.
Apify's own scraper validates existence more reliably than HEAD requests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 01:38:12 +09:00
Haewon Kam 087f65eec1 fix: revert to single Perplexity query with proven prompt pattern
Split queries performed worse. The proven working pattern is:
- Single query with Korean+English clinic name
- "검색해서 찾아줘. 검색 결과에서 발견된 계정을 모두 알려줘" phrasing
- All channels in one request
- English name in parentheses helps Perplexity find international accounts

Tested: "그랜드성형외과 (Grand Plastic Surgery)" → finds Instagram,
YouTube, Facebook, TikTok, Naver Blog all in one call.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 01:36:36 +09:00
Haewon Kam 5157cf446a fix: split Perplexity into 3 focused queries matching research methodology
Single mega-query returns empty results. Split into:
B4a. Instagram + YouTube (most important, focused search)
B4b. Facebook + TikTok + Naver Blog + Kakao
B4c. 강남언니 + review platforms

Each query is short and focused — matches the proven pattern of
2-5 keyword searches that Perplexity handles well.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 01:34:45 +09:00
Haewon Kam ac2da7a4ac fix: simplify Perplexity prompt — short system + direct user query
Long system prompt caused sonar-pro to return empty results.
Reverted to sonar model with short, proven prompt pattern that
matches the user's successful manual test.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 01:32:54 +09:00
Haewon Kam e64d168d34 feat: Perplexity sonar-pro research agent with structured online presence analysis
Replaced simple "find handles" prompt with comprehensive research agent:
- Model: sonar → sonar-pro (advanced multi-step web search)
- System prompt: full research methodology with 2-3 keyword searches,
  URL fetching, quantitative data extraction
- Output: structured JSON with channels (handles + follower counts +
  subscriber counts) + platforms (강남언니 rating, reviews)
- Research results saved to scrape_data.onlinePresenceResearch for
  downstream use in collect-channel-data and generate-report

Added _shared/researchPrompt.ts with prompt template + builder.
Updated agent documentation in doc/.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 01:31:00 +09:00
Haewon Kam c74832d764 feat: Perplexity Online Presence 종합 분석 + Apify Instagram 검색
B4 Perplexity: rewrote from narrow "find social accounts" to broad
"Online Presence 종합 분석" — finds Instagram, YouTube, Facebook,
TikTok, Naver, Kakao, 강남언니, 바비톡 in one query.

B5 Apify Instagram: generates handle candidates from clinic name
(english name, domain, _official, _ps, _clinic variants) and directly
checks each via Apify instagram-profile-scraper. Finds accounts that
web search misses.

Removed redundant B4b (platform presence) — now merged into B4.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 01:24:56 +09:00
Haewon Kam 64669888c2 fix: type-safe string handling in extractSocialLinks/mergeSocialLinks
API results may contain null, numbers, or objects instead of strings.
Now coerces all values to strings before processing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 01:17:49 +09:00
Haewon Kam f224d1788c feat: API-first channel discovery — YouTube API + Naver API + Firecrawl Search + Perplexity
Replaced Perplexity-only approach with 5 parallel direct API searches:

B1. YouTube Data API: search?type=channel&q={clinicName} → find channel
B2a. Naver Blog API: search blog.json → find official Naver blog
B2b. Naver Web API: search webkr.json → find Instagram/YouTube/Facebook URLs
B3. Firecrawl Search: web search → extract social URLs from results
B4. Perplexity: supplement — catch what direct APIs missed

All 5 sources run in parallel after Stage A (Firecrawl scrape for clinicName).
Results merged + deduplicated + verified. Perplexity is now a fallback,
not the primary source.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 01:15:49 +09:00
Haewon Kam 159de36e38 docs: add AI prompts catalog for all pipeline functions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 01:09:33 +09:00
Haewon Kam 25aece2366 fix: Perplexity prompt rewrite + clinicName fallback via AI
Perplexity prompts changed from "find verified accounts" (returns all
null) to "search and report what you find" (returns actual handles).
Added clinicName resolution: Firecrawl Korean → English → Perplexity
URL-to-name lookup → domain fallback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 01:07:04 +09:00
Haewon Kam 122b1915f0 fix: 2-stage discovery — Firecrawl first for clinicName, then Perplexity
Previously Firecrawl and Perplexity ran in parallel, so Perplexity
received raw URL instead of clinic name → poor search results.

Now:
Stage A: Firecrawl scrape+map (parallel) → extract clinicName from HTML
Stage B: Perplexity searches using extracted clinicName → finds Instagram,
  YouTube, Facebook handles that Firecrawl HTML parsing missed
Stage C: Merge 3 sources + verify all handles

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 01:02:30 +09:00
Haewon Kam df8f84c3b9 fix: YouTube channel ID (UC...) handling + handle-to-channelId resolution
discover-channels: extractHandle('youtube') now detects UC* channel IDs
and returns them without @ prefix (previously @UC... caused verify fail)

verifyHandles: verifyYouTube uses cleanHandle for UC* check, requests
part=id,snippet for richer data

collect-channel-data: if channelId missing but handle present, resolves
via forHandle/forUsername lookup or direct UC* detection before skipping

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 01:00:21 +09:00
Haewon Kam 163751410f fix: reduce blob animation range + force GPU with translate3d
Halved blob movement (30px→15px, 8vw→4vw) and reduced scale
(1.1→1.05). Using translate3d forces GPU compositing layer,
preventing main-thread layout recalculation that causes jitter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:48:42 +09:00
Haewon Kam c07f839773 fix: GPU-accelerate blob animations to prevent layout jitter
Added will-change:transform, contain:layout style, and
backface-visibility:hidden to all blob animations. This promotes
blobs to their own GPU compositing layer, preventing them from
triggering main-thread reflow/repaint that causes page shaking.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:46:26 +09:00
Haewon Kam eb058ab2e5 fix: add overflow-x:hidden to html to stop blob-caused layout shaking
Animated blobs with translate+scale overflow their containers,
causing horizontal scrollbar to flicker and page to jitter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:40:47 +09:00
Haewon Kam 9a141f3603 fix: thin overlay scrollbar to equalize left/right margins
Uses scrollbar-width:thin + 6px webkit scrollbar to minimize
layout shift from the default ~15px scrollbar. Keeps original
design intact while reducing visual asymmetry.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:15:00 +09:00
Haewon Kam c6b39e3706 revert: restore Hero, Modules, CSS to exact original version (922ec8f)
Reverts to the original design with full-color button (no disabled
opacity), original background gradients, and original blob decorations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:07:18 +09:00
Haewon Kam 46b911d4c0 fix: remove opacity-50 from Analyze button — always show full color
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:05:50 +09:00
Haewon Kam f65f0e85b3 fix: robust handle extraction — reject non-platform URLs, fix type safety
discover-channels: new extractHandle() validates each handle belongs to
its platform (rejects hospital-internal URLs like /idtube/view being
treated as YouTube). Extracts handles from full URLs correctly.

collect-channel-data: explicit Record<string,unknown> typing for DB JSON
fields — fixes TypeScript property access on VerifiedChannels from DB.

verifyHandles: fix TikTok double-URL concatenation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:03:26 +09:00
Haewon Kam 0d72750982 revert: restore Hero, Modules, CSS to original state
All layout changes (blob modifications, overflow-x/clip, scrollbar-gutter)
reverted to the original version that was working correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:56:58 +09:00
Haewon Kam 81d673a3e8 fix: use overflow-y:overlay so scrollbar doesn't shift layout
Removes scrollbar-gutter:stable which pushed content left.
overlay scrollbar floats over content with zero layout impact.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:54:32 +09:00
Haewon Kam ef5d9fed0f fix: scrollbar-gutter:stable to balance left/right margins
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:53:01 +09:00
Haewon Kam 0f517473e0 fix: remove asymmetric blobs from Hero, use centered gradient
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:48:15 +09:00
Haewon Kam 7154e76bc4 fix: balance Hero blob sizes and opacity for symmetric layout
Reduced blob size (w-64→w-48), lowered opacity (30%→20%), used
percentage positioning (left-10→left-[10%]), and wrapped in
overflow-clip container. Eliminates visual weight asymmetry.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:45:28 +09:00
Haewon Kam 2b7494305a fix: contain all overflowing blobs within viewport
- Modules.tsx: wrap blobs in overflow-clip container, use max-w instead
  of min-w to prevent viewport overflow
- index.css: add #root { overflow-x:clip; max-width:100vw } as final
  safety net — no child element can expand beyond viewport

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:42:35 +09:00
Haewon Kam 71c56783ed fix: use overflow-x:clip instead of hidden to fully contain blur blobs
overflow-x:hidden doesn't clip CSS blur() filter radius, allowing
blurred blobs to still cause horizontal scrollbar. overflow-x:clip
fully contains all rendered pixels including blur.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:38:38 +09:00
Haewon Kam a6bb31a093 fix: restore English loading steps, hide channel panel, fix blank report page
- Loading steps back to English (Scanning website, Collecting data, etc.)
- Removed verified channels panel from loading screen
- Fixed blank report page: detect empty report JSON from DB and show
  appropriate error message instead of rendering empty components
- Navigation state: only pass if report+metadata exist

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:35:06 +09:00
Haewon Kam caac2f22c5 fix: prevent horizontal overflow causing right-shifted layout
Animated blur blobs and absolute-positioned elements were overflowing
the viewport, creating a horizontal scrollbar that shifted all content.
Added overflow-x: hidden to html and body.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:30:27 +09:00
Haewon Kam 9d06272073 fix: KPI uses real enrichment data instead of AI guesses
buildKpiDashboard now reads channelEnrichment (real API data from
Phase 2) with fallback to channelAnalysis (AI-generated). YouTube
subscribers, Instagram followers, 강남언니 rating/reviews all use
verified data when available. Fixed || ?? operator precedence.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 22:28:11 +09:00
Haewon Kam ff82c9f9d5 fix: KPI dashboard always generates comprehensive 10+ metrics
Previously AI-provided kpiTargets (often only 3-4 items) would
completely replace our channel-based KPI generation. Now we always
build the full set (YouTube, Instagram, Naver, 강남언니, Google Maps,
cross-platform) and merge AI extras that don't overlap.

Also adds 강남언니 평점/리뷰, 네이버 플레이스 평점 as standard KPIs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 22:22:40 +09:00
Haewon Kam 5239ad7382 chore: add deno.json for new Edge Functions
Required by Supabase deploy to resolve @supabase/functions-js import.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 22:04:13 +09:00
Haewon Kam 7557ef774c feat: Pipeline V2 — 3-phase analysis with verified channel discovery
Restructured the entire analysis pipeline from AI-guessing social
handles to deterministic 3-phase discovery + collection + generation.

Phase 1 (discover-channels): 3-source channel discovery
  - Firecrawl scrape: extract social links from HTML
  - Perplexity search: find handles via web search
  - URL regex parsing: deterministic link extraction
  - Handle verification: HEAD requests + YouTube API
  - DB: creates row with verified_channels + scrape_data

Phase 2 (collect-channel-data): 9 parallel data collectors
  - Instagram (Apify), YouTube (Data API v3), Facebook (Apify)
  - 강남언니 (Firecrawl), Naver Blog + Place (Naver API)
  - Google Maps (Apify), Market analysis (Perplexity 4x parallel)
  - DB: stores ALL raw data in channel_data column

Phase 3 (generate-report): AI report from real data
  - Reads channel_data + analysis_data from DB
  - Builds channel summary with real metrics
  - AI generates report using only verified data
  - V1 backwards compatibility preserved (url-based flow)

Supporting changes:
  - DB migration: status, verified_channels, channel_data columns
  - _shared/extractSocialLinks.ts: regex-based social link parser
  - _shared/verifyHandles.ts: multi-platform handle verifier
  - AnalysisLoadingPage: real 3-phase progress + channel panel
  - useReport: channel_data column support + V2 enrichment merge
  - 강남언니 rating: auto-correct 5→10 scale + search fallback
  - KPIDashboard: navigate() instead of <a href>
  - Loading text: 20-30초 → 1-2분

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 21:49:13 +09:00
Haewon Kam da267fd744 feat: Content Director engine + report diagnosis/roadmap/KPI overhaul + PDF export fix
- Content Director (contentDirector.ts): deterministic 4-week editorial
  calendar engine — pillar-service matrix, channel-format slots, weekly
  themes (브랜드 정비 → 콘텐츠 엔진 → 소셜 증거 → 전환 최적화)
- transformPlan.ts: buildCalendar() delegates to Content Director with
  enrichment data (YouTube videos for repurposing)
- transformReport.ts: buildTransformation() generates rich per-channel
  platform strategies; buildRoadmap() creates Foundation/Content Engine/
  Optimization 3-phase plan; buildKpiDashboard() generates 10+ channel-
  specific metrics with targets
- ProblemDiagnosis: clustered 3 core issues (brand/content/funnel) in
  glass cards + expandable detail list
- RoadmapTimeline: Foundation/Content Engine/Optimization structure
- KPIDashboard: formatKpiValue() for human-readable numbers (150K, 1.5M)
- YouTubeAudit: metric-based diagnosis rows (subscriber ratio, upload freq)
- ContentCalendar: week theme labels, channel symbols, compact entries
- useExportPDF: triggerAllAnimations() scrolls all sections to fire
  whileInView before capture; isDarkSection() keeps dark sections whole;
  forceVisible() 2-pass opacity/transform override

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 20:07:39 +09:00
Haewon Kam e32b8766de feat: prototype gap closure — enrichment diagnosis + brand extraction + plan assets
Phase 1: Data Pipeline Fixes
- Plan page: connect enrichment data for Asset Collection + YouTube Repurpose
- mergeEnrichment: generate 15-20 data-driven diagnosis items from enrichment
  (YouTube Shorts check, IG engagement, FB activity, 강남언니 ratings, GMaps)
- ClinicSnapshot: fill staffCount, nearestStation, certifications from enrichment

Phase 2: AI + Brand Enhancement
- AI prompt: per-channel diagnosis[] array (5-7 items), established, nameEn, newChannelProposals
- scrape-website: Firecrawl branding extraction (colors, fonts, logo, tagline)
- transformPlan: BrandGuide colors/fonts from scraped branding data
- transformPlan: cross-channel brand consistency analysis (name, phone mismatches)
- transformPlan: channel branding rules from enrichment (YT, IG, FB profiles)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 17:09:15 +09:00
Haewon Kam a7d8aeeddc feat: Facebook page data collection via Apify scraper
- enrich-channels: add Facebook Pages Scraper (apify~facebook-pages-scraper)
- Collects: pageName, followers, likes, categories, email, phone, website, intro, rating
- transformReport: merge Facebook data into facebookAudit.pages[] (auto-shows section)
- Frontend: pass facebookHandle through enrichment pipeline
- EnrichChannelsRequest: add facebookHandle parameter

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 16:16:37 +09:00
Haewon Kam ad625e08ee fix: enrichment pipeline reliability + loading page gradient + button click area
- generate-report: filter empty strings from AI social handles, add saveError logging
- useReport: 3-level fallback for social handles (report > clinicInfo > scrape_data)
- useEnrichment: always trigger enrichment if clinicName exists (not just IG/YT handles)
- Hero: pointer-events-none on decorative blobs (were blocking button clicks)
- AnalysisLoadingPage: warm gradient on INFINITH logo text (#fff3eb → #e4cfff → #f5f9ff)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 16:05:33 +09:00
Haewon Kam 72ea8f4a2d feat: Naver Search API + multi-account Instagram + button UX fix
- Naver Blog search: collect blog post results for clinic name (total count + top 10 posts)
- Naver Place search: collect place info (name, category, address, telephone)
- Multi-account Instagram: AI prompt requests all IG accounts (국내/해외)
- enrich-channels: process multiple IG handles with fallback per handle
- transformReport: merge multiple IG accounts into instagramAudit.accounts[]
- generate-report: socialHandles.instagram now array of handles
- Hero/CTA: transition-all → transition-shadow for instant click response
- Hero/CTA: disabled state when URL is empty (opacity-50 + cursor-not-allowed)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 15:34:10 +09:00
Haewon Kam cf482d1bd7 feat: 강남언니 real-time data collection via Firecrawl scraping
- enrich-channels: add 강남언니 scraping module (search + structured JSON extraction)
- Collects: rating/10, reviews, doctors with ratings, procedures, certifications
- transformReport: merge 강남언니 data into clinicSnapshot + otherChannels
- Updates lead doctor info, certifications, and review counts from real data

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 14:51:47 +09:00
Haewon Kam e5399486f7 fix: Instagram data collection pipeline — handle normalization + DB persistence
- enrich-channels: Instagram fallback — auto-try _ps, .ps, _clinic suffixes when <100 followers
- enrich-channels: YouTube URL normalization via normalizeYouTubeChannel (handles /c/, /user/, @handle)
- enrich-channels: Google Maps multi-query search for better hit rate
- generate-report: AI-found social handles prioritized over Firecrawl scrape
- generate-report: Added socialMedia field to AI prompt for accurate handle discovery
- normalizeHandles: Added normalizeYouTubeChannel for /c/, /user/, /channel/, @handle URLs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 14:45:00 +09:00
Haewon Kam 9bf47f7d93 feat: Creatomate API integration — real video generation in Content Studio
- Add creatomateVideoGen.ts service with polling-based async rendering
- Replace video stub (setTimeout) with actual Creatomate API calls
- Add video preview (<video> tag) and MP4 download support
- Build programmatic source (branded slideshow) without pre-built templates
- Error handling: auth, rate limit, render failure → Korean messages

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 14:13:07 +09:00