Skip to main content

Dispatch Incoming and Workflow

Process

  1. Webhook POST /api/dispatch/inbound creates a DispatchItem and triggers the AI Analysis (/api/dispatch/[id]/analyze).

  2. The AI fills in the following: Triage (entry category, whether the Dev Team is needed, structured Dev Handoff, next steps for MEC, questions for the sender) and, if editorial guidance is needed: content type, Center Assignment (centerIds in order of plausibility, centerMatchNote, centerMatchAmbiguous), channels, Responsibility (User-ID), deadlines, urgency, teaser, Social Caption (which replaces manual follow-ups and Gmail tags). The center list in the prompt is alphabetical — the model is not allowed to arbitrarily choose the first element; unknown UUIDs are discarded server-side (sanitizeAndSyncCenters).

  3. “Create Draft” generates ContentIntent + ContentDraft (source: dispatch, Status PENDING) — not direct News; the draft belongs to exactly one selected center. For multiple checked centers, the interface determines which center to create (default: most likely according to AI order in centerIds).

  4. Editors edit and approve under Workflow & Approvals (/dashboard/workflow). Deep-Link: ?highlight=<contentDraftId>. In the dashboard, Dispatch, Workflow, and Content Planner link to the same Editorial Flow (three steps, current page highlighted). Delete Draft: DELETE /api/content/drafts/[draftId] — session required; sets DispatchItem.contentDraftId to null for this draft and deletes the ContentDraft (the associated ContentIntent remains without a draft).

  5. Upon Approval, executeContentDraft creates the actual entity (e.g., News). Afterward:

    • DispatchItem.statusPUBLISHED
    • if preferredPublishAt is set: optionally ContentSchedule (News, date_range) for the Content Planner

    Fields / Prisma: Only columns explicitly set in executeContentDraft (apps/dashboard/src/app/api/content/drafts/[draftId]/route.ts) are filled — not the full dashboard forms. Offer: Draft JSON validFrom/validTo (or startDate/endDate) → Offer.startDate / Offer.endDate. Job: among other things, type from type, department or employmentType; long text from contentrequirements (no Prisma field content on the job). Shop: The Prisma model includes shopChainId, no chainSlug; the draft can contain chainSlug, chainId (UUID of the chain) or shopChainId — upon creation, it is resolved or the chain field omitted. openingHours as an object is saved as a JSON string (not "[object Object]"). Service: Draft openingHours also needs to be serialized to JSON if necessary. Missing SEO, Hero, or shop links should be added in the respective content editing view after approval.

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

  • Status: In the Assignment tab, each status from the enum can be selected and saved with Save & Assign via PATCH /api/dispatch/[id] — including Entry (INBOX), to place a case back in the entry column of the board view.

AI Analysis (Dispatch & General)

  • Email Content for AI: POST /api/dispatch/[id]/analyze pulls the plain text from bodyText; if bodyHtml (e.g., Postmark HtmlBody) is significantly longer or the plain text is just a stub, htmlToPlainText(bodyHtml) is used, so that not just the "first" plain text block is analyzed. Optional: DISPATCH_ANALYZE_MAX_BODY_CHARS (default 24,000, min 4,000, max 80,000); very long emails are shortened with head and tail and mid-section notes. For legacy models with 8k context (gpt-4 without “o”/Turbo), the email is automatically shortened more (max. 10,000 characters), and max_tokens for the response is limited to 3072 — otherwise the API returns context_length_exceeded (e.g., if max_tokens was 8192). Recommendation in AI configuration: gpt-4o-mini or similar Larger Models: up to 8192 Completion Tokens. In Development, the route returns an additional detail with the error message at 500.
  • Fields in aiSuggestion (Excerpt): intakeCategory, primaryOwner, needsDevTeam, mecNextSteps, questionsForSender, devHandoff (Title, Problem, URLs, Repro, suspectedLayer, Priority), centerIds / centerNames (multiple hits possible, order = best guess first), centerMatchNote (justification from the email), centerMatchAmbiguous, plus existing content fields (type news/offer/event or none if no post). Goal: small MEC team can categorize emails without lengthy investigations. Additionally optional customerCommunication: structured suggestion for personal feedback to the sender (subject, email text, channel note) — transferred to ContentDraft.data upon "Create Draft," so that the supervisor does not lose track of relationship management.
  • Manual Workflow (without new DB column): Under aiSuggestion.workflowhandoffToDev (boolean), handoffToDevAt (ISO, set upon first activation), handoffNote (optional). Saved via PATCH /api/dispatch/[id] with body workflowPatch; upon Re-analysis, the workflow remains through merge (see dispatch-workflow.ts).
  • Dispatch Overview: Filter by triage category (intakeCategory), "Dev needed / handed over" combines needsDevTeam or workflow.handoffToDev.
  • Dispatch: POST /api/dispatch/[id]/analyze utilizes the global AI configuration (getAIConfig) and the central HTTP client openAIChatCompletion (apps/dashboard/src/lib/openai-chat.ts). Empty or relative baseUrl in the DB would previously lead to fetch("/chat/completions") — the client normalizes to https://api.openai.com/v1 or OPENAI_API_BASE_URL. If the configured model does not support OpenAI’s JSON Mode (response_format: json_object, e.g., older gpt-4), a second request without JSON Mode is automatically executed; the response is parsed as plaintext in JSON (including Markdown code blocks).
  • General (Dashboard): POST /api/ai/chat – session required, body: messages[], optional centerId, model, temperature, max_tokens, response_format. Response: { success, content }.

Environment

  • DISPATCH_WEBHOOK_SECRET – optional, header X-Dispatch-Secret for inbound and possibly internal triggers.

Legacy

Older entries may still lead with contentDraftId as a former News ID; new entries use the ContentDraft-ID until approval, after which the ID may be updated to the published content ID.

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