Widget & Flowbuilder Implementatie
Widget & Flowbuilder Implementatie
Section titled “Widget & Flowbuilder Implementatie”v9 Implementatie gids voor het toevoegen van de Magic Agent chatwidget en flowbuilder aan een tenant.
Architectuur Overzicht
Section titled “Architectuur Overzicht”┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐│ Storefront │───▶│ Widget Server │───▶│ Agent Backend ││ (widget-loader) │ │ (port 4060) │ │ (port 40XX) │└─────────────────┘ └──────────────────┘ └─────────────────┘ │ ┌─────────────────┐ │ │ Flowbuilder │◀─────┘ │ (port 3003) │ │ └─────────────────┘ │ ▼ ┌──────────────┐ ┌─────────────────┐ │ n8n │ │ PostgreSQL │ │ (port 80XX) │ │ magic_agent_{t} │ └──────────────┘ └─────────────────┘| Component | Locatie | Functie |
|---|---|---|
| Widget Loader | /widget/widget-loader.js | Laadt de chatwidget op de storefront |
| Widget Core | /widget/widget-core.js | Chat UI, berichten, uploads, knoppen |
| Widget Server | /widget/widget-server.ts | Proxy + config API + chat history |
| Agent Backend | /agents/{tenant}/ | Flow executor, AI, API endpoints |
| Flowbuilder | /flowbuilder/ | Visuele flow editor (React + ReactFlow) |
| Flow API | /flow-api/ | CRUD voor flows |
Stap 1: Database Aanmaken
Section titled “Stap 1: Database Aanmaken”Maak een nieuwe database magic_agent_{tenant} aan:
CREATE DATABASE magic_agent_{tenant};De tabellen worden automatisch aangemaakt bij eerste start van de agent. De belangrijkste tabellen:
| Tabel | Functie |
|---|---|
chat_sessions | Actieve chat sessies met klantinfo |
chat_messages | Alle berichten per sessie |
agent_flows | Flowbuilder flows (nodes + edges als JSON) |
flow_sessions | Actieve flow status per chat sessie |
widget_configs | Widget configuratie (kleuren, teksten, domeinen) |
conversation_context | Gesprekscontext (product, budget, etc.) |
ai_prompts | Systeem prompts per agent |
ai_metrics | Token gebruik en kosten |
Stap 2: Agent Backend Opzetten
Section titled “Stap 2: Agent Backend Opzetten”Kopieer een bestaande agent als template:
cp -r /mnt/data/magic_omniverse/magic_agent/agents/jodasign \ /mnt/data/magic_omniverse/magic_agent/agents/{tenant}Configuratie (.env)
Section titled “Configuratie (.env)”# DatabaseDB_HOST=192.168.1.26DB_PORT=5432DB_USER=postgresDB_PASS=<your-db-password>DB_NAME=magic_agent_{tenant}
# Medusa commerce databaseMEDUSA_DB_HOST=192.168.1.26MEDUSA_DB_NAME=magic_b2b_{tenant}
# AgentAGENT_NAME={tenant}AGENT_PORT=40XXNODE_ENV=production
# AIANTHROPIC_API_KEY=sk-ant-...
# FastEditor (optioneel)FASTEDITOR_API_URL=https://api.editor.fasteditor.com/apiFASTEDITOR_API_KEY=...FASTEDITOR_PARTNER_ID=magiceverse
# EmailSMTP_HOST=mail.magiceverse.nlSMTP_PORT=587SMTP_USER=portal@magiceverse.nlSMTP_PASS=...Builden en starten
Section titled “Builden en starten”cd /mnt/data/magic_omniverse/magic_agent/agents/{tenant}npm installnpm run buildpm2 start dist/src/index.js --name magic-agent-{tenant}Stap 3: Widget Configuratie
Section titled “Stap 3: Widget Configuratie”Widget Config in Database
Section titled “Widget Config in Database”De widget configuratie wordt opgeslagen in de widget_configs tabel. Stel deze in via de Flowbuilder UI of direct in de database:
INSERT INTO widget_configs ( agent_name, brand_name, bot_name, primary_color, welcome_message_nl, welcome_message_en, welcome_message_de, position, is_active, allowed_domains) VALUES ( '{tenant}', 'Bedrijfsnaam', 'Nova', '#CF0D65', 'Hallo! Waarmee kan ik je helpen?', 'Hello! How can I help you?', 'Hallo! Wie kann ich Ihnen helfen?', 'bottom-right', true, ARRAY['*.magiceverse.online', 'www.{tenant}.nl']);Configuratie Parameters
Section titled “Configuratie Parameters”| Parameter | Type | Beschrijving |
|---|---|---|
agent_name | string | Unieke agent identifier |
brand_name | string | Bedrijfsnaam in de widget |
bot_name | string | Naam van de chatbot (bijv. “Nova”, “Luke”) |
primary_color | hex | Hoofdkleur van de widget |
secondary_color | hex | Secundaire kleur |
accent_color | hex | Accent kleur |
gradient_color | hex | Gradient kleur voor header |
position | string | bottom-right of bottom-left |
logo_url | url | Logo URL voor in de widget |
welcome_message_nl | string | Welkomstbericht (Nederlands) |
welcome_message_en | string | Welkomstbericht (Engels) |
welcome_message_de | string | Welkomstbericht (Duits) |
welcome_message_returning_nl | string | Terugkerend bezoeker bericht |
allowed_domains | array | Domeinen waar de widget mag laden |
is_active | boolean | Widget aan/uit |
Stap 4: Widget Injecteren op Storefront
Section titled “Stap 4: Widget Injecteren op Storefront”Next.js (Medusa Storefront)
Section titled “Next.js (Medusa Storefront)”Maak een ChatWidget component:
"use client"
import { useEffect } from "react"
type Customer = { id: string email: string first_name: string last_name: string}
export default function ChatWidget({ customer }: { customer?: Customer | null }) { useEffect(() => { // Set customer context if (customer) { window.__MEDUSA_LOGGED_IN__ = true window.__MEDUSA_CUSTOMER__ = customer window.MagicWidgetConfig = { customer_context: { email: customer.email, name: `${customer.first_name} ${customer.last_name}`.trim(), customer_id: customer.id, }, } }
// Inject widget loader script if (!document.getElementById("magic-widget-loader")) { const script = document.createElement("script") script.id = "magic-widget-loader" script.src = "https://agent.magiceverse.online/widget/widget-loader.js" script.setAttribute("data-agent", "{tenant}") script.setAttribute("data-tenant", "{tenant}") script.setAttribute("data-api-url", "https://agent.magiceverse.online") script.setAttribute("data-position", "bottom-right") script.setAttribute("data-language", "nl") if (customer) { script.setAttribute("data-logged-in", "true") } document.body.appendChild(script) } }, [customer])
return null}In layout.tsx (server-side customer data)
Section titled “In layout.tsx (server-side customer data)”import { cookies } from "next/headers"import ChatWidget from "@modules/common/components/chat-widget"
async function getCustomer() { const cookieStore = cookies() const token = cookieStore.get("_medusa_jwt")?.value if (!token) return null // Fetch customer from Medusa API const res = await fetch(`${MEDUSA_BACKEND_URL}/store/customers/me`, { headers: { Authorization: `Bearer ${token}` }, }) if (!res.ok) return null const { customer } = await res.json() return customer}
export default async function RootLayout({ children }) { const customer = await getCustomer() return ( <html> <body> {children} <ChatWidget customer={customer} /> </body> </html> )}Script tag (zonder framework)
Section titled “Script tag (zonder framework)”<script id="magic-widget-loader" src="https://agent.magiceverse.online/widget/widget-loader.js" data-agent="{tenant}" data-tenant="{tenant}" data-api-url="https://agent.magiceverse.online" data-position="bottom-right" data-language="nl"></script>Stap 5: Flowbuilder Flows Maken
Section titled “Stap 5: Flowbuilder Flows Maken”Toegang
Section titled “Toegang”Open de Flowbuilder op https://agent.magiceverse.online/flowbuilder/ en selecteer de juiste agent.
Flow Structuur
Section titled “Flow Structuur”Een flow bestaat uit nodes (stappen) en edges (verbindingen):
| Node Type | Functie | Voorbeeld |
|---|---|---|
marker | Startpunt / trigger | ”Offerte Start” |
response | Tekst tonen aan gebruiker | ”Welkom! Hoe kan ik helpen?” |
user_input | Wacht op gebruikersinvoer | Knoppen, vrije tekst, foto upload |
switch | Routeer op basis van waarde | Als keuze = “offerte” → … |
action | Voer een actie uit | API call, DB query, order aanmaken |
set_variable | Variabele opslaan | quotation_id = {{__user_input}} |
http_request | Externe API aanroepen | n8n webhook, product zoeken |
trigger_flow | Start een andere flow | Hoofdmenu → Offerte flow |
end | Beëindig de flow | Bedankt en tot ziens |
Variabelen
Section titled “Variabelen”Flows gebruiken {{variabele}} syntax voor dynamische waarden:
| Variabele | Bron | Voorbeeld |
|---|---|---|
{{__user_input}} | Laatste gebruikersinvoer | ”100806-001” |
{{session_id}} | Huidige chat sessie | ”chat_1234_abc” |
{{customer_email}} | Klant email (uit sessie) | “klant@bedrijf.nl” |
{{customer_name}} | Klant naam | ”Jan de Vries” |
{{offerte_result.quotation_number}} | API response variabele | ”Q-2026-0042” |
User Input met Knoppen
Section titled “User Input met Knoppen”{ "nodeType": "user_input", "userInputData": { "inputType": "buttons", "variable": "main_keuze", "noTyping": true, "buttons": [ { "value": "product", "text": "Product zoeken", "label_en": "Find product" }, { "value": "offerte", "text": "Offerte aanvragen", "label_en": "Request quote" }, { "value": "voorraad", "text": "Voorraad checken", "label_en": "Check stock" } ] }}HTTP Request Node (n8n webhook)
Section titled “HTTP Request Node (n8n webhook)”{ "nodeType": "action", "actionData": { "type": "http_request", "url": "http://localhost:8090/webhook/magic-agent/{tenant}/search-products", "method": "POST", "body": "{\"query\": \"{{__user_input}}\", \"session_id\": \"{{session_id}}\"}", "responseVariable": "search_result" }}Ingebouwde Action Types
Section titled “Ingebouwde Action Types”| Type | Functie |
|---|---|
SHOW_QUOTATION_SESSIONS | Toon openstaande offertes |
SHOW_QUOTATION_LINES | Toon regels van een offerte |
CREATE_ORDER_APPROVED_LINES | Maak order van goedgekeurde regels |
TRIGGER_FLOW | Start een andere flow |
http_request | Externe API call |
Stap 6: n8n Workflow Koppelen
Section titled “Stap 6: n8n Workflow Koppelen”Webhook Endpoint
Section titled “Webhook Endpoint”Maak een n8n workflow met een Webhook trigger:
Webhook URL: POST /webhook/magic-agent/{tenant}/{actie}Veelgebruikte n8n Nodes
Section titled “Veelgebruikte n8n Nodes”| Node | Functie |
|---|---|
| Webhook | Ontvang request van agent |
| PostgreSQL | Query op commerce database |
| Code | Data transformatie |
| HTTP Request | Externe API calls |
| Send Email | SMTP email versturen |
| Respond to Webhook | Response terugsturen |
Database Credentials
Section titled “Database Credentials”Maak een PostgreSQL credential in n8n:
- Host:
192.168.1.26 - Database:
magic_b2b_{tenant} - User:
postgres - Password: (zie .env)
Stap 7: Testen
Section titled “Stap 7: Testen”Widget Test
Section titled “Widget Test”- Open de storefront in de browser
- De chatwidget bubble verschijnt rechtsonder
- Klik op de bubble → welkomstbericht verschijnt
- Test de flow door op knoppen te klikken
Flow Test via Flowbuilder
Section titled “Flow Test via Flowbuilder”- Open de Flowbuilder (
/flowbuilder/) - Selecteer een flow
- Klik op “Test” in de toolbar
- Voer berichten in en controleer de respons
API Test
Section titled “API Test”curl -X POST https://agent.magiceverse.online/api/{tenant}/send-message \ -H "Content-Type: application/json" \ -d '{"session_id": "test_123", "message": "hallo"}'Architectuur Details
Section titled “Architectuur Details”Message Flow
Section titled “Message Flow”- Gebruiker typt bericht in widget
widget-core.jsstuurt POST naar/api/{agent}/send-message- Widget Server proxy’t naar Agent Backend
- Agent checkt actieve flow sessie in
flow_sessions - Flow Executor verwerkt het bericht door de flow nodes
- Bij
http_requestnodes → n8n webhook of externe API - Bij
actionnodes → ingebouwde handlers (DB queries, order aanmaken) - Response wordt teruggestuurd naar widget
- Widget toont bericht + eventuele knoppen
Session Management
Section titled “Session Management”- Chat sessie (
chat_sessions): Uniek per bezoeker, bevat klantinfo - Flow sessie (
flow_sessions): Actieve flow status per chat sessie - Browser opslag:
localStoragevoor sessie-id persistentie
Multi-language
Section titled “Multi-language”De widget ondersteunt NL, EN, DE, FR. Knoppen in flows kunnen per taal gelabeld worden:
{ "value": "offerte", "label_nl": "Offerte aanvragen", "label_en": "Request quote", "label_de": "Angebot anfordern"}PM2 Processen
Section titled “PM2 Processen”| Proces | Port | Functie |
|---|---|---|
magic-widget-server | 4060 | Widget proxy + config |
magic-agent-brinxx | 4040 | Brinxx agent |
magic-agent-jodasign | 4071 | JoDa Sign agent |
magic-agent-logohorloge | 4072 | Logohorloge agent |
magic-agent-spranz | 4073 | Spranz agent |
flow-builder | 3003 | Flowbuilder UI |
flow-api | 3004 | Flow CRUD API |