Zum Hauptinhalt springen

Dispatch-Eingang und Workflow

Ablauf

  1. Webhook POST /api/dispatch/inbound legt ein DispatchItem an und stößt die KI-Analyse an (/api/dispatch/[id]/analyze).

  2. Die KI füllt u. a. vor: Triage (Eingangskategorie, ob das Dev-Team nötig ist, strukturierte Dev-Übergabe, nächste Schritte für MEC, Rückfragen an den Absender) sowie bei redaktionellem Bedarf: Inhaltstyp, Center-Zuordnung (centerIds in Reihenfolge der Plausibilität, centerMatchNote, centerMatchAmbiguous), Kanäle, Zuständigkeit (User-ID), Fristen, Dringlichkeit, Teaser, Social-Caption (ersetzt manuelles Nachhaken und Gmail-Tags). Die Center-Liste im Prompt ist alphabetisch — das Modell darf nicht willkürlich das erste Element wählen; unbekannte UUIDs werden serverseitig verworfen (sanitizeAndSyncCenters).

  3. „Entwurf erstellen“ erzeugt ContentIntent + ContentDraft (source: dispatch, Status PENDING) — kein direktes News; der Entwurf gehört genau einem gewählten Center. Bei mehreren angehakten Centern legt die Oberfläche fest, für welches Center angelegt wird (Standard: wahrscheinlichstes laut KI-Reihenfolge in centerIds).

  4. Redakteure bearbeiten und genehmigen unter Workflow & Freigaben (/dashboard/workflow). Deep-Link: ?highlight=<contentDraftId>. Im Dashboard verlinken Dispatch, Workflow und Content Planner denselben Redaktionsfluss (drei Schritte, aktuelle Seite markiert). Entwurf löschen: DELETE /api/content/drafts/[draftId] — Session erforderlich; setzt DispatchItem.contentDraftId für diesen Entwurf auf null und löscht den ContentDraft (der verknüpfte ContentIntent bleibt ohne Entwurf bestehen).

  5. Bei Genehmigung legt executeContentDraft die echte Entität an (z. B. News). Anschließend:

    • DispatchItem.statusPUBLISHED
    • bei gesetztem preferredPublishAt: optional ContentSchedule (News, date_range) für den Content Planner

    Felder / Prisma: Es werden nur die in executeContentDraft (apps/dashboard/src/app/api/content/drafts/[draftId]/route.ts) explizit gesetzten Spalten befüllt — nicht die vollen Dashboard-Masken. Offer: Entwurf-JSON validFrom/validTo (oder startDate/endDate) → Offer.startDate / Offer.endDate. Job: u. a. type aus type, department oder employmentType; langer Text aus contentrequirements (kein Prisma-Feld content am Job). Shop: Das Prisma-Modell hat shopChainId, kein chainSlug; im Entwurf können chainSlug, chainId (UUID der Kette) oder shopChainId stehen — beim Anlegen wird aufgelöst bzw. das Ketten-Feld weggelassen. openingHours als Objekt wird als JSON-String gespeichert (nicht "[object Object]"). Service: Entwurf openingHours ebenfalls JSON-serialisieren wenn nötig. Fehlende SEO-, Hero- oder Shop-Verknüpfungen nach Freigabe in der jeweiligen Content-Bearbeiten-Ansicht ergänzen.

Dispatch-Detail (/dashboard/dispatch/[id])

  • Status: In der Registerkarte Zuordnung ist jeder Status aus dem Enum wählbar und wird mit Speichern & Zuweisen per PATCH /api/dispatch/[id] gespeichert — inkl. Eingang (INBOX), um einen Fall wieder in die Eingangs-Spalte der Board-Ansicht zu legen.

