# Community Management System - Roadmap 2.3 bis 3.0 (Erweitert) **Version:** 2.0 (Erweitert mit Facebook-Integration) **Datum:** 16. Januar 2026 **Erstellt von:** Dev-KI nach Analyse des Konzept-Prompts --- ## Analyse des Original-Prompts ### Umsetzbarkeit in aktueller Implementierung | Komponente | Status | Bewertung | |------------|--------|-----------| | SocialPlatforms Collection | ✅ Existiert | Instagram, Facebook bereits definiert | | SocialAccounts Collection | ✅ Existiert | OAuth-Credentials-Struktur vorhanden | | CommunityInteractions | ✅ Existiert | Plattform-agnostisch, erweiterbar | | Rules Engine | ✅ Existiert | Basis für Auto-Reply vorhanden | | ClaudeAnalysisService | ✅ Existiert | Wiederverwendbar für alle Plattformen | | ClaudeReplyService | ✅ Existiert | Wiederverwendbar für alle Plattformen | | E-Mail Service | ✅ Existiert | Für Reports nutzbar | | YouTubeClient Pattern | ✅ Vorlage | Replizierbar für Meta/TikTok | ### Identifizierte Synergien 1. **Facebook + Instagram**: Beide nutzen Meta Graph API → Gemeinsame Auth-Basis 2. **CommentsSyncService**: Pattern kann für alle Plattformen verwendet werden 3. **Rules Engine → Auto-Reply**: Natürliche Erweiterung der bestehenden Logik --- ## Restrukturierte Phasen (Logisch aufgeteilt) ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ IMPLEMENTIERUNGSREIHENFOLGE │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ Phase 2.3a Phase 2.3b Phase 2.3c Phase 2.4 Phase 2.5a Phase 2.5b │ │ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │ │ │ Meta │───▶│Facebook│───▶│Insta- │───▶│TikTok │──▶│Auto- │──▶│Auto- │ │ │ │ OAuth │ │ Integr.│ │ gram │ │ │ │Reply │ │Reply │ │ │ └───────┘ └───────┘ └───────┘ └───────┘ │Service│ │ UI │ │ │ └───────┘ └───────┘ │ │ │ │ │ │ ▼ ▼ │ │ Phase 3.0a Phase 3.0b │ │ ┌───────────┐ ┌───────────┐ │ │ │ Scheduled │ │ Real-time │ │ │ │ Reports │ │ Updates │ │ │ └───────────┘ └───────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ ``` --- ## Phase 2.3a: Meta OAuth & Basis-Infrastruktur **Dauer:** 1-2 Tage **Abhängigkeiten:** Meta Business Suite Zugang, App-Konfiguration ### Ziel Gemeinsame OAuth-Infrastruktur für Facebook und Instagram (beide nutzen Meta Graph API). ### Voraussetzungen - Facebook Developer Account - Meta Business Suite mit verbundener Facebook Page - Instagram Business Account (mit Facebook Page verknüpft) - App in Meta for Developers erstellt ### Deliverables #### 1. Meta OAuth Flow ``` src/app/(payload)/api/auth/meta/ ├── route.ts # OAuth initiate └── callback/route.ts # OAuth callback (für FB + IG) ``` **OAuth Configuration:** ```typescript // src/lib/integrations/meta/oauth.ts const META_OAUTH_CONFIG = { authorizationUrl: 'https://www.facebook.com/v19.0/dialog/oauth', tokenUrl: 'https://graph.facebook.com/v19.0/oauth/access_token', scopes: [ // Facebook 'pages_show_list', 'pages_read_engagement', 'pages_manage_posts', 'pages_read_user_content', 'pages_manage_engagement', // Instagram 'instagram_basic', 'instagram_manage_comments', 'instagram_manage_messages', // Business 'business_management', ], } export async function getAuthUrl(state: string): Promise export async function exchangeCodeForTokens(code: string): Promise export async function refreshAccessToken(token: string): Promise export async function getLongLivedToken(shortLivedToken: string): Promise ``` #### 2. Meta Base Client ```typescript // src/lib/integrations/meta/MetaBaseClient.ts export class MetaBaseClient { protected accessToken: string protected apiVersion: string = 'v19.0' protected baseUrl: string = 'https://graph.facebook.com' constructor(accessToken: string) protected async request( endpoint: string, method?: 'GET' | 'POST' | 'DELETE', params?: Record ): Promise async getMe(): Promise async getPages(): Promise async getInstagramAccounts(pageId: string): Promise } ``` #### 3. Types ```typescript // src/types/meta.ts export interface MetaTokens { access_token: string token_type: string expires_in: number } export interface FacebookPage { id: string name: string access_token: string // Page-spezifischer Token category: string instagram_business_account?: { id: string } } export interface InstagramAccount { id: string username: string profile_picture_url: string followers_count: number media_count: number } export interface MetaComment { id: string message: string from: { id: string name: string } created_time: string like_count?: number comment_count?: number is_hidden?: boolean } ``` #### 4. API Endpoint ```typescript // src/app/(payload)/api/auth/meta/route.ts export async function GET(request: NextRequest) { // 1. State generieren mit accountType (facebook | instagram) // 2. Auth URL generieren // 3. Redirect zu Meta OAuth } // src/app/(payload)/api/auth/meta/callback/route.ts export async function GET(request: NextRequest) { // 1. Code aus Query extrahieren // 2. Token austauschen // 3. Long-lived Token holen (60 Tage gültig) // 4. Pages/IG Accounts abrufen // 5. In SocialAccounts speichern // 6. Redirect zu Admin mit Erfolg } ``` ### Environment Variables ```bash # .env META_APP_ID=your_app_id META_APP_SECRET=your_app_secret META_REDIRECT_URI=https://your-domain.com/api/auth/meta/callback ``` ### Acceptance Criteria - [ ] OAuth-Flow leitet korrekt zu Meta weiter - [ ] Callback verarbeitet Token korrekt - [ ] Long-lived Token wird generiert (60 Tage) - [ ] Pages und IG-Accounts werden erkannt - [ ] Credentials werden sicher gespeichert - [ ] Fehler werden benutzerfreundlich angezeigt --- ## Phase 2.3b: Facebook Integration **Dauer:** 2-3 Tage **Abhängigkeiten:** Phase 2.3a abgeschlossen ### Ziel Facebook Page Kommentare und Nachrichten synchronisieren, analysieren und beantworten. ### Deliverables #### 1. FacebookClient ```typescript // src/lib/integrations/meta/FacebookClient.ts import { MetaBaseClient } from './MetaBaseClient' export class FacebookClient extends MetaBaseClient { private pageId: string private pageAccessToken: string constructor(pageAccessToken: string, pageId: string) // Posts async getPagePosts(limit?: number, since?: Date): Promise async getPostComments(postId: string, limit?: number): Promise // Comments async replyToComment(commentId: string, message: string): Promise async hideComment(commentId: string): Promise async unhideComment(commentId: string): Promise async deleteComment(commentId: string): Promise async likeComment(commentId: string): Promise // Page Messages (Messenger) async getConversations(limit?: number): Promise async getMessages(conversationId: string): Promise async sendMessage(recipientId: string, message: string): Promise // Page Info async getPageInsights(metrics: string[], period: string): Promise } ``` #### 2. Facebook Types ```typescript // src/types/facebook.ts export interface FacebookPost { id: string message?: string story?: string full_picture?: string permalink_url: string created_time: string shares?: { count: number } reactions?: { summary: { total_count: number } } comments?: { summary: { total_count: number } } } export interface FacebookConversation { id: string participants: { data: Array<{ id: string; name: string }> } updated_time: string message_count: number } export interface FacebookMessage { id: string message: string from: { id: string; name: string } created_time: string attachments?: Array<{ type: string url: string }> } ``` #### 3. FacebookContent Collection ```typescript // src/collections/FacebookContent.ts { slug: 'facebook-content', admin: { useAsTitle: 'title', group: 'Social Media', defaultColumns: ['title', 'socialAccount', 'type', 'postedAt'], }, fields: [ { name: 'externalId', type: 'text', required: true, unique: true }, { name: 'socialAccount', type: 'relationship', relationTo: 'social-accounts', required: true }, { name: 'type', type: 'select', options: ['post', 'photo', 'video', 'link', 'event'] }, { name: 'title', type: 'text' }, // Erste Zeile der Message { name: 'message', type: 'textarea' }, { name: 'permalinkUrl', type: 'text' }, { name: 'imageUrl', type: 'text' }, { name: 'postedAt', type: 'date' }, { name: 'stats', type: 'group', fields: [ { name: 'reactions', type: 'number', defaultValue: 0 }, { name: 'comments', type: 'number', defaultValue: 0 }, { name: 'shares', type: 'number', defaultValue: 0 }, { name: 'reach', type: 'number', defaultValue: 0 }, ]}, ], } ``` #### 4. FacebookSyncService ```typescript // src/lib/integrations/meta/FacebookSyncService.ts export class FacebookSyncService { constructor(payload: Payload) async syncAccount(account: SocialAccount): Promise private async syncPosts(client: FacebookClient, account: SocialAccount): Promise private async syncComments(client: FacebookClient, post: FacebookContent): Promise private async syncMessages(client: FacebookClient, account: SocialAccount): Promise private async processComment(comment: MetaComment, account: SocialAccount, content: FacebookContent): Promise<'new' | 'updated' | 'skipped'> private async processMessage(message: FacebookMessage, account: SocialAccount, conversation: FacebookConversation): Promise<'new' | 'updated' | 'skipped'> } ``` #### 5. UI Updates **CommunityInbox.tsx Erweiterungen:** - Facebook-Icon und Badge - "Hide Comment" / "Unhide Comment" Actions - "Like Comment" Action - Messenger-Konversationen in separatem Tab - Facebook-spezifische Filter (Posts, Messenger) **Platform-Icon Mapping:** ```typescript const platformIcons = { youtube: , facebook: , instagram: , tiktok: , } ``` ### Acceptance Criteria - [ ] Posts werden synchronisiert (letzte 30 Tage) - [ ] Kommentare werden importiert und analysiert - [ ] Antworten werden über API gepostet - [ ] Hide/Unhide funktioniert - [ ] Messenger-Nachrichten werden synchronisiert - [ ] Messenger-Antworten funktionieren - [ ] Analytics zeigt Facebook-Daten - [ ] Rate Limiting wird beachtet (200 calls/hour) --- ## Phase 2.3c: Instagram Integration **Dauer:** 2 Tage **Abhängigkeiten:** Phase 2.3a abgeschlossen (Phase 2.3b parallel möglich) ### Ziel Instagram-Kommentare und DMs synchronisieren, analysieren und beantworten. ### Deliverables #### 1. InstagramClient ```typescript // src/lib/integrations/meta/InstagramClient.ts import { MetaBaseClient } from './MetaBaseClient' export class InstagramClient extends MetaBaseClient { private igAccountId: string constructor(accessToken: string, igAccountId: string) // Media async getMedia(limit?: number, since?: Date): Promise async getMediaComments(mediaId: string): Promise // Comments async replyToComment(commentId: string, message: string): Promise async hideComment(commentId: string): Promise async deleteComment(commentId: string): Promise // Mentions & Tags async getMentions(): Promise async getTaggedMedia(): Promise // Stories (Mentions) async getStoryMentions(): Promise // DMs (wenn Scope verfügbar) async getConversations(): Promise async sendMessage(conversationId: string, message: string): Promise // Account Info async getAccountInsights(metrics: string[], period: string): Promise } ``` #### 2. Instagram Types ```typescript // src/types/instagram.ts export interface InstagramMedia { id: string media_type: 'IMAGE' | 'VIDEO' | 'CAROUSEL_ALBUM' | 'REELS' media_url?: string thumbnail_url?: string permalink: string caption?: string timestamp: string like_count: number comments_count: number } export interface InstagramMention { id: string caption?: string media_type: string permalink: string timestamp: string username: string // Who mentioned us } export interface InstagramStoryMention { id: string media_type: string media_url: string timestamp: string // Story mentions expire after 24h! } export interface InstagramConversation { id: string participants: Array<{ id: string; username: string }> updated_time: string } ``` #### 3. InstagramContent Collection ```typescript // src/collections/InstagramContent.ts { slug: 'instagram-content', admin: { useAsTitle: 'caption', group: 'Social Media', defaultColumns: ['caption', 'socialAccount', 'mediaType', 'postedAt'], }, fields: [ { name: 'externalId', type: 'text', required: true, unique: true }, { name: 'socialAccount', type: 'relationship', relationTo: 'social-accounts', required: true }, { name: 'mediaType', type: 'select', options: ['image', 'video', 'carousel', 'reel', 'story'] }, { name: 'caption', type: 'textarea' }, { name: 'permalink', type: 'text' }, { name: 'mediaUrl', type: 'text' }, { name: 'thumbnailUrl', type: 'text' }, { name: 'postedAt', type: 'date' }, { name: 'stats', type: 'group', fields: [ { name: 'likes', type: 'number', defaultValue: 0 }, { name: 'comments', type: 'number', defaultValue: 0 }, { name: 'saves', type: 'number', defaultValue: 0 }, { name: 'reach', type: 'number', defaultValue: 0 }, { name: 'impressions', type: 'number', defaultValue: 0 }, ]}, ], } ``` #### 4. InstagramSyncService ```typescript // src/lib/integrations/meta/InstagramSyncService.ts export class InstagramSyncService { constructor(payload: Payload) async syncAccount(account: SocialAccount): Promise private async syncMedia(client: InstagramClient, account: SocialAccount): Promise private async syncComments(client: InstagramClient, media: InstagramContent): Promise private async syncMentions(client: InstagramClient, account: SocialAccount): Promise private async syncStoryMentions(client: InstagramClient, account: SocialAccount): Promise } ``` ### Wichtige Hinweise 1. **Story Mentions:** Verfallen nach 24h → Sync alle 6 Stunden oder Webhooks 2. **Token Refresh:** Alle 60 Tage → Automatischen Refresh implementieren 3. **DM Scope:** `instagram_manage_messages` erfordert App-Review ### Acceptance Criteria - [ ] Media wird synchronisiert (letzte 30 Tage) - [ ] Kommentare werden importiert und analysiert - [ ] Antworten werden über API gepostet - [ ] Mentions werden erkannt und importiert - [ ] Story-Mentions werden erfasst (falls verfügbar) - [ ] Hide Comment funktioniert - [ ] Analytics Dashboard integriert --- ## Phase 2.4: TikTok Integration **Dauer:** 2-3 Tage **Abhängigkeiten:** Keine (parallel zu Meta möglich, aber API-Approval erforderlich) ### Ziel TikTok-Kommentare synchronisieren und beantworten. ### Voraussetzungen - TikTok Business Account - TikTok for Developers Zugang - **App-Genehmigung für Comment API** (WICHTIG: Frühzeitig beantragen!) ### Deliverables #### 1. TikTok OAuth ```typescript // src/lib/integrations/tiktok/oauth.ts const TIKTOK_OAUTH_CONFIG = { authorizationUrl: 'https://www.tiktok.com/v2/auth/authorize/', tokenUrl: 'https://open.tiktokapis.com/v2/oauth/token/', scopes: [ 'user.info.basic', 'video.list', 'comment.list', 'comment.list.manage', ], } export async function getAuthUrl(state: string): Promise export async function exchangeCodeForTokens(code: string): Promise export async function refreshAccessToken(refreshToken: string): Promise ``` #### 2. TikTokClient ```typescript // src/lib/integrations/tiktok/TikTokClient.ts export class TikTokClient { private accessToken: string private openId: string constructor(accessToken: string, openId: string) // Videos async getVideos(cursor?: number, maxCount?: number): Promise<{ videos: TikTokVideo[] cursor: number hasMore: boolean }> // Comments async getVideoComments(videoId: string, cursor?: number): Promise<{ comments: TikTokComment[] cursor: number hasMore: boolean }> async replyToComment(videoId: string, commentId: string, text: string): Promise // User Info async getUserInfo(): Promise } ``` #### 3. TikTok Types ```typescript // src/types/tiktok.ts export interface TikTokVideo { id: string title: string description: string create_time: number // Unix timestamp cover_image_url: string share_url: string duration: number like_count: number comment_count: number share_count: number view_count: number } export interface TikTokComment { id: string text: string create_time: number like_count: number reply_count: number user: { open_id: string display_name: string avatar_url: string } parent_comment_id?: string // Für Replies } export interface TikTokTokens { access_token: string refresh_token: string expires_in: number open_id: string scope: string } ``` #### 4. TikTokContent Collection ```typescript // src/collections/TikTokContent.ts { slug: 'tiktok-content', admin: { useAsTitle: 'title', group: 'Social Media', }, fields: [ { name: 'externalId', type: 'text', required: true, unique: true }, { name: 'socialAccount', type: 'relationship', relationTo: 'social-accounts', required: true }, { name: 'title', type: 'text' }, { name: 'description', type: 'textarea' }, { name: 'shareUrl', type: 'text' }, { name: 'coverImageUrl', type: 'text' }, { name: 'duration', type: 'number' }, { name: 'postedAt', type: 'date' }, { name: 'stats', type: 'group', fields: [ { name: 'views', type: 'number', defaultValue: 0 }, { name: 'likes', type: 'number', defaultValue: 0 }, { name: 'comments', type: 'number', defaultValue: 0 }, { name: 'shares', type: 'number', defaultValue: 0 }, ]}, ], } ``` ### Wichtige Hinweise 1. **API-Zugang:** Comment API erfordert App-Review (1-4 Wochen) 2. **Sandbox Mode:** Erst in Sandbox testen 3. **Cursor-based Pagination:** Kein Offset-Support 4. **Kein DM-Zugang:** TikTok API erlaubt keine DMs 5. **Rate Limits:** 100 Requests/Minute ### Acceptance Criteria - [ ] OAuth-Flow funktioniert - [ ] Videos werden synchronisiert - [ ] Kommentare werden importiert und analysiert - [ ] Antworten können gepostet werden - [ ] Analytics integriert --- ## Phase 2.5a: Auto-Reply Service **Dauer:** 2-3 Tage **Abhängigkeiten:** Mindestens eine Social Platform integriert (YouTube reicht) ### Ziel Backend-Logik für vollautomatische Antworten basierend auf konfigurierbaren Regeln. ### Architektur ``` ┌─────────────────────────────────────────────────────────────────┐ │ AUTO-REPLY FLOW │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ New Comment ──▶ Claude Analysis ──▶ Safety Check │ │ │ │ │ ┌────────────┴────────────┐ │ │ ▼ ▼ │ │ [SAFE TO AUTO-REPLY] [MANUAL QUEUE] │ │ │ │ │ ▼ │ │ Rule Matching (Priority-sorted) │ │ │ │ │ ┌───────┴───────┐ │ │ ▼ ▼ │ │ [RULE MATCH] [NO MATCH] │ │ │ │ │ │ ▼ ▼ │ │ Generate Reply Manual Queue │ │ │ │ │ ▼ │ │ Rate Limit Check │ │ │ │ │ ┌──────┴──────┐ │ │ ▼ ▼ │ │ [ALLOWED] [LIMITED] │ │ │ │ │ │ ▼ ▼ │ │ Post Reply Queue for Later │ │ │ │ │ ▼ │ │ Log & Update Stats │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ### Deliverables #### 1. AutoReplyRules Collection ```typescript // src/collections/AutoReplyRules.ts { slug: 'auto-reply-rules', admin: { useAsTitle: 'name', group: 'Community', defaultColumns: ['name', 'enabled', 'priority', 'stats.totalFired'], }, fields: [ // Basis { name: 'name', type: 'text', required: true }, { name: 'description', type: 'textarea' }, { name: 'enabled', type: 'checkbox', defaultValue: false }, // Default: AUS { name: 'priority', type: 'number', defaultValue: 100 }, // Niedriger = höher // Scope { name: 'scope', type: 'group', fields: [ { name: 'platforms', type: 'relationship', relationTo: 'social-platforms', hasMany: true }, { name: 'accounts', type: 'relationship', relationTo: 'social-accounts', hasMany: true }, { name: 'channelTypes', type: 'select', hasMany: true, options: ['corporate', 'lifestyle', 'business'] }, ] }, // Conditions (Wann feuert die Regel?) { name: 'conditions', type: 'group', fields: [ { name: 'sentiments', type: 'select', hasMany: true, options: [ { label: 'Positiv', value: 'positive' }, { label: 'Dankbarkeit', value: 'gratitude' }, { label: 'Neutral', value: 'neutral' }, { label: 'Frage', value: 'question' }, ]}, { name: 'minConfidence', type: 'number', defaultValue: 80, min: 0, max: 100 }, { name: 'keywordsInclude', type: 'array', fields: [{ name: 'keyword', type: 'text' }] }, { name: 'keywordsExclude', type: 'array', fields: [{ name: 'keyword', type: 'text' }] }, { name: 'topicsInclude', type: 'array', fields: [{ name: 'topic', type: 'text' }] }, { name: 'topicsExclude', type: 'array', fields: [{ name: 'topic', type: 'text' }] }, { name: 'maxMessageLength', type: 'number', defaultValue: 300 }, ] }, // Sicherheits-Ausschlüsse (NIEMALS überschreiben!) { name: 'safetyExclusions', type: 'group', admin: { description: '⚠️ Diese Ausschlüsse können nicht deaktiviert werden!' }, fields: [ { name: 'excludeMedicalQuestions', type: 'checkbox', defaultValue: true, admin: { readOnly: true } }, { name: 'excludeEscalations', type: 'checkbox', defaultValue: true, admin: { readOnly: true } }, { name: 'excludeNegativeSentiment', type: 'checkbox', defaultValue: true }, { name: 'excludeFrustration', type: 'checkbox', defaultValue: true }, { name: 'excludeVerifiedAccounts', type: 'checkbox', defaultValue: true }, { name: 'excludeInfluencers', type: 'checkbox', defaultValue: true }, { name: 'influencerThreshold', type: 'number', defaultValue: 10000 }, ] }, // Action { name: 'action', type: 'group', fields: [ { name: 'type', type: 'select', required: true, options: [ { label: 'Template verwenden', value: 'template' }, { label: 'AI generieren', value: 'ai_generate' }, { label: 'Template + AI personalisieren', value: 'template_ai' }, ]}, { name: 'template', type: 'relationship', relationTo: 'community-templates', admin: { condition: (data) => data?.action?.type === 'template' || data?.action?.type === 'template_ai' } }, { name: 'aiTone', type: 'select', options: ['freundlich', 'professionell', 'empathisch'], admin: { condition: (data) => data?.action?.type === 'ai_generate' || data?.action?.type === 'template_ai' } }, { name: 'delayMinutes', type: 'number', defaultValue: 2, min: 0, max: 60 }, { name: 'addSignature', type: 'checkbox', defaultValue: true }, ] }, // Rate Limits { name: 'limits', type: 'group', fields: [ { name: 'maxPerHour', type: 'number', defaultValue: 10 }, { name: 'maxPerDay', type: 'number', defaultValue: 50 }, { name: 'cooldownPerAuthor', type: 'number', defaultValue: 60, admin: { description: 'Minuten bis gleicher Autor wieder Auto-Reply bekommt' } }, ] }, // Stats { name: 'stats', type: 'group', admin: { readOnly: true }, fields: [ { name: 'totalFired', type: 'number', defaultValue: 0 }, { name: 'successCount', type: 'number', defaultValue: 0 }, { name: 'failCount', type: 'number', defaultValue: 0 }, { name: 'lastFiredAt', type: 'date' }, ] }, ], } ``` #### 2. AutoReplyLogs Collection ```typescript // src/collections/AutoReplyLogs.ts { slug: 'auto-reply-logs', admin: { group: 'Community', defaultColumns: ['interaction', 'rule', 'success', 'createdAt'], }, fields: [ { name: 'interaction', type: 'relationship', relationTo: 'community-interactions', required: true }, { name: 'rule', type: 'relationship', relationTo: 'auto-reply-rules', required: true }, { name: 'decision', type: 'group', fields: [ { name: 'shouldAutoReply', type: 'checkbox' }, { name: 'reason', type: 'text' }, { name: 'blockedBy', type: 'text' }, // z.B. "safety:medical", "limit:hourly" ]}, { name: 'generatedReply', type: 'textarea' }, { name: 'postedReply', type: 'textarea' }, // Falls abweichend (z.B. gekürzt) { name: 'externalReplyId', type: 'text' }, { name: 'success', type: 'checkbox' }, { name: 'error', type: 'text' }, { name: 'processingTime', type: 'number' }, // ms { name: 'postedAt', type: 'date' }, ], } ``` #### 3. AutoReplyService ```typescript // src/lib/services/AutoReplyService.ts interface AutoReplyDecision { shouldAutoReply: boolean rule?: AutoReplyRule reason: string blockedBy?: string } interface AutoReplyResult { success: boolean replyId?: string error?: string processingTime: number } export class AutoReplyService { private payload: Payload private claudeReply: ClaudeReplyService constructor(payload: Payload) /** * Haupteinsprungspunkt: Prüft und führt Auto-Reply aus */ async processInteraction(interaction: CommunityInteraction): Promise /** * Schritt 1: Safety-Check (NIEMALS umgehen!) */ private async checkSafety(interaction: CommunityInteraction): Promise<{ safe: boolean reason?: string }> /** * Schritt 2: Finde passende Regel */ private async findMatchingRule(interaction: CommunityInteraction): Promise /** * Schritt 3: Prüfe Rate Limits */ private async checkRateLimits(rule: AutoReplyRule, authorId: string): Promise<{ allowed: boolean reason?: string }> /** * Schritt 4: Generiere Reply */ private async generateReply(interaction: CommunityInteraction, rule: AutoReplyRule): Promise /** * Schritt 5: Poste Reply */ private async postReply(interaction: CommunityInteraction, replyText: string): Promise /** * Schritt 6: Logging */ private async logResult( interaction: CommunityInteraction, rule: AutoReplyRule, decision: AutoReplyDecision, result: AutoReplyResult ): Promise } ``` #### 4. Safety Rules (KRITISCH - Nicht änderbar!) ```typescript // src/lib/services/AutoReplyService.ts - Safety Check Implementation private async checkSafety(interaction: CommunityInteraction): Promise { const flags = interaction.flags const analysis = interaction.analysis // ABSOLUTE BLOCKS - NIEMALS Auto-Reply if (flags?.isMedicalQuestion) { return { safe: false, reason: 'Medizinische Frage erkannt' } } if (flags?.requiresEscalation) { return { safe: false, reason: 'Eskalation erforderlich' } } if (interaction.status !== 'new') { return { safe: false, reason: 'Bereits bearbeitet' } } if (interaction.response?.sentAt) { return { safe: false, reason: 'Bereits beantwortet' } } // CONFIGURABLE BLOCKS (können in Rule überschrieben werden) // ... sentiment, influencer, verified, etc. return { safe: true } } ``` #### 5. Integration in Sync-Flow ```typescript // Erweitere alle CommentsSyncServices async processComment(comment: RawComment): Promise { // 1. In DB speichern const interaction = await this.saveInteraction(comment) // 2. Claude-Analyse const analysis = await this.claudeAnalysis.analyzeComment(interaction.message) await this.updateAnalysis(interaction.id, analysis) // 3. Rules Engine (bestehend) await this.rulesEngine.evaluate(interaction) // 4. Auto-Reply Check (NEU) if (this.autoReplyEnabled) { const autoReplyService = new AutoReplyService(this.payload) await autoReplyService.processInteraction(interaction) } } ``` ### Acceptance Criteria - [ ] Safety-Check blockiert medizinische Fragen IMMER - [ ] Safety-Check blockiert Eskalationen IMMER - [ ] Rules werden nach Priorität sortiert ausgewertet - [ ] Rate Limits funktionieren (per Stunde/Tag/Autor) - [ ] Logs werden vollständig geschrieben - [ ] Stats werden aktualisiert - [ ] Delay vor Antwort funktioniert --- ## Phase 2.5b: Auto-Reply UI & Testing **Dauer:** 2 Tage **Abhängigkeiten:** Phase 2.5a abgeschlossen ### Ziel Admin-UI für Auto-Reply Konfiguration und Testing. ### Deliverables #### 1. Auto-Reply Manager View ``` src/app/(payload)/admin/views/community/auto-reply/ ├── page.tsx ├── AutoReplyManager.tsx ├── components/ │ ├── RulesList.tsx │ ├── RuleEditor.tsx │ ├── RuleTester.tsx │ ├── RuleStats.tsx │ └── RecentLogs.tsx └── auto-reply.scss ``` #### 2. UI Features **Rules List:** - Alle Regeln mit Enable/Disable Toggle - Sortiert nach Priorität - Quick Stats (Fired Count, Success Rate) - Drag & Drop für Prioritäts-Änderung **Rule Editor:** - Vollständiger Regel-Editor - Condition Builder mit Preview - Action-Konfiguration - Limit-Einstellungen **Rule Tester:** ```typescript // Test-Input interface TestInput { message: string sentiment?: string platform?: string authorFollowers?: number } // Test-Output interface TestOutput { wouldAutoReply: boolean matchedRule?: string reason: string generatedReply?: string warnings: string[] } ``` **Recent Logs:** - Letzte 100 Auto-Reply Entscheidungen - Filter: Success/Failed, Rule, Platform - Details mit Interaction-Link #### 3. Analytics Integration **Neue Metriken für Dashboard:** ```typescript // /api/community/analytics/auto-reply/route.ts interface AutoReplyStats { totalProcessed: number autoReplied: number autoReplyRate: number blockedByMedical: number blockedByEscalation: number blockedByRateLimit: number topRules: Array<{ rule: string fired: number successRate: number }> avgProcessingTime: number } ``` ### Acceptance Criteria - [ ] Rules können erstellt/bearbeitet werden - [ ] Enable/Disable funktioniert - [ ] Tester zeigt korrekte Entscheidungen - [ ] Logs werden angezeigt - [ ] Analytics zeigen Auto-Reply Metriken --- ## Phase 3.0a: Scheduled Reports **Dauer:** 2-3 Tage **Abhängigkeiten:** E-Mail-Service (existiert bereits) ### Ziel Automatische Community-Reports per E-Mail. ### Deliverables #### 1. ReportSchedules Collection ```typescript // src/collections/ReportSchedules.ts { slug: 'report-schedules', admin: { useAsTitle: 'name', group: 'Community', }, fields: [ { name: 'name', type: 'text', required: true }, { name: 'enabled', type: 'checkbox', defaultValue: true }, // Schedule { name: 'frequency', type: 'select', required: true, options: [ { label: 'Täglich', value: 'daily' }, { label: 'Wöchentlich', value: 'weekly' }, { label: 'Monatlich', value: 'monthly' }, ]}, { name: 'dayOfWeek', type: 'select', options: [ { label: 'Montag', value: 'monday' }, // ... andere Tage ], admin: { condition: (data) => data?.frequency === 'weekly' }}, { name: 'dayOfMonth', type: 'number', min: 1, max: 28, admin: { condition: (data) => data?.frequency === 'monthly' }}, { name: 'time', type: 'text', defaultValue: '08:00', admin: { description: 'Format: HH:MM' }}, { name: 'timezone', type: 'text', defaultValue: 'Europe/Berlin' }, // Recipients { name: 'recipients', type: 'array', fields: [ { name: 'email', type: 'email', required: true }, { name: 'name', type: 'text' }, ]}, // Report Configuration { name: 'reportType', type: 'select', required: true, options: [ { label: 'Übersicht', value: 'overview' }, { label: 'Sentiment-Analyse', value: 'sentiment' }, { label: 'Team-Performance', value: 'response_metrics' }, { label: 'Content-Performance', value: 'content' }, { label: 'Vollständiger Report', value: 'full' }, ]}, { name: 'channels', type: 'relationship', relationTo: 'social-accounts', hasMany: true }, { name: 'format', type: 'select', options: ['pdf', 'excel', 'html_email'], defaultValue: 'pdf' }, // Stats { name: 'lastSentAt', type: 'date' }, { name: 'nextScheduledAt', type: 'date' }, { name: 'sendCount', type: 'number', defaultValue: 0 }, ], } ``` #### 2. ReportGeneratorService ```typescript // src/lib/services/ReportGeneratorService.ts export class ReportGeneratorService { async generateReport(schedule: ReportSchedule): Promise<{ content: Buffer filename: string mimeType: string }> async sendReport(schedule: ReportSchedule): Promise private async generatePdfReport(data: ReportData): Promise private async generateExcelReport(data: ReportData): Promise private async generateHtmlEmail(data: ReportData): Promise private async collectReportData(schedule: ReportSchedule): Promise } ``` #### 3. Cron Job ```typescript // src/app/(payload)/api/cron/send-reports/route.ts export async function GET(request: NextRequest) { // Auth check... const now = new Date() const dueReports = await findDueReports(now) for (const schedule of dueReports) { try { const generator = new ReportGeneratorService() await generator.sendReport(schedule) // Update nextScheduledAt await updateNextSchedule(schedule) } catch (error) { console.error(`Report ${schedule.id} failed:`, error) } } return Response.json({ success: true, sent: dueReports.length }) } ``` #### 4. vercel.json Update ```json { "crons": [ { "path": "/api/cron/youtube-sync", "schedule": "*/15 * * * *" }, { "path": "/api/cron/send-reports", "schedule": "0 * * * *" } ] } ``` ### Acceptance Criteria - [ ] Reports werden generiert (PDF/Excel/HTML) - [ ] E-Mail-Versand funktioniert - [ ] Scheduling funktioniert (daily/weekly/monthly) - [ ] Timezone-Support - [ ] Error Handling bei fehlgeschlagenem Versand --- ## Phase 3.0b: Real-time Updates **Dauer:** 2-3 Tage **Abhängigkeiten:** Keine ### Ziel Live-Updates im Dashboard ohne manuellen Refresh. ### Deliverables #### 1. Server-Sent Events Endpoint ```typescript // src/app/(payload)/api/community/stream/route.ts export async function GET(request: NextRequest) { // Auth check... const encoder = new TextEncoder() const stream = new ReadableStream({ async start(controller) { let lastCheck = new Date() const sendUpdate = async () => { try { const updates = await getUpdatesSince(lastCheck) lastCheck = new Date() if (updates.length > 0) { controller.enqueue( encoder.encode(`data: ${JSON.stringify(updates)}\n\n`) ) } } catch (error) { console.error('Stream error:', error) } } // Initial send await sendUpdate() // Poll every 5 seconds const interval = setInterval(sendUpdate, 5000) // Cleanup on close request.signal.addEventListener('abort', () => { clearInterval(interval) controller.close() }) } }) return new Response(stream, { headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', } }) } ``` #### 2. React Hook ```typescript // src/hooks/useRealtimeUpdates.ts interface Update { type: 'new_interaction' | 'status_change' | 'new_reply' data: any timestamp: string } export function useRealtimeUpdates() { const [updates, setUpdates] = useState([]) const [connected, setConnected] = useState(false) useEffect(() => { const eventSource = new EventSource('/api/community/stream') eventSource.onopen = () => setConnected(true) eventSource.onerror = () => setConnected(false) eventSource.onmessage = (event) => { const data = JSON.parse(event.data) setUpdates(prev => [...data, ...prev].slice(0, 100)) } return () => { eventSource.close() setConnected(false) } }, []) return { updates, connected } } ``` #### 3. UI Integration **Dashboard Updates:** - Live-Counter Badge bei neuen Items - Toast-Notifications bei wichtigen Events - Auto-Refresh der Liste bei neuen Items - Pulsierender Indicator wenn verbunden ### Acceptance Criteria - [ ] SSE-Verbindung funktioniert - [ ] Updates werden in Echtzeit angezeigt - [ ] Toast-Notifications bei neuen Kommentaren - [ ] Reconnect bei Verbindungsabbruch - [ ] Kein Performance-Impact bei vielen Clients --- ## Zusammenfassung der Phasen | Phase | Name | Dauer | Abhängigkeiten | Priorität | |-------|------|-------|----------------|-----------| | 2.3a | Meta OAuth | 1-2 Tage | Meta App Setup | Hoch | | 2.3b | Facebook Integration | 2-3 Tage | 2.3a | Hoch | | 2.3c | Instagram Integration | 2 Tage | 2.3a | Hoch | | 2.4 | TikTok Integration | 2-3 Tage | API Approval | Mittel | | 2.5a | Auto-Reply Service | 2-3 Tage | Keine | Mittel | | 2.5b | Auto-Reply UI | 2 Tage | 2.5a | Mittel | | 3.0a | Scheduled Reports | 2-3 Tage | Keine | Niedrig | | 3.0b | Real-time Updates | 2-3 Tage | Keine | Niedrig | **Gesamtdauer:** ~16-21 Tage --- ## Empfohlene Reihenfolge ``` Woche 1: 2.3a (Meta OAuth) → 2.3b (Facebook) + 2.3c (Instagram parallel) Woche 2: 2.5a (Auto-Reply Service) → 2.5b (Auto-Reply UI) Woche 3: 2.4 (TikTok, falls API approved) + 3.0a (Reports) Woche 4: 3.0b (Real-time) + Testing & Polish ``` --- *Erstellt: 16. Januar 2026* *Basierend auf: Community Management Roadmap Prompt (Konzept-KI)* *Erweitert um: Facebook-Integration, Logische Aufteilung* *Für: Dev-KI (Claude Code)*