cms.c2sgmbh/prompts/Community-Management-Roadmap-Extended.md
Martin Porwoll 77f70876f4 chore: add Claude Code config, prompts, and tenant setup scripts
- Add .claude/ configuration (agents, commands, hooks, get-shit-done workflows)
- Add prompts/ directory with development planning documents
- Add scripts/setup-tenants/ with tenant configuration
- Add docs/screenshots/
- Remove obsolete phase2.2-corrections-report.md
- Update pnpm-lock.yaml
- Update detect-secrets.sh to ignore setup.sh (env var usage, not secrets)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 10:18:05 +00:00

42 KiB

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:

// 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<string>
export async function exchangeCodeForTokens(code: string): Promise<MetaTokens>
export async function refreshAccessToken(token: string): Promise<MetaTokens>
export async function getLongLivedToken(shortLivedToken: string): Promise<string>

2. Meta Base Client

// 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<T>(
    endpoint: string,
    method?: 'GET' | 'POST' | 'DELETE',
    params?: Record<string, any>
  ): Promise<T>

  async getMe(): Promise<MetaUser>
  async getPages(): Promise<FacebookPage[]>
  async getInstagramAccounts(pageId: string): Promise<InstagramAccount[]>
}

3. Types

// 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

// 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

# .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

// 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<FacebookPost[]>
  async getPostComments(postId: string, limit?: number): Promise<MetaComment[]>

  // Comments
  async replyToComment(commentId: string, message: string): Promise<string>
  async hideComment(commentId: string): Promise<void>
  async unhideComment(commentId: string): Promise<void>
  async deleteComment(commentId: string): Promise<void>
  async likeComment(commentId: string): Promise<void>

  // Page Messages (Messenger)
  async getConversations(limit?: number): Promise<FacebookConversation[]>
  async getMessages(conversationId: string): Promise<FacebookMessage[]>
  async sendMessage(recipientId: string, message: string): Promise<string>

  // Page Info
  async getPageInsights(metrics: string[], period: string): Promise<PageInsight[]>
}

2. Facebook Types

// 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

// 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

// src/lib/integrations/meta/FacebookSyncService.ts

export class FacebookSyncService {
  constructor(payload: Payload)

  async syncAccount(account: SocialAccount): Promise<SyncResult>

  private async syncPosts(client: FacebookClient, account: SocialAccount): Promise<number>
  private async syncComments(client: FacebookClient, post: FacebookContent): Promise<number>
  private async syncMessages(client: FacebookClient, account: SocialAccount): Promise<number>
  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:

const platformIcons = {
  youtube: <YouTubeIcon />,
  facebook: <FacebookIcon />,
  instagram: <InstagramIcon />,
  tiktok: <TikTokIcon />,
}

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

// 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<InstagramMedia[]>
  async getMediaComments(mediaId: string): Promise<MetaComment[]>

  // Comments
  async replyToComment(commentId: string, message: string): Promise<string>
  async hideComment(commentId: string): Promise<void>
  async deleteComment(commentId: string): Promise<void>

  // Mentions & Tags
  async getMentions(): Promise<InstagramMention[]>
  async getTaggedMedia(): Promise<InstagramMedia[]>

  // Stories (Mentions)
  async getStoryMentions(): Promise<InstagramStoryMention[]>

  // DMs (wenn Scope verfügbar)
  async getConversations(): Promise<InstagramConversation[]>
  async sendMessage(conversationId: string, message: string): Promise<string>

  // Account Info
  async getAccountInsights(metrics: string[], period: string): Promise<AccountInsight[]>
}

2. Instagram Types

// 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

// 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

// src/lib/integrations/meta/InstagramSyncService.ts

export class InstagramSyncService {
  constructor(payload: Payload)

  async syncAccount(account: SocialAccount): Promise<SyncResult>

  private async syncMedia(client: InstagramClient, account: SocialAccount): Promise<number>
  private async syncComments(client: InstagramClient, media: InstagramContent): Promise<number>
  private async syncMentions(client: InstagramClient, account: SocialAccount): Promise<number>
  private async syncStoryMentions(client: InstagramClient, account: SocialAccount): Promise<number>
}

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

// 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<string>
export async function exchangeCodeForTokens(code: string): Promise<TikTokTokens>
export async function refreshAccessToken(refreshToken: string): Promise<TikTokTokens>

2. TikTokClient

// 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<string>

  // User Info
  async getUserInfo(): Promise<TikTokUser>
}

3. TikTok Types

// 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

// 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

// 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

// 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

// 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<AutoReplyResult | null>

  /**
   * 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<AutoReplyRule | null>

  /**
   * 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<string>

  /**
   * Schritt 5: Poste Reply
   */
  private async postReply(interaction: CommunityInteraction, replyText: string): Promise<string>

  /**
   * Schritt 6: Logging
   */
  private async logResult(
    interaction: CommunityInteraction,
    rule: AutoReplyRule,
    decision: AutoReplyDecision,
    result: AutoReplyResult
  ): Promise<void>
}

4. Safety Rules (KRITISCH - Nicht änderbar!)

// src/lib/services/AutoReplyService.ts - Safety Check Implementation

private async checkSafety(interaction: CommunityInteraction): Promise<SafetyResult> {
  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

// Erweitere alle CommentsSyncServices

async processComment(comment: RawComment): Promise<void> {
  // 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:

// 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:

// /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

// 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

// src/lib/services/ReportGeneratorService.ts

export class ReportGeneratorService {
  async generateReport(schedule: ReportSchedule): Promise<{
    content: Buffer
    filename: string
    mimeType: string
  }>

  async sendReport(schedule: ReportSchedule): Promise<void>

  private async generatePdfReport(data: ReportData): Promise<Buffer>
  private async generateExcelReport(data: ReportData): Promise<Buffer>
  private async generateHtmlEmail(data: ReportData): Promise<string>

  private async collectReportData(schedule: ReportSchedule): Promise<ReportData>
}

3. Cron Job

// 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

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

// 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

// src/hooks/useRealtimeUpdates.ts

interface Update {
  type: 'new_interaction' | 'status_change' | 'new_reply'
  data: any
  timestamp: string
}

export function useRealtimeUpdates() {
  const [updates, setUpdates] = useState<Update[]>([])
  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)