KI-Analyse (Dispatch & allgemein)

  • E-Mail-Inhalt für die KI: POST /api/dispatch/[id]/analyze zieht den Klartext aus bodyText; ist bodyHtml (z. B. Postmark HtmlBody) deutlich länger oder der Plaintext nur ein Stub, wird htmlToPlainText(bodyHtml) verwendet, damit nicht nur der «erste» Plaintext-Block analysiert wird. Optional: DISPATCH_ANALYZE_MAX_BODY_CHARS (Standard 24 000, min 4 000, max 80 000); sehr lange Mails werden mit Kopf+Schwanz und Mittelteil-Hinweis gekürzt. Bei Legacy-Modellen mit 8k-Kontext (gpt-4 ohne „o“/Turbo) wird die Mail automatisch stärker gekürzt (max. 10 000 Zeichen), und max_tokens für die Antwort auf 3072 begrenzt — sonst liefert die API context_length_exceeded (z. B. wenn max_tokens 8192 gesetzt war). Empfehlung in der KI-Konfiguration: gpt-4o-mini o. Ä. Größere Modelle: bis 8192 Completion-Tokens. In Development liefert die Route bei 500 zusätzlich detail mit der Fehlermeldung.
  • Felder in aiSuggestion (Auszug): intakeCategory, primaryOwner, needsDevTeam, mecNextSteps, questionsForSender, devHandoff (Titel, Problem, URLs, Repro, suspectedLayer, Priorität), centerIds / centerNames (Mehrfachtreffer möglich, Reihenfolge = beste Vermutung zuerst), centerMatchNote (Begründung aus Mail), centerMatchAmbiguous, dazu die bisherigen Content-Felder (type news/offer/event oder none wenn kein Post). Ziel: kleines MEC-Team kann Mails ohne langes Ermitteln zuordnen. Zusätzlich optional customerCommunication: strukturierter Vorschlag für persönliche Rückmeldung an den Absender (Betreff, E-Mail-Text, Kanalhinweis) — wird bei „Entwurf erstellen“ in ContentDraft.data übernommen, damit Betreuer die Beziehungspflege nicht verlieren.
  • Manueller Workflow (ohne neue DB-Spalte): Unter aiSuggestion.workflowhandoffToDev (boolean), handoffToDevAt (ISO, gesetzt beim ersten Aktivieren), handoffNote (optional). Wird über PATCH /api/dispatch/[id] mit Body workflowPatch gespeichert; bei Re-Analyse bleibt workflow durch Merge erhalten (siehe dispatch-workflow.ts).
  • Dispatch-Übersicht: Filter nach Triage-Kategorie (intakeCategory), „Dev nötig / übergeben“ kombiniert needsDevTeam oder workflow.handoffToDev.
  • Dispatch: POST /api/dispatch/[id]/analyze nutzt die globale KI-Konfiguration (getAIConfig) und den zentralen HTTP-Client openAIChatCompletion (apps/dashboard/src/lib/openai-chat.ts). Leere oder relative baseUrl in der DB würden früher zu fetch("/chat/completions") führen – der Client normalisiert auf https://api.openai.com/v1 bzw. OPENAI_API_BASE_URL. Unterstützt das konfigurierte Modell keinen OpenAI-JSON-Mode (response_format: json_object, z. B. älteres gpt-4), wird automatisch ein zweiter Aufruf ohne JSON-Mode ausgeführt; die Antwort wird wie Klartext in JSON geparst (inkl. Markdown-Codeblöcken).
  • Allgemein (Dashboard): POST /api/ai/chat – Session erforderlich, Body: messages[], optional centerId, model, temperature, max_tokens, response_format. Antwort: { success, content }.

Umgebung

  • DISPATCH_WEBHOOK_SECRET – optional, Header X-Dispatch-Secret für Inbound und ggf. interne Trigger.

Legacy

Ältere Einträge können contentDraftId noch als frühere News-ID führen; neue Einträge verwenden die ContentDraft-ID bis zur Freigabe, danach wird die ID ggf. auf die veröffentlichte Content-ID aktualisiert.

Nutzungsstatistik: Seitenaufrufe werden anonymisiert erfasst. Im Umami-Dashboard nach diesem Pfad filtern: /developer-guide/dispatch-und-workflow