17. Instagram đ§
Implementiert, aber ohne konfigurierte Meta-App noch nicht produktiv nutzbar. Der
gesamte Code-Pfad (Konto-Verbindung, Content Studio, Kommentar-zu-DM-Automation, Inbox,
CRM-VerknĂŒpfung) ist gebaut, getestet und lauffĂ€hig â was fehlt, ist eine echte, im Meta
Developer Dashboard angelegte und von Meta freigegebene App (INSTAGRAM_APP_ID/
INSTAGRAM_APP_SECRET/INSTAGRAM_OAUTH_STATE_SECRET/INSTAGRAM_VERIFY_TOKEN als
Umgebungsvariablen). Solange diese fehlen, zeigt die OberflĂ€che ehrlich âMeta-Verbindung
erforderlich"/âBerechtigung fehlt" statt eine Verbindung oder Veröffentlichung vorzutĂ€uschen.
Die Verbindung lĂ€uft ĂŒber den direkten Instagram-Login (Business Login for Instagram) â keine Facebook-Seite nötig. Das ersetzt einen frĂŒheren Facebook-Login-for-Business-Ansatz vollstĂ€ndig.
Was existiert
| Bereich | Route | Funktion |
|---|---|---|
| Konto verbinden | /instagram/einstellungen | Direkter Instagram-Login, Status/Token/Berechtigungsanzeige, Trennen |
| Content erstellen | /instagram | Ăbersicht aller EntwĂŒrfe (Filter/Suche/Sortierung), âNeuer Entwurf" |
| Entwurf bearbeiten | /instagram/entwurf/:id | Medien-Upload, Caption/Hashtags/CTA, KI-Vorbereitung (echt + Mock-Vorschau), Live-Vorschau, Speichern/Planen/Veröffentlichen |
| Content Kalender | /instagram/kalender | Monatskalender + Liste geplanter BeitrÀge |
| Veröffentlichte BeitrÀge | /instagram/veroeffentlicht | Liste bereits veröffentlichter BeitrÀge |
| Automationen | /instagram/automationen, /instagram/automationen/:id | Kommentar-zu-DM-Automation pro Beitrag/Reel: Keyword-Regeln, Antworttext mit Variablen, PDF-Auswahl, Live-DM-Vorschau, Ereignis-Logs |
| Inbox | /instagram/inbox | Alle Kommentar-/DM-Ereignisse, Filter nach Status/Automation, Verlinkung zum verknĂŒpften CRM-Kontakt |
Backend: src/lib/instagram-*.server.ts/*.functions.ts, OAuth-Callback unter
/api/public/oauth/instagram/callback, Webhook-Empfang unter /api/public/instagram/webhook,
Datenmodell in den Migrationen 20261103090000_..._instagramkern001.sql,
20261104090000_..._instagramcontentstudio001.sql, 20261105090000_..._instagramcrminbox001.sql.
Berechtigungen (direkter Instagram-Login)
PRONTO nutzt fĂŒr Instagram eine eigene, von WhatsApp getrennte Meta-App (eigene
App-Review-Einreichung, eigene Env-Vars). Angeforderte Scopes und wofĂŒr sie jeweils
gebraucht werden â keine pages_*-Scopes mehr nötig, da keine Facebook-Seite mehr
im Spiel ist:
| Berechtigung | WofĂŒr |
|---|---|
instagram_business_basic | Grundzugriff auf das verbundene Instagram-Professional-Konto (Username, Account-ID, Profilbild) |
instagram_business_manage_comments | Eingehende Kommentare per Webhook empfangen, fĂŒr die Keyword-Automation lesen, private Antworten auf Kommentare senden |
instagram_business_manage_messages | Direktnachrichten allgemein â Webhook-Feld messages (Quick-Reply-Button-Klicks empfangen) und Folge-DMs im Buttons-Antwortmodus senden |
instagram_business_content_publish | BeitrÀge direkt aus dem Content Studio auf Instagram veröffentlichen |
Keine dieser Berechtigungen wird fĂŒr Funktionen angefordert, die sie nicht tatsĂ€chlich
brauchen â insbesondere: kein instagram_business_manage_insights, kein Zugriff auf
Facebook-Seiten-Inhalte (es gibt keine mehr im Spiel).
OAuth-Flow (direkter Instagram-Login, kein Facebook JS SDK)
Klassischer serverseitiger Redirect-Flow â strukturell identisch zur bestehenden
Google-/Zoom-Anbindung (google-oauth.server.ts), nicht mehr zum WhatsApp-Popup-Muster:
- âMit Instagram verbinden" auf
/instagram/einstellungenruftstartInstagramConnectauf (liefert eine signierte, 10 Minuten gĂŒltigestate-URL) und leitet den Browser direkt aufhttps://www.instagram.com/oauth/authorizeweiter â kein SDK, kein Popup. - Instagram leitet nach Zustimmung auf
/api/public/oauth/instagram/callback?code=âŠzurĂŒck. - Server tauscht den Code serverseitig gegen einen kurzlebigen (~1 Std.) Instagram-
User-Token â liefert direkt die Instagram-User-ID und die tatsĂ€chlich gewĂ€hrten
Berechtigungen mit (kein separater
debug_token-Call mehr nötig). - Server tauscht gegen einen langlebigen Token (~60 Tage).
- Server liest Username/Profilbild direkt vom Instagram-Account (kein Umweg ĂŒber
Facebook-Seiten mehr) und meldet das Konto fĂŒr Kommentar-Webhooks an
(
POST graph.instagram.com/{ig-user-id}/subscribed_apps). - Token wird unverschlĂŒsselt in
instagram_accountsgespeichert â siehe Sicherheitshinweis unten. - âVerbindung testen" prĂŒft den gespeicherten Token per Live-API-Call, âTrennen" löscht
ihn und markiert den Datensatz als
disconnected.
Alle Daten-/Content-/Messaging-Calls laufen ĂŒber den Host graph.instagram.com (statt
graph.facebook.com beim vorherigen Facebook-Login-Ansatz).
Webhook-Flow
POST /api/public/instagram/webhook (Feld comments, siehe instagram-webhook.server.ts)
â unverĂ€ndert gegenĂŒber dem vorherigen Ansatz, da das Webhook-Payload-Format
login-methoden-unabhÀngig ist:
- Meta-GET-Verifizierung gegen
INSTAGRAM_VERIFY_TOKENbeim Einrichten der Subscription. - Jeder eingehende POST wird zuerst roh und idempotent in
instagram_webhook_eventsgespeichert (Unique-Constraint auf einen Payload-Hash), bevor irgendetwas verarbeitet wird â schĂŒtzt vor Replay/Doppelverarbeitung bei Meta-Retries. - Pro Kommentar-Change einzeln verarbeitet (ein defekter Eintrag blockiert nie den Rest desselben Aufrufs); eigene Kommentare des Kontos werden ignoriert (keine Endlosschleife).
- Bei Keyword-Treffer gegen eine aktive Automation: CRM-VerknĂŒpfung
(
instagram-crm.server.ts) â DM-Versand (instagram-dm-versand.server.ts, Credit-Abzug vor dem Versand) â Ereignis-Status wird ehrlich fortgeschrieben (sent/failed/permission_missing/blocked/rate_limitedâ nie ein vorgetĂ€uschter Erfolg).
Die Webhook-Anmeldung selbst lÀuft jetzt anders als zuvor: statt einer rein manuellen
Konfiguration auf Facebook-Seiten-Ebene im Meta-Dashboard meldet PRONTO jedes verbundene
Konto direkt per API an (abonniereWebhook() in instagram-oauth.server.ts, Schritt 5 im
OAuth-Flow oben) â FehlschlĂ€ge dabei blockieren die Verbindung nicht, werden der
Verbindungskarte aber als Warnung angezeigt.
Private Reply / DM-Versand
sendeInstagramPrivateReply() (instagram-dm.server.ts) ruft
POST https://graph.instagram.com/{ig-user-id}/messages mit
{"recipient":{"comment_id":"âŠ"},"message":{"text":"âŠ"}} auf â echte Implementierung,
kein Platzhalter: liefert "sent" ausschlieĂlich, wenn Meta den Versand mit einer
message_id bestÀtigt. Fehler werden nach Status/Meldung eingeordnet (Berechtigung fehlt,
7-Tage-Antwortfenster abgelaufen, Rate-Limit, sonstiger Fehler) â nie stillschweigend als
Erfolg gewertet.
Antwortmöglichkeiten (Buttons) statt eines einzelnen Texts
Jede Automation kann statt eines einzelnen Antworttexts mehrere auswÀhlbare
Antwortmöglichkeiten anbieten (instagram_automations.antwort_modus = 'buttons',
Tabelle instagram_automation_antworten, UI unter /instagram/automationen/$id). Jede
Option hat einen eigenen Button-Titel (max. 20 Zeichen), einen eigenen Antworttext und
einen eigenen Inhalt (Text/PDF/Link/Bild).
Technisch nutzt das Instagrams Quick Replies (offiziell dokumentiert unter
developers.facebook.com/docs/messenger-platform/instagram/features/quick-replies, max. 13
Buttons):
- Bei Keyword-Treffer sendet
sendeInstagramQuickReplies()(instagram-dm.server.ts) eine Private Reply mitmessage.quick_replies(ein Eintrag pro Antwortmöglichkeit,payload= die jeweiligeinstagram_automation_antworten.idâ opak, keine zusĂ€tzliche Zuordnungstabelle nötig). - Klickt der Nutzer einen Button, sendet Meta ein Webhook-Event im Feld
messaging(nichtcomments) mitmessage.quick_reply.payloadâ dafĂŒr ist die Webhook-Subscription jetzt aufsubscribed_fields=comments,messageserweitert (abonniereWebhook()), was die Berechtigunginstagram_business_manage_messagesvoraussetzt. verarbeiteEinzelnenButtonKlick()(instagram-webhook.server.ts) liest die Option per ID, lĂ€dt ihren Inhalt (signierter PDF-/Bild-Link oder freier Link) und schickt ihn persendeInstagramDirectMessage()als Folge-DM direkt an den Absender (recipient.id, nichtrecipient.comment_idâ dafĂŒr gilt Metas allgemeines 24-Stunden-Antwortfenster, nicht das 7-Tage-Fenster der ursprĂŒnglichen Kommentarantwort).
FĂŒr den App-Review-Tester: TestfĂ€lle
- Instagram-Professional-Konto unter
/instagram/einstellungendirekt verbinden (keine Facebook-Seite nötig) â Status wechselt auf âVerbunden", zeigt Username/Profilbild/Account-ID/erteilte Berechtigungen. - Unter
/instagram/automationenâNeue Automation" â Beitrag/Reel auswĂ€hlen (Button âVon Instagram laden" synchronisiert die Post-Liste ĂŒber die Graph API) â Keyword (z. B. âPDF") + Antworttext + optional PDF hinterlegen â Status auf âAktiv" setzen. - Als Test-Nutzer einen Kommentar mit dem Keyword auf dem gewĂ€hlten Beitrag hinterlassen.
- Innerhalb weniger Sekunden erscheint eine private Instagram-Direktnachricht mit dem konfigurierten Text/Link beim kommentierenden Nutzer.
- In PRONTO unter
/instagram/inboxerscheint das Ereignis mit Status âGesendet", der erkannten Keyword, und einem Link zum automatisch angelegten CRM-Kontakt. - Unter
/instagram/automationen/:idlĂ€sst sich die Automation jederzeit pausieren (âPausieren"-Button) â danach reagiert sie auf neue Kommentare nicht mehr. - Content Studio: unter
/instagrameinen Entwurf mit Bild + Caption anlegen, unter/instagram/entwurf/:idâDirekt veröffentlichen" â landet als echter Beitrag auf dem verbundenen Instagram-Konto (nur Einzelbild-Format automatisch unterstĂŒtzt, siehe unten).
Bekannte EinschrÀnkungen
- Nur Einzelbild-Veröffentlichung ist ĂŒber die Graph API automatisiert umgesetzt; Carousel/Reel/Story zeigen im Content Studio einen klaren Hinweis, dass die Veröffentlichung manuell auf Instagram erfolgen muss (mehrstufige Container/ Video-Verarbeitung wĂ€ren ein eigenstĂ€ndiger, gröĂerer Ausbauschritt).
- Token-VerschlĂŒsselung: Access-Tokens liegen wie beim bestehenden WhatsApp-Modul im Klartext in der Datenbank (RLS + ausschlieĂlich service_role-Zugriff, nie ans Frontend ausgegeben) â eine echte VerschlĂŒsselungsschicht existiert projektweit nicht und wurde hier bewusst nicht isoliert nur fĂŒr Instagram nachgerĂŒstet (siehe 25-security.md).
- Kein automatischer Token-Refresh:
aktualisiereInstagramToken()(Refresh-Funktion) ist implementiert, aber noch nicht an einen Cron-Job angebunden â lĂ€uft der langlebige Token nach ~60 Tagen ab, zeigt die Verbindungskarte âVerbindung abgelaufen", Nutzer verbinden manuell neu (identisch zum bestehenden WhatsApp-Verhalten).
Datenschutz-/Nutzungsbedingungen-Anforderungen (fĂŒr die App-Review-Einreichung)
Meta verlangt bei der App-Review-Einreichung fĂŒr jede der oben genannten Berechtigungen:
- Eine öffentlich erreichbare DatenschutzerklÀrung, die explizit beschreibt, dass Instagram-Kommentartext, Nutzername und Nutzer-ID verarbeitet werden, um automatisierte Direktnachrichten zu versenden, sowie wie lange diese Daten aufbewahrt werden.
- Eine öffentlich erreichbare Nutzungsbedingungen-Seite, die den Instagram- Automationsdienst als Teil des Angebots benennt.
- Eine Löschmöglichkeit auf Anfrage (Data Deletion Request Callback URL oder gleichwertiger Prozess) â aktuell nicht separat fĂŒr Instagram implementiert; die bestehende âTrennen"-Funktion löscht den Access-Token, aber keine historischen Kommentar-/Nachrichtenereignisse oder Lead-DatensĂ€tze automatisch. Das ist eine offene LĂŒcke, die vor der tatsĂ€chlichen App-Review-Einreichung geschlossen werden muss.
- Ein Demo-Video, das exakt die TestfĂ€lle oben zeigt (Verbindung â Automation einrichten â Kommentar â private DM â Inbox-Eintrag).
Offene manuelle Schritte (Meta-Konfiguration)
- Im Meta Developer Dashboard eine neue, separate App anlegen und das Produkt âInstagram" hinzufĂŒgen (nicht âFacebook Login for Business").
- Unter âBusiness Login" die Redirect-URI exakt eintragen:
https://<domain>/api/public/oauth/instagram/callback. INSTAGRAM_APP_ID,INSTAGRAM_APP_SECRET(Werte des Instagram-Produkts, nicht einer Facebook-App),INSTAGRAM_OAUTH_STATE_SECRET(beliebiger zufĂ€lliger String, nur fĂŒr die CSRF-Signatur) undINSTAGRAM_VERIFY_TOKENals Umgebungsvariablen hinterlegen (Vercel-Projekteinstellungen).- App-Review fĂŒr
instagram_business_manage_comments,instagram_business_manage_messages,instagram_business_content_publisheinreichen (Datenschutz/ToS/Demo-Video wie oben, ĂŒblich 2â4 Wochen Bearbeitungszeit bei Meta). - Bis zur Freigabe: App im Entwicklungsmodus mit bis zu 25 Test-Nutzern (unter den App-Rollen im Dashboard hinzugefĂŒgt) vollstĂ€ndig nutzbar â das reicht fĂŒr alle TestfĂ€lle oben. Die Webhook-Subscription passiert automatisch beim Verbinden (Schritt 5 im OAuth-Flow), keine manuelle Page-Konfiguration mehr nötig.
