1.7.5
⚙️ Patch 1.7.5 — Tickets AI workflow v2 (n8n payload, live updates, agents)¶
🚀 Summary¶
- Tickets n8n integration upgraded: lean webhook payload with conversation context, order IDs, attachment proxy URLs, and optional PDF drafts from n8n callbacks.
- Live UI updates via WebSocket (
/api/v1/tickets/ws) — replaces pollingGET /ai-responseswhile waiting for n8n. - Six specialist n8n agents documented (German system prompts): damaged, wrong/missing, delivery, order, refund/return, general — see
docs/docs/services/service_tickets/n8n-agent-prompts.md. - Messages UI shows inbound customer messages only; shop replies appear on the AI draft side. Editable issue category per ticket.
- Per-message response sync (
ticket_message_responses) and closed-ticket training pairs for future AI training. - Plenty send supports PDF attachments from n8n drafts; reply payload matches Plenty backend UI shape.
✨ Improvements¶
Tickets — n8n webhook payload¶
build_generate_webhook_payloadsends a deduplicated structure:ticket— title, plain-text body,external_order_id,order_id, customer emails, target attachments.conversation[]— inbound customer messages only (oldest first), each with optionalai_responsefor prior replies.- Shop/outbound messages (
newReplyFromUser,from.type=user,linkedTo) are not duplicated as conversation entries. external_order_idparsed from titles likeAuftrags-Nr. cbn4sv9bdx (ID: #22999668)and fromconversation_relations.issue_categoriesremoved from webhook — routing happens entirely in n8n.- Cached messages:
POST /workflow/generateaccepts optionalcached_messagesfrom the UI to skip a second full Plenty history fetch. - Attachment proxy for n8n:
GET /webhooks/n8n/attachments/{message_uuid}and.../{filename}withX-API-KEY(Plenty ZIP extracted server-side).
Tickets — n8n callback & PDF attachments¶
- Callback accepts optional
attachmentsarray (name,contentType,content_base64). - Stored on
tickets.ai_response_attachments(JSON text) until send; UI shows attachment chips without exposing base64. - Send to Plenty includes attachments in the messenger POST payload.
- JSON-string coercion for
attachmentswhen n8n sends the array as a string (common HTTP Request quirk).
Tickets — WebSocket live draft updates¶
- Endpoints:
/wsand/api/v1/tickets/ws(public, no JWT). - Broadcast on: workflow generate start (
generating), n8n callback (draft/error), trigger failures. - Message:
{ "type": "ai_draft_update", "ticket_uuid": "...", "draft": { ... } }. - Frontend
ticketAiDraft.jssubscribes once;TicketsTabapplies updates without interval polling.
Tickets — UI & categories¶
- Left column: inbound customer messages only (
from.type=useroutbound filtered). - Right column: AI draft per message; category dropdown (12 issue types).
- Recreate / Generate via n8n with confirmation when replacing an existing draft.
- Optimistic generating state; final content arrives via WebSocket.
Tickets — data sync & training¶
ticket_message_responses— per-message Plenty/dashboard/n8n replies (optional table; graceful skip if not migrated).closed_ticket_message_pairs— minimal training rows on ticket close (message_title,message_text,ai_response,ai_category).tickets.ai_categorycolumn for manual and n8n-assigned complaint types.
Tickets — Plenty send fixes¶
create_reply_message()— POST/rest/messageswith Plenty UIlinkedToshape (user/contact/email/order slots).- Re-query ticket after async Plenty calls (fixes detached SQLAlchemy session on generate/close/send).
- Reopen restores ticket from Plenty when removed from DB on refresh.
Documentation¶
docs/docs/services/service_tickets/n8n-workflow.md— full API, callback, attachments, Code node examples.docs/docs/services/service_tickets/n8n-agent-prompts.md— routing agent + 6 Fach-Agenten (Deutsch), tool specs, skeptical damaged-goods verification rules.docs/docs/services/service_tickets/index.md— service overview and doc links.- Removed duplicate
backend/service_tickets/docs/n8n-workflow.md(content lives underdocs/).
🐛 Bug Fixes¶
- Shop replies in conversation payload —
newReplyFromUserno longer sent to n8n as fake inbound messages; paired underai_responseonly. - Generate 500 —
Instance '<Ticket>' is not persistentafter async Plenty calls; ticket re-queried afterawait. - Category update — skipped
ticket_message_responsesqueries when table missing; avoids poisoned transactions. - 422 on n8n callback attachments — Pydantic rejected stringified JSON arrays; coercion added.
- Undo reopen 404 — ticket re-imported from Plenty when missing locally after refresh.
📁 Files changed¶
Backend (service_tickets)
app/services/n8n_workflow_payload.py— lean payload, order IDs, shop-message filter.app/services/ticket_order_context.py—external_order_id/order_idextraction.app/services/ai_response_attachments.py— normalize, store, Plenty forward.app/services/ticket_ws.py— WebSocket manager + broadcast.app/services/message_response_store.py,message_response_sync.py— per-message sync.app/services/closed_ticket_training.py— training pairs on close.app/services/ticket_issue_categories.py— 12 category keys.app/services/plenty/plenty_manager.py— UI-shaped replies, attachment enrich.app/services/plenty_attachment_proxy.py,plenty/attachments.py— n8n attachment proxy.app/api/v1/endpoints/tickets.py— generate, send, categories, cached messages, WS notify hooks.app/api/v1/endpoints/n8n_webhooks.py— callback + attachments + WS notify.app/main.py— WebSocket endpoints.
Frontend
src/pages/Tickets/Tabs/TicketsTab.jsx— inbound filter, categories, WS updates, attachment chips.src/services/ws/ticketAiDraft.js— WebSocket client.src/services/api/tickets/tickets.js— cached messages, category API.src/utils/ticketIssueCategories.js,n8nWorkflowDefaults.js.src/pages/Tickets/Credentials/WorkflowInfo.jsx— settings UI improvements.
Tests
test_n8n_workflow_payload.py,test_ticket_order_context.py,test_ai_response_attachments.pytest_message_response_store.py,test_closed_ticket_training.py,test_ticket_issue_categories.pytest_plenty_reply_payload.py,test_plenty_attachments.py
Docs
docs/docs/services/service_tickets/*docs/docs/patchnotes/1.7/1.7.5.md
🔧 Database & SQL¶
Run on server before deploy (combined script):
-- See docker/postgres/migrations/add_tickets_ai_schema.sql
ALTER TABLE public.tickets ADD COLUMN IF NOT EXISTS ai_category text;
ALTER TABLE public.tickets ADD COLUMN IF NOT EXISTS ai_response_attachments text;
-- Per-message responses (optional, for UI sync)
-- ticket_message_responses table — see migration file
-- Closed-ticket training corpus
-- closed_ticket_message_pairs table — see migration file
Individual migrations:
docker/postgres/migrations/add_tickets_ai_schema.sql(combined)docker/postgres/migrations/add_ticket_ai_response_attachments.sqldocker/postgres/migrations/add_ticket_message_responses.sqldocker/postgres/migrations/add_closed_ticket_message_pairs.sql
Usage notes¶
Tickets workflow
- Run SQL migrations on Postgres.
- Credentials → Plenty + n8n Workflow configured.
- Expand ticket → Generate via n8n → draft appears via WebSocket (no polling).
- Edit draft → Send to Plenty.
n8n callback (text only)
{
"action": "generate_complete",
"ticket_uuid": "<from webhook>",
"message_uuid": "<from webhook>",
"content": "<German reply, Sie-Form>"
}
n8n callback (with PDF) — optional attachments with content_base64; omit when no PDF.
n8n Code node — build body in JavaScript; use output.response from agent nodes; see n8n-workflow.md.
WebSocket / nginx
- Proxy
/api/v1/tickets/wswith WebSocket upgrade headers in production. - Dev: frontend connects to
localhost:8006(VITE_TICKETS_API_PORT).
Agent prompts
- Copy system prompts from
n8n-agent-prompts.mdinto n8n LLM nodes. - Damaged-article agent: skeptical photo verification before any refund promise.