275 lines
16 KiB
XML
275 lines
16 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800" font-family="Arial, sans-serif">
|
|
<defs>
|
|
<linearGradient id="bgGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
<stop offset="0%" style="stop-color:#f8fafc"/>
|
|
<stop offset="100%" style="stop-color:#e2e8f0"/>
|
|
</linearGradient>
|
|
<linearGradient id="frontendGrad" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
<stop offset="0%" style="stop-color:#3b82f6"/>
|
|
<stop offset="100%" style="stop-color:#1d4ed8"/>
|
|
</linearGradient>
|
|
<linearGradient id="backendGrad" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
<stop offset="0%" style="stop-color:#10b981"/>
|
|
<stop offset="100%" style="stop-color:#059669"/>
|
|
</linearGradient>
|
|
<linearGradient id="dbGrad" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
<stop offset="0%" style="stop-color:#f59e0b"/>
|
|
<stop offset="100%" style="stop-color:#d97706"/>
|
|
</linearGradient>
|
|
<linearGradient id="externalGrad" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
<stop offset="0%" style="stop-color:#8b5cf6"/>
|
|
<stop offset="100%" style="stop-color:#7c3aed"/>
|
|
</linearGradient>
|
|
<linearGradient id="platformGrad" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
<stop offset="0%" style="stop-color:#ef4444"/>
|
|
<stop offset="100%" style="stop-color:#dc2626"/>
|
|
</linearGradient>
|
|
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
|
|
<feDropShadow dx="2" dy="2" stdDeviation="3" flood-opacity="0.2"/>
|
|
</filter>
|
|
</defs>
|
|
|
|
<!-- Background -->
|
|
<rect width="1200" height="800" fill="url(#bgGrad)"/>
|
|
|
|
<!-- Title -->
|
|
<text x="600" y="40" text-anchor="middle" font-size="24" font-weight="bold" fill="#1e293b">CaStAD System Architecture</text>
|
|
|
|
<!-- Frontend Section -->
|
|
<g transform="translate(50, 70)">
|
|
<rect width="320" height="280" rx="12" fill="url(#frontendGrad)" filter="url(#shadow)"/>
|
|
<text x="160" y="30" text-anchor="middle" font-size="16" font-weight="bold" fill="white">Frontend (React 19 + Vite)</text>
|
|
<rect x="15" y="50" width="290" height="210" rx="8" fill="white" fill-opacity="0.95"/>
|
|
|
|
<!-- Frontend Components -->
|
|
<text x="25" y="75" font-size="11" font-weight="bold" fill="#1e40af">Pages</text>
|
|
<text x="25" y="92" font-size="10" fill="#475569">• GeneratorPage (영상 생성)</text>
|
|
<text x="25" y="106" font-size="10" fill="#475569">• AdminDashboard (관리자)</text>
|
|
<text x="25" y="120" font-size="10" fill="#475569">• PensionsView (펜션 관리)</text>
|
|
|
|
<text x="25" y="145" font-size="11" font-weight="bold" fill="#1e40af">Services</text>
|
|
<text x="25" y="162" font-size="10" fill="#475569">• geminiService (AI 콘텐츠)</text>
|
|
<text x="25" y="176" font-size="10" fill="#475569">• sunoService (음악 생성)</text>
|
|
<text x="25" y="190" font-size="10" fill="#475569">• naverService (크롤링)</text>
|
|
<text x="25" y="204" font-size="10" fill="#475569">• instagramService (크롤링)</text>
|
|
|
|
<text x="170" y="75" font-size="11" font-weight="bold" fill="#1e40af">Contexts</text>
|
|
<text x="170" y="92" font-size="10" fill="#475569">• AuthContext</text>
|
|
<text x="170" y="106" font-size="10" fill="#475569">• LanguageContext</text>
|
|
<text x="170" y="120" font-size="10" fill="#475569">• ThemeContext</text>
|
|
|
|
<text x="170" y="145" font-size="11" font-weight="bold" fill="#1e40af">Features</text>
|
|
<text x="170" y="162" font-size="10" fill="#475569">• 다국어 지원 (6개)</text>
|
|
<text x="170" y="176" font-size="10" fill="#475569">• JWT 인증</text>
|
|
<text x="170" y="190" font-size="10" fill="#475569">• OAuth (Google/Naver)</text>
|
|
<text x="170" y="204" font-size="10" fill="#475569">• 실시간 프리뷰</text>
|
|
|
|
<text x="160" y="248" text-anchor="middle" font-size="10" fill="#64748b">Port: 5173 (dev) / 3000 (prod)</text>
|
|
</g>
|
|
|
|
<!-- Backend Section -->
|
|
<g transform="translate(440, 70)">
|
|
<rect width="320" height="280" rx="12" fill="url(#backendGrad)" filter="url(#shadow)"/>
|
|
<text x="160" y="30" text-anchor="middle" font-size="16" font-weight="bold" fill="white">Backend (Express.js)</text>
|
|
<rect x="15" y="50" width="290" height="210" rx="8" fill="white" fill-opacity="0.95"/>
|
|
|
|
<!-- Backend Components -->
|
|
<text x="25" y="75" font-size="11" font-weight="bold" fill="#065f46">API Endpoints (107+)</text>
|
|
<text x="25" y="92" font-size="10" fill="#475569">• /api/auth/* (인증)</text>
|
|
<text x="25" y="106" font-size="10" fill="#475569">• /api/profile/* (펜션)</text>
|
|
<text x="25" y="120" font-size="10" fill="#475569">• /api/youtube/* (YouTube)</text>
|
|
<text x="25" y="134" font-size="10" fill="#475569">• /api/instagram/* (Instagram)</text>
|
|
<text x="25" y="148" font-size="10" fill="#475569">• /api/tiktok/* (TikTok)</text>
|
|
<text x="25" y="162" font-size="10" fill="#475569">• /api/gemini/* (AI)</text>
|
|
<text x="25" y="176" font-size="10" fill="#475569">• /api/admin/* (관리자)</text>
|
|
|
|
<text x="170" y="75" font-size="11" font-weight="bold" fill="#065f46">Core Services</text>
|
|
<text x="170" y="92" font-size="10" fill="#475569">• Puppeteer (렌더링)</text>
|
|
<text x="170" y="106" font-size="10" fill="#475569">• FFmpeg (영상 병합)</text>
|
|
<text x="170" y="120" font-size="10" fill="#475569">• JWT 인증</text>
|
|
<text x="170" y="134" font-size="10" fill="#475569">• 쿠키 기반 크롤링</text>
|
|
<text x="170" y="148" font-size="10" fill="#475569">• API 사용량 추적</text>
|
|
<text x="170" y="162" font-size="10" fill="#475569">• 자동 생성 스케줄러</text>
|
|
|
|
<text x="160" y="248" text-anchor="middle" font-size="10" fill="#64748b">Port: 3001</text>
|
|
</g>
|
|
|
|
<!-- Database Section -->
|
|
<g transform="translate(830, 70)">
|
|
<rect width="320" height="280" rx="12" fill="url(#dbGrad)" filter="url(#shadow)"/>
|
|
<text x="160" y="30" text-anchor="middle" font-size="16" font-weight="bold" fill="white">Database (SQLite)</text>
|
|
<rect x="15" y="50" width="290" height="210" rx="8" fill="white" fill-opacity="0.95"/>
|
|
|
|
<!-- Database Tables -->
|
|
<text x="25" y="75" font-size="11" font-weight="bold" fill="#92400e">Core Tables (30+)</text>
|
|
<text x="25" y="92" font-size="10" fill="#475569">• users (사용자/플랜/크레딧)</text>
|
|
<text x="25" y="106" font-size="10" fill="#475569">• pension_profiles (펜션)</text>
|
|
<text x="25" y="120" font-size="10" fill="#475569">• pension_images (이미지)</text>
|
|
<text x="25" y="134" font-size="10" fill="#475569">• history (영상 이력)</text>
|
|
<text x="25" y="148" font-size="10" fill="#475569">• youtube_connections</text>
|
|
<text x="25" y="162" font-size="10" fill="#475569">• instagram_connections</text>
|
|
<text x="25" y="176" font-size="10" fill="#475569">• tiktok_connections</text>
|
|
|
|
<text x="170" y="75" font-size="11" font-weight="bold" fill="#92400e">Data Tables</text>
|
|
<text x="170" y="92" font-size="10" fill="#475569">• festivals (축제)</text>
|
|
<text x="170" y="106" font-size="10" fill="#475569">• public_pensions</text>
|
|
<text x="170" y="120" font-size="10" fill="#475569">• api_usage_logs</text>
|
|
<text x="170" y="134" font-size="10" fill="#475569">• system_settings</text>
|
|
<text x="170" y="148" font-size="10" fill="#475569">• activity_logs</text>
|
|
<text x="170" y="162" font-size="10" fill="#475569">• credit_history</text>
|
|
|
|
<text x="160" y="248" text-anchor="middle" font-size="10" fill="#64748b">File: server/database.sqlite</text>
|
|
</g>
|
|
|
|
<!-- External APIs Section -->
|
|
<g transform="translate(50, 380)">
|
|
<rect width="540" height="180" rx="12" fill="url(#externalGrad)" filter="url(#shadow)"/>
|
|
<text x="270" y="30" text-anchor="middle" font-size="16" font-weight="bold" fill="white">External APIs</text>
|
|
<rect x="15" y="50" width="510" height="110" rx="8" fill="white" fill-opacity="0.95"/>
|
|
|
|
<!-- API Groups -->
|
|
<g transform="translate(25, 70)">
|
|
<rect width="110" height="70" rx="6" fill="#f0f9ff" stroke="#0ea5e9" stroke-width="1"/>
|
|
<text x="55" y="20" text-anchor="middle" font-size="11" font-weight="bold" fill="#0369a1">Google</text>
|
|
<text x="55" y="38" text-anchor="middle" font-size="9" fill="#475569">Gemini AI</text>
|
|
<text x="55" y="52" text-anchor="middle" font-size="9" fill="#475569">Places API</text>
|
|
<text x="55" y="66" text-anchor="middle" font-size="9" fill="#475569">OAuth 2.0</text>
|
|
</g>
|
|
|
|
<g transform="translate(145, 70)">
|
|
<rect width="110" height="70" rx="6" fill="#fdf4ff" stroke="#d946ef" stroke-width="1"/>
|
|
<text x="55" y="20" text-anchor="middle" font-size="11" font-weight="bold" fill="#a21caf">Suno AI</text>
|
|
<text x="55" y="38" text-anchor="middle" font-size="9" fill="#475569">Music Gen</text>
|
|
<text x="55" y="52" text-anchor="middle" font-size="9" fill="#475569">V5 Model</text>
|
|
<text x="55" y="66" text-anchor="middle" font-size="9" fill="#475569">Custom Mode</text>
|
|
</g>
|
|
|
|
<g transform="translate(265, 70)">
|
|
<rect width="110" height="70" rx="6" fill="#f0fdf4" stroke="#22c55e" stroke-width="1"/>
|
|
<text x="55" y="20" text-anchor="middle" font-size="11" font-weight="bold" fill="#16a34a">Naver</text>
|
|
<text x="55" y="38" text-anchor="middle" font-size="9" fill="#475569">Map GraphQL</text>
|
|
<text x="55" y="52" text-anchor="middle" font-size="9" fill="#475569">OAuth 2.0</text>
|
|
<text x="55" y="66" text-anchor="middle" font-size="9" fill="#475569">Cookie Auth</text>
|
|
</g>
|
|
|
|
<g transform="translate(385, 70)">
|
|
<rect width="110" height="70" rx="6" fill="#fff7ed" stroke="#f97316" stroke-width="1"/>
|
|
<text x="55" y="20" text-anchor="middle" font-size="11" font-weight="bold" fill="#ea580c">TourAPI</text>
|
|
<text x="55" y="38" text-anchor="middle" font-size="9" fill="#475569">축제 정보</text>
|
|
<text x="55" y="52" text-anchor="middle" font-size="9" fill="#475569">펜션 정보</text>
|
|
<text x="55" y="66" text-anchor="middle" font-size="9" fill="#475569">지역 코드</text>
|
|
</g>
|
|
</g>
|
|
|
|
<!-- Upload Platforms Section -->
|
|
<g transform="translate(610, 380)">
|
|
<rect width="540" height="180" rx="12" fill="url(#platformGrad)" filter="url(#shadow)"/>
|
|
<text x="270" y="30" text-anchor="middle" font-size="16" font-weight="bold" fill="white">Upload Platforms</text>
|
|
<rect x="15" y="50" width="510" height="110" rx="8" fill="white" fill-opacity="0.95"/>
|
|
|
|
<!-- Platform Groups -->
|
|
<g transform="translate(35, 70)">
|
|
<rect width="140" height="70" rx="6" fill="#fef2f2" stroke="#ef4444" stroke-width="1"/>
|
|
<text x="70" y="20" text-anchor="middle" font-size="11" font-weight="bold" fill="#dc2626">YouTube</text>
|
|
<text x="70" y="38" text-anchor="middle" font-size="9" fill="#475569">OAuth 2.0 연동</text>
|
|
<text x="70" y="52" text-anchor="middle" font-size="9" fill="#475569">플레이리스트 관리</text>
|
|
<text x="70" y="66" text-anchor="middle" font-size="9" fill="#475569">Analytics API</text>
|
|
</g>
|
|
|
|
<g transform="translate(185, 70)">
|
|
<rect width="140" height="70" rx="6" fill="#fdf2f8" stroke="#ec4899" stroke-width="1"/>
|
|
<text x="70" y="20" text-anchor="middle" font-size="11" font-weight="bold" fill="#db2777">Instagram</text>
|
|
<text x="70" y="38" text-anchor="middle" font-size="9" fill="#475569">Reels 업로드</text>
|
|
<text x="70" y="52" text-anchor="middle" font-size="9" fill="#475569">자동 캡션/해시태그</text>
|
|
<text x="70" y="66" text-anchor="middle" font-size="9" fill="#475569">주간 통계</text>
|
|
</g>
|
|
|
|
<g transform="translate(335, 70)">
|
|
<rect width="140" height="70" rx="6" fill="#f0f0f0" stroke="#171717" stroke-width="1"/>
|
|
<text x="70" y="20" text-anchor="middle" font-size="11" font-weight="bold" fill="#171717">TikTok</text>
|
|
<text x="70" y="38" text-anchor="middle" font-size="9" fill="#475569">OAuth 2.0 연동</text>
|
|
<text x="70" y="52" text-anchor="middle" font-size="9" fill="#475569">Direct Post API</text>
|
|
<text x="70" y="66" text-anchor="middle" font-size="9" fill="#475569">개인정보 설정</text>
|
|
</g>
|
|
</g>
|
|
|
|
<!-- Data Flow Section -->
|
|
<g transform="translate(50, 590)">
|
|
<rect width="1100" height="180" rx="12" fill="#1e293b" filter="url(#shadow)"/>
|
|
<text x="550" y="30" text-anchor="middle" font-size="16" font-weight="bold" fill="white">Video Generation Pipeline</text>
|
|
|
|
<!-- Flow Steps -->
|
|
<g transform="translate(30, 55)">
|
|
<rect width="150" height="100" rx="8" fill="#3b82f6"/>
|
|
<text x="75" y="25" text-anchor="middle" font-size="11" font-weight="bold" fill="white">1. 입력</text>
|
|
<text x="75" y="45" text-anchor="middle" font-size="9" fill="#dbeafe">펜션 정보</text>
|
|
<text x="75" y="60" text-anchor="middle" font-size="9" fill="#dbeafe">이미지 (최대 100장)</text>
|
|
<text x="75" y="75" text-anchor="middle" font-size="9" fill="#dbeafe">URL 크롤링</text>
|
|
<text x="75" y="90" text-anchor="middle" font-size="9" fill="#dbeafe">(Naver/Google/Insta)</text>
|
|
</g>
|
|
|
|
<path d="M195 105 L225 105" stroke="#94a3b8" stroke-width="2" marker-end="url(#arrowhead)"/>
|
|
|
|
<g transform="translate(235, 55)">
|
|
<rect width="150" height="100" rx="8" fill="#8b5cf6"/>
|
|
<text x="75" y="25" text-anchor="middle" font-size="11" font-weight="bold" fill="white">2. AI 콘텐츠 생성</text>
|
|
<text x="75" y="45" text-anchor="middle" font-size="9" fill="#ede9fe">Gemini: 광고 카피</text>
|
|
<text x="75" y="60" text-anchor="middle" font-size="9" fill="#ede9fe">Gemini: TTS 음성</text>
|
|
<text x="75" y="75" text-anchor="middle" font-size="9" fill="#ede9fe">Suno: 배경 음악</text>
|
|
<text x="75" y="90" text-anchor="middle" font-size="9" fill="#ede9fe">DNA 분석</text>
|
|
</g>
|
|
|
|
<path d="M400 105 L430 105" stroke="#94a3b8" stroke-width="2"/>
|
|
|
|
<g transform="translate(440, 55)">
|
|
<rect width="150" height="100" rx="8" fill="#10b981"/>
|
|
<text x="75" y="25" text-anchor="middle" font-size="11" font-weight="bold" fill="white">3. 영상 렌더링</text>
|
|
<text x="75" y="45" text-anchor="middle" font-size="9" fill="#d1fae5">Puppeteer 캡처</text>
|
|
<text x="75" y="60" text-anchor="middle" font-size="9" fill="#d1fae5">FFmpeg 병합</text>
|
|
<text x="75" y="75" text-anchor="middle" font-size="9" fill="#d1fae5">H.264 + AAC</text>
|
|
<text x="75" y="90" text-anchor="middle" font-size="9" fill="#d1fae5">9:16 / 16:9 / 1:1</text>
|
|
</g>
|
|
|
|
<path d="M605 105 L635 105" stroke="#94a3b8" stroke-width="2"/>
|
|
|
|
<g transform="translate(645, 55)">
|
|
<rect width="150" height="100" rx="8" fill="#f59e0b"/>
|
|
<text x="75" y="25" text-anchor="middle" font-size="11" font-weight="bold" fill="white">4. 후처리</text>
|
|
<text x="75" y="45" text-anchor="middle" font-size="9" fill="#fef3c7">SEO 최적화</text>
|
|
<text x="75" y="60" text-anchor="middle" font-size="9" fill="#fef3c7">다국어 제목/설명</text>
|
|
<text x="75" y="75" text-anchor="middle" font-size="9" fill="#fef3c7">해시태그 생성</text>
|
|
<text x="75" y="90" text-anchor="middle" font-size="9" fill="#fef3c7">썸네일 생성</text>
|
|
</g>
|
|
|
|
<path d="M810 105 L840 105" stroke="#94a3b8" stroke-width="2"/>
|
|
|
|
<g transform="translate(850, 55)">
|
|
<rect width="200" height="100" rx="8" fill="#ef4444"/>
|
|
<text x="100" y="25" text-anchor="middle" font-size="11" font-weight="bold" fill="white">5. 멀티 플랫폼 업로드</text>
|
|
<text x="100" y="45" text-anchor="middle" font-size="9" fill="#fecaca">YouTube (플레이리스트)</text>
|
|
<text x="100" y="60" text-anchor="middle" font-size="9" fill="#fecaca">Instagram (Reels)</text>
|
|
<text x="100" y="75" text-anchor="middle" font-size="9" fill="#fecaca">TikTok (Direct Post)</text>
|
|
<text x="100" y="90" text-anchor="middle" font-size="9" fill="#fecaca">자동/수동 선택</text>
|
|
</g>
|
|
</g>
|
|
|
|
<!-- Arrows -->
|
|
<defs>
|
|
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
<polygon points="0 0, 10 3.5, 0 7" fill="#94a3b8"/>
|
|
</marker>
|
|
</defs>
|
|
|
|
<!-- Connection Lines -->
|
|
<path d="M210 350 L210 380" stroke="#64748b" stroke-width="2" stroke-dasharray="5,5"/>
|
|
<path d="M600 350 L600 380" stroke="#64748b" stroke-width="2" stroke-dasharray="5,5"/>
|
|
<path d="M990 350 L990 380" stroke="#64748b" stroke-width="2" stroke-dasharray="5,5"/>
|
|
|
|
<path d="M370 210 L440 210" stroke="#64748b" stroke-width="2" marker-end="url(#arrowhead)"/>
|
|
<path d="M760 210 L830 210" stroke="#64748b" stroke-width="2" marker-end="url(#arrowhead)"/>
|
|
|
|
<!-- Version Info -->
|
|
<text x="1150" y="790" text-anchor="end" font-size="10" fill="#94a3b8">v3.6.0 - CaStAD Architecture</text>
|
|
</svg>
|