diff --git a/CLAUDE.md b/CLAUDE.md index 8a0c316..08d2672 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -443,6 +443,11 @@ Das System unterstützt Deutsch (default) und Englisch: - **Workflows API:** https://pl.porwoll.tech/api/workflows (GET, öffentlich, tenant required) - **Data Retention API:** https://pl.porwoll.tech/api/retention (GET/POST, Super-Admin erforderlich) - **YouTube Analytics:** https://pl.porwoll.tech/admin/youtube-analytics (Admin View, Auth erforderlich) +- **Community Inbox:** https://pl.porwoll.tech/admin/community/inbox (Admin View, Auth erforderlich) +- **Community Analytics:** https://pl.porwoll.tech/admin/community/analytics (Admin View, Auth erforderlich) +- **Community Sync:** https://pl.porwoll.tech/api/community/sync (POST: Trigger, GET: Status) +- **Community Stats:** https://pl.porwoll.tech/api/community/stats (GET, Auth erforderlich) +- **Meta OAuth:** https://pl.porwoll.tech/api/auth/meta (GET, startet OAuth-Flow) ## Security-Features @@ -1156,6 +1161,157 @@ Die FormSubmissions Collection wurde zu einem leichtgewichtigen CRM erweitert: - `src/collections/FormSubmissionsOverrides.ts` - Feld-Definitionen - `src/hooks/formSubmissionHooks.ts` - Automatisierungen +## Community Management System + +Plattformübergreifendes Community Management für YouTube, Facebook und Instagram mit einer einheitlichen Inbox, AI-Analyse und automatischer Moderation. + +### Architektur + +``` + ┌─────────────────────────────────────────┐ + │ Admin UI │ + │ ┌─────────────┐ ┌──────────────────┐ │ + │ │ Community │ │ Community │ │ + │ │ Inbox │ │ Analytics │ │ + │ └──────┬──────┘ └────────┬─────────┘ │ + └─────────┼──────────────────┼────────────┘ + │ │ + ┌─────────▼──────────────────▼────────────┐ + │ /api/community/* │ + │ sync, sync-status, stats, reply, │ + │ generate-reply, export, stream │ + └─────────────────┬───────────────────────┘ + │ + ┌─────────────────▼───────────────────────┐ + │ UnifiedSyncService │ + │ ┌──────────┬───────────┬────────────┐ │ + │ │ YouTube │ Facebook │ Instagram │ │ + │ │ Sync │ Sync │ Sync │ │ + │ └────┬─────┴─────┬─────┴──────┬─────┘ │ + └───────┼───────────┼────────────┼────────┘ + │ │ │ + ┌───────▼───────────▼────────────▼────────┐ + │ CommunityInteractions │ + │ (einheitliche Collection für alle │ + │ Plattform-Kommentare) │ + └─────────────────────────────────────────┘ +``` + +### Admin UI + +**Community Inbox** (`/admin/community/inbox`): +- Einheitliche Ansicht aller Kommentare (YouTube + Facebook + Instagram) +- Filter nach Plattform, Status, Priorität, Sentiment, Flags +- AI-generierte Antwort-Vorschläge (Claude) +- Direkte Antwort-Funktion +- Echtzeit-Updates via SSE (`/api/community/stream`) +- Export als CSV/JSON +- Sync-Button (triggert alle Plattformen) + +**Community Analytics** (`/admin/community/analytics`): +- KPI-Cards (Gesamt, Heute, Unbeantwortet) +- Sentiment-Trend-Chart +- Topic-Cloud +- Response-Metriken +- Kanal-Vergleich +- Top-Content nach Engagement + +### Meta (Facebook + Instagram) Integration + +**OAuth-Flow:** +``` +1. Admin öffnet /api/auth/meta?socialAccountId=X&accountType=both +2. Redirect zu Facebook OAuth (12 Scopes) +3. Callback: Short-Lived → Long-Lived Token (60 Tage) +4. Facebook Pages + Instagram Business Accounts werden geladen +5. Token + Account-Daten in SocialAccounts gespeichert +``` + +**Unterstützte Scopes:** +- Facebook: `pages_show_list`, `pages_read_engagement`, `pages_manage_posts`, `pages_read_user_content`, `pages_manage_engagement`, `pages_messaging` +- Instagram: `instagram_basic`, `instagram_manage_comments`, `instagram_manage_messages`, `instagram_content_publish` + +**API-Clients:** + +| Client | Datei | Funktionen | +|--------|-------|------------| +| MetaBaseClient | `src/lib/integrations/meta/MetaBaseClient.ts` | HTTP-Basis, Pagination, Retry, Token-Management | +| FacebookClient | `src/lib/integrations/meta/FacebookClient.ts` | Posts, Kommentare, Messenger, Insights | +| InstagramClient | `src/lib/integrations/meta/InstagramClient.ts` | Media, Kommentare, Mentions, DMs, Insights | + +**Sync-Services:** + +| Service | Datei | Beschreibung | +|---------|-------|--------------| +| FacebookSyncService | `src/lib/integrations/meta/FacebookSyncService.ts` | Synct Page-Kommentare + Replies | +| InstagramSyncService | `src/lib/integrations/meta/InstagramSyncService.ts` | Synct Media-Kommentare + Mentions | +| UnifiedSyncService | `src/lib/jobs/UnifiedSyncService.ts` | Orchestriert YouTube + Facebook + Instagram | + +**Sync-Ablauf (pro Account):** +1. SocialAccount laden + Platform verifizieren +2. Token validieren +3. Posts/Media abrufen (mit Datum-Filter) +4. Kommentare pro Post synchronisieren +5. AI-Analyse via Claude (Sentiment, Topics, Flags) +6. In CommunityInteractions speichern (dedupliziert via `externalId`) +7. Account-Stats aktualisieren + +### Sync-Trigger + +| Trigger | Endpoint | Plattformen | +|---------|----------|-------------| +| Cron (alle 15 Min) | `/api/cron/community-sync` | Alle aktiven Accounts | +| Manuell (Inbox-Button) | `/api/community/sync` (POST) | Alle (optional filterbar) | +| YouTube-spezifisch | `/api/cron/youtube-sync` | Nur YouTube | + +### Community API-Endpoints + +| Endpoint | Methode | Beschreibung | +|----------|---------|--------------| +| `/api/community/sync` | POST | Manueller Sync (alle Plattformen) | +| `/api/community/sync` | GET | Sync-Status | +| `/api/community/sync-status` | GET | Detaillierter Status mit Account-Stats | +| `/api/community/stats` | GET | Interaktions-Statistiken | +| `/api/community/reply` | POST | Antwort senden | +| `/api/community/generate-reply` | POST | AI-Antwort generieren (Claude) | +| `/api/community/export` | GET | Daten-Export (CSV/JSON) | +| `/api/community/stream` | GET | SSE-Stream für Echtzeit-Updates | +| `/api/community/sync-comments` | POST | Kommentar-Sync (Legacy) | +| `/api/community/analytics/*` | GET | Analytics-Daten (6 Endpoints) | +| `/api/auth/meta` | GET | Meta OAuth starten | +| `/api/auth/meta/callback` | GET | Meta OAuth Callback | + +### CommunityRules (Automatisierung) + +Regel-basierte Automatisierung für eingehende Kommentare: + +**Trigger-Typen:** `keyword`, `sentiment`, `question_detected`, `medical_detected`, `influencer` (>10k Follower), `all_new`, `contains_link`, `contains_email` + +**Aktionen:** `set_priority`, `assign_to`, `set_flag`, `suggest_template`, `send_notification`, `flag_medical`, `escalate`, `mark_spam`, `set_deadline` + +### Wichtige Dateien + +``` +src/lib/integrations/meta/ +├── MetaBaseClient.ts # HTTP-Basis mit Retry + Pagination +├── FacebookClient.ts # Facebook Graph API Client +├── InstagramClient.ts # Instagram Graph API Client +├── FacebookSyncService.ts # Facebook Kommentar-Sync +├── InstagramSyncService.ts # Instagram Kommentar-Sync +├── oauth.ts # Meta OAuth 2.0 Flow +└── index.ts # Re-Exports + +src/lib/jobs/ +├── UnifiedSyncService.ts # Orchestriert alle Plattform-Syncs +├── syncAllComments.ts # YouTube-spezifischer Sync (Legacy) +└── JobLogger.ts # Strukturiertes Logging + +src/app/(payload)/api/ +├── auth/meta/ # OAuth Start + Callback +├── community/ # 14 Community-Endpoints +└── cron/community-sync/ # Cron-Trigger für Unified Sync +``` + ## Globals > **Hinweis:** SiteSettings, Navigations und PrivacyPolicySettings wurden zu tenant-spezifischen Collections umgewandelt (siehe Collections Übersicht). @@ -1333,4 +1489,4 @@ ssh payload@162.55.85.18 ### Scripts & Backup - `scripts/backup/README.md` - Backup-System Dokumentation -*Letzte Aktualisierung: 13.02.2026 (CI Pipeline: ESLint + Typecheck grün, Payload 3.76.1, Next.js 16.2.0-canary.41)* +*Letzte Aktualisierung: 13.02.2026 (Community Management Doku, Sync-Endpoint Fix: UnifiedSyncService statt YouTube-only)* diff --git a/src/app/(payload)/api/community/sync/route.ts b/src/app/(payload)/api/community/sync/route.ts index e44cbf9..8a120d6 100644 --- a/src/app/(payload)/api/community/sync/route.ts +++ b/src/app/(payload)/api/community/sync/route.ts @@ -3,11 +3,17 @@ import { NextRequest, NextResponse } from 'next/server' import { getPayload } from 'payload' import config from '@payload-config' -import { runSync, getSyncStatus } from '@/lib/jobs/syncAllComments' +import { + runUnifiedSync, + getUnifiedSyncStatus, + type SupportedPlatform, +} from '@/lib/jobs/UnifiedSyncService' /** * POST /api/community/sync - * Manueller Sync-Trigger für alle YouTube-Accounts + * Manueller Sync-Trigger für alle Plattformen (YouTube, Facebook, Instagram) + * + * Optional: ?platforms=youtube,facebook,instagram (komma-separiert) */ export async function POST(request: NextRequest) { try { @@ -35,7 +41,7 @@ export async function POST(request: NextRequest) { } // Prüfe ob bereits ein Sync läuft - const status = getSyncStatus() + const status = getUnifiedSyncStatus() if (status.isRunning) { return NextResponse.json( { @@ -46,14 +52,30 @@ export async function POST(request: NextRequest) { ) } - console.log(`[Sync] Manual sync triggered by user ${user.id}`) + // Optionaler Plattform-Filter aus Body oder Query + let platforms: SupportedPlatform[] | undefined + try { + const body = await request.json() + if (body.platforms && Array.isArray(body.platforms)) { + platforms = body.platforms as SupportedPlatform[] + } + } catch { + // Kein JSON Body — alle Plattformen syncen + } - const result = await runSync() + console.log( + `[Sync] Manual unified sync triggered by user ${user.id}`, + platforms ? `(platforms: ${platforms.join(', ')})` : '(all platforms)' + ) + + const result = await runUnifiedSync({ platforms }) return NextResponse.json({ success: result.success, + duration: result.duration, + platforms: result.platforms, results: result.results, - error: result.error, + errors: result.errors.length > 0 ? result.errors : undefined, }) } catch (error: unknown) { console.error('[Sync] Error:', error) @@ -76,7 +98,7 @@ export async function GET(request: NextRequest) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } - const status = getSyncStatus() + const status = getUnifiedSyncStatus() return NextResponse.json({ ...status,