Phase 3 — Self-Service WhatsApp-Channel-Onboarding
Overview
Bauen die Pipeline die einen neuen Kunden in unter 5 Minuten von „interessiert” auf „bot live auf eigener WhatsApp-Business-Nummer” bringt — ohne dass wir oder der Kunde im Facebook Business Manager rumstochern muessen.
Voraussetzung: 360dialog Partner-Plan Growth (€500/Mo) ist aktiviert. Dieser Plan baut die Infrastruktur drumherum so dass die Aktivierung des Partner-Vertrags der einzige verbleibende manuelle Schritt ist — alles andere ist Self-Service.
Problem Frame
Heute braucht jeder neue WhatsApp-Kunde 1-2 Wochen Setup-Krampf (Meta Business Manager anlegen, Phone-Number-Verify, App Review, Tech-Provider-Antrag). Das bremst Akquise messbar: Lead 3 ist in aktiver Verhandlung (siehe origin _index.md Sequencing), aber „2 Wochen Setup”-Story koennte ihn kippen. Phase 3 ersetzt das durch Embedded Signup: Kunde klickt einen Link, durchlaeuft 3-4 Browser-Schritte (eigener Meta-Login + Business-Manager-Wahl + Phone-Number-Verify + Permission-Grant), und 360dialog meldet uns per Webhook „Channel aktiv”. Wir provisionieren automatisch: Token in Secrets Manager, Row in receptionist-customers, Bot ist live.
Requirements Trace
Aus dem origin-Doc _index.md Phase 3 + Sequencing:
- R1. Kunde durchlaeuft Embedded Signup auf
onboarding.agenticventures.deohne unsere manuelle Beteiligung - R2. Nach erfolgreicher 360dialog-Channel-Aktivierung wird automatisch eine neue Row in
receptionist-customers(DDB) angelegt - R3. Channel-API-Key wird automatisch in AWS Secrets Manager unter
receptionist/tenant/<slug>/360dialog-api-keyabgelegt - R4. receptionist-brain kann den neuen Tenant sofort bedienen (DDB-Stream-Trigger funktioniert ohne Code-Aenderung)
- R5. Local-Storage-Setting der Phone-Number auf
EU (Germany)wird im Channel-Setup automatisch gesetzt (DSGVO-Pflicht aus Research-Run) - R6. Onboarding-Session wird in DDB mit Audit-Trail vorgehalten (welcher Lead hat wann gestartet, mit welcher Email)
- R7. Bei Embedded-Signup-Abbruch oder Failure ist Session sauber abgeraeumt (TTL 7 Tage) und kann wieder gestartet werden
- R8. 360dialog-Webhook-Aufrufe sind signaturverifiziert (kein anonymer POST darf eine Channel-Provisionierung ausloesen)
- R9. Reconciliation-Job laeuft alle 5-15 Min und gleicht Partner-API-Channel-Liste mit
receptionist-customersab (Webhook-Verlust-Schutz)
Success Criteria (aus Sequencing): Lead 3-Onboarding-Flow in der vereinbarten Live-Woche durchlaeuft komplett autonom — End-to-End-Zeit Browser-Klick bis Bot-Antwort unter 5 Minuten.
Scope Boundaries
- Out-of-Scope: mcp-whatsapp Multi-Provider-Refactor (= Phase 1 des Migrations-Projekts, separater Plan, hier nur Interface-Anforderung dokumentiert)
- Out-of-Scope: Icking-Migration Direct-Client → Partner-Hub (passiert nach Aktivierung als 1-Tag-Folge-Arbeit, eigene PR)
- Out-of-Scope: Friseur-Migration auf 360dialog (bleibt Meta-Direct als Resilienz-Hedge, Phase 4 im origin)
- Out-of-Scope: Partner-Plan-Vertragsabschluss bei 360dialog (manueller Sales-Schritt, Trigger fuer Aktivierung dieses Plans)
- Out-of-Scope: Reseller-Billing / eigene Marge-Rechnung an Endkunden (kommt spaeter mit Partner-paid Billing-Modell)
- Non-Goal: Eigene Inbox-UI fuer Mitarbeiter — wir bleiben „Bot-only”, Kunden mit menschlichem Posteingang-Bedarf bekommen separat Superchat-Empfehlung
Context & Research
Relevant Code and Patterns
- Receptionist-Schema
[receptionist.md](../../capabilities/receptionist.md): PKphone_number_id(S), YAML-Config,state.activeToggle. Phase-3-Erweiterung: 3 neue Top-Level-Felder (provider,provider_credentials_secret_arn,local_storage_region). Aktueller einziger Eintrag: Friseur im Sueden (Meta-Direct, bleibt unangetastet). - Agents-Platform-Stack-Pattern
[agents-platform.md](../../capabilities/agents-platform.md):~/source/agents-platform/infra/lib/<name>-stack.ts, kopieren vonbeleg-pipeline-stack.tsoderreceptionist-brain-stack.ts. Lambda-Layeragentic-commonfuer Telegram/Bedrock/Secrets/Logging. - mcp-whatsapp Webhook-Pattern
[mcp-whatsapp.md](../../capabilities/repos/mcp-whatsapp.md): bestehende RoutesPOST /webhook(Meta) +GET /webhook(Verify). FastMCPcustom_route()Pattern. Wir ergaenzenPOST /webhook/360dialoganalog. - Onboarding-Page-Hosting:
av-cockpitPattern (Next.js Static Export → S3 + CloudFront mit Cloudflare-Edge davor). Sieheintern/firma/web-properties.md+dashboard.agenticventures.de-Setup. - Fargate-Tunnel-Pattern
[mcp-hosting-fargate-tunnel.md](../../wissen/prozesse/mcp-hosting-fargate-tunnel.md): nur dann noetig wenn wir tatsaechlich Container brauchen. Fuer reines Static-Site + Webhook-Lambda nicht relevant — leichter mit S3+CloudFront + Lambda Function URL hinter Cloudflare. - DDB-Cross-Account-Pattern: wir bleiben innerhalb
av-production(425924867359, eu-central-1) — keine Cross-Account-AssumeRoles fuer Phase 3 noetig.
Institutional Learnings
- AVV bereits gesichert:
assets/legal/360dialog/2025-04-360dialog-AVV-Partner-Klienten.pdfist die richtige Variante fuer das Partner-Modell. EU-Verarbeitungs-Klausel auf Seite 3 §5 — DSGVO-Lage ist erledigt. - Local-Storage-Default
EU (Germany)muss bei jedem Channel-Setup explizit gesetzt werden (ist NICHT Default in 360dialog). Steht im Research-Run. - Service-Window-Quirk: Outbound-free-form-Messages funktionieren nur in offenem 24h-Service-Window. Erstes Outbound braucht approved Template. Gilt fuer +1 555 Test-Nummer wie fuer echte Channels. Smoke-Skript muss das beruecksichtigen.
- FastMCP DNS-Rebinding-Quirk: falls Onboarding-Backend doch FastMCP-basiert wird →
MCP_ALLOWED_HOSTSEnv-Var pflicht (siehe mcp-hosting-fargate-tunnel.md). Voraussichtlich aber Lambda + reines HTTP, keine FastMCP, kein Quirk.
External References
Aus Research-Run 2026-05-18-research-360dialog-whatsapp-bsp/_index.md:
- 360dialog Integrated Onboarding Doc — Self-Hosted Embedded Signup Flow
- 360dialog Partner API Overview — programmatisches WABA-Management
- 360dialog Embedded Signup Docs — Meta-Embedded-Signup-Integration
- Local Storage Setting Doc — EU(Germany)-Setting pro Phone-Number
Key Technical Decisions
- Erweiterung von
receptionist-customersstatt neueav-channel-registry-Table: eine Source-of-Truth, Brain liest schon dort. Korrigiert die Brainstorm-Annahme. - Webhook-Route am
mcp-whatsapp-Service statt eigenem Webhook-Service: spart Hosting + nutzt den existierenden Fargate-Tunnel + selbe Sicherheits-Boundary. RoutePOST /webhook/360dialoganalog zu bestehendem Meta-Webhook. - Onboarding-Page als Next.js Static + S3+CloudFront + Cloudflare-Edge: kein neues Container-Hosting noetig, wiederverwendet av-cockpit-Pattern. API-Routes (Session-Start, Status-Polling) als separate Lambda Function URL hinter Cloudflare (Pattern
mcp-whatsapphat schon Cloudflare-Tunnel, aber Function URL ist einfacher fuer reine HTTP-Endpoints). onboarding-sessionsals neue DDB-Table mit TTL 7 Tage: Audit-Trail (Lead-Email, Start-Timestamp, 360dialog client_id, Status) + Korrelation Browser-Flow ↔ Webhook-Callback. Nicht inreceptionist-customersmergen weil Lifecycle anders ist (Sessions koennen verfallen ohne Channel zu werden).- Webhook + Reconciliation kombiniert: Webhook ist primary (low-latency Provisionierung), Reconciliation-Lambda alle 15 Min raeumt verpasste Webhooks auf. Pattern wie Stripe. Spart uns Production-Incidents wenn 360dialog mal einen Webhook verliert.
- Provider-Discrimination in
receptionist-customers.providerFeld (meta-direct | 360dialog): erlaubt Friseur (Meta-Direct) + alle Neuen (360dialog) parallel. mcp-whatsapp Phase-1-Refactor muss das Feld lesen. - Webhook-Signatur-Pflicht: 360dialog signiert Webhooks mit HMAC. Verifikation am Endpoint pflicht — kein anonymer POST darf
receptionist-customersschreiben. - Embedded-Signup-Flow vollstaendig clientseitig getriggert: Onboarding-Page laedt 360dialog-Embedded-Signup-Widget (JS-SDK), Browser redirected zu Meta, kommt mit Permission-Code zurueck, JS submitet zu unserer API-Lambda die den 360dialog Partner-API-Call macht. Wir agieren als Proxy, nicht als eigener Auth-Provider.
Open Questions
Resolved During Planning
- Wo wohnt die Onboarding-Page? Antwort: S3 + CloudFront unter
onboarding.agenticventures.de, analogdashboard.agenticventures.de. Cloudflare-Edge davor fuer TLS + WAF. - Webhook-Hosting? Antwort: bestehender mcp-whatsapp-Service kriegt zusaetzliche Route. Spart eine neue Komponente.
- Neue Table oder Erweiterung? Antwort: Erweiterung von
receptionist-customers+ separateonboarding-sessions-Table fuer den temporaeren Flow-State. - Webhook oder Polling? Antwort: Beides. Webhook primary, Reconciliation als Backup.
- Partner-Plan-Aktivierung als Teil des Plans? Nein — manueller Schritt, ist Trigger fuer Plan-Aktivierung. Plan baut Infrastruktur die ohne Partner-Plan-Live-Schaltung schon „bereit” steht (Sandbox-Test-Mode).
Deferred to Implementation
- Exakte 360dialog-Webhook-Signatur-Verifikation (HMAC-SHA-256 vs anderes?): Doku lesen + implementieren in Unit 3
- Lambda Function URL CORS-Konfiguration fuer Cross-Origin-POSTs von der Onboarding-Page: einrichten in Unit 4
- Genaue Felder im 360dialog Channel-Status-Webhook-Payload: erst beim ersten Test-Channel sichtbar, Schema-Lese-Code in Unit 3 toleranter Bauen
- Visual Design der Onboarding-Page: copy + Layout, koennte als spaetere ce:work-Iteration ausgefeilt werden. Erste Version funktional ausreichend.
- Idempotency-Key-Strategie bei Webhook-Replay: vermutlich
event_idals DDB-Conditional-Write — in Unit 3 implementieren - Reconciliation-Cron-Intervall: 5 vs 15 Min vs 1h. In Unit 5 starten mit 15 Min, anpassen wenn Webhook-Verluste auftauchen
High-Level Technical Design
Diese Skizze illustriert den angestrebten Flow und ist Direktional, keine Implementierungs-Spezifikation. Der implementierende Agent behandelt sie als Kontext, nicht als Code zum Reproduzieren.
flowchart TB L[Lead klickt Onboarding-Link in Email/Chat] --> P[onboarding.agenticventures.de Static Next.js] P --> A1[POST /api/start-onboarding Lambda Function URL] A1 --> S[onboarding-sessions DDB Row mit session_id Status pending] A1 --> CP[POST partners/pid/clients via 360dialog Partner-API] CP --> ESU[Embedded Signup URL] ESU --> P P --> M[Browser Redirect zu Meta Embedded Signup] M --> MC{Kunde durchlaeuft Meta-Flow} MC -->|Success| CB[Browser Callback an Onboarding-Page] MC -->|Abbruch| ABRT[Session bleibt pending, TTL 7d raeumt auf] CB --> A2[POST /api/finalize-onboarding Lambda] A2 --> CC[POST partners/pid/clients/id/channels mit local_storage EU] CC --> WAIT[Status pending_channel_activation] WAIT --> W{360dialog Webhook ankommend} W --> WH[POST /webhook/360dialog Route in mcp-whatsapp] WH --> SIG[HMAC Signatur verifizieren] SIG -->|valid| PROV[Provisionierungs-Lambda] PROV --> SM[Channel-API-Key in Secrets Manager] PROV --> RC[Row in receptionist-customers anlegen] PROV --> SU[onboarding-sessions Status active] PROV --> TG[Telegram-Push an Marvin neuer Channel live] REC[Reconciliation-Cron alle 15 Min] --> A3[GET partners/pid/clients/id/channels] A3 --> DIFF{Channel aktiv aber keine receptionist-customers Row} DIFF -->|ja| PROV
Flow-Notizen:
- Session-State lebt nur in
onboarding-sessionsbis Channel aktiv, dann wird sieactivemarkiert (Audit) und faellt unter TTL raus - PROV-Lambda ist die einzige Stelle die
receptionist-customersschreibt — sowohl Webhook als auch Reconciliation rufen dieselbe Funktion auf (Idempotency viachannel_id-Conditional-Write) - mcp-whatsapp ist nur Webhook-Empfaenger + Signatur-Verifier; Business-Logik liegt in der Provisionierungs-Lambda (
agents-platformStack) - Receptionist-Brain bleibt unangetastet — neue Row in
receptionist-customerstriggert nichts direkt; Brain reagiert erst wenn End-Kunde an die neue Nummer schreibt
Implementation Units
- Unit 1: receptionist-customers Schema-Erweiterung + onboarding-sessions Table
Goal: DDB-Schema erweitern damit Provider-Info pro Tenant abgelegt werden kann, plus neue Session-Table fuer den temporaeren Onboarding-Flow.
Requirements: R2, R5, R6, R7
Dependencies: keine (DDB Schemas sind schemalos, kein Migrations-Risk)
Files:
- Modify:
~/source/agents-platform/infra/lib/receptionist-brain-stack.ts(neue Tableonboarding-sessionsergaenzen) - Modify:
~/source/agents-platform/lambdas/receptionist-brain/state.py(lese-Helper fuer neue Felder, defensiv mit Default-Werten) - Create:
~/source/agents-platform/docs/receptionist-customers-schema.md(Schema-Doku mit neuen Feldern dokumentieren) - Modify:
intern/capabilities/receptionist.md(Schema-Section + neue Table ergaenzen)
Approach:
receptionist-customersbleibt PKphone_number_id— neue optionale Top-Level-Felder:provider(defaultmeta-direct),provider_credentials_secret_arn(default null fuer Friseur),local_storage_region(defaulteu-germany)onboarding-sessionsneue Table: PKsession_id(UUID), TTL-Attributeexpires_at(7d), Felderlead_email,started_at,dialog360_client_id,status(pending|pending_channel_activation|active|failed),failure_reason- PITR an fuer
onboarding-sessions(Audit-Pflicht) state.pyHelperget_customer_with_provider(phone_number_id)returnt typisiertes Object mit Provider-Info — Friseur-Row bekommt automatischmeta-directals Default
Patterns to follow:
- Bestehende DDB-Tables im
ReceptionistBrainStackals Vorlage (4 Tables, PITR-Toggle, TTL-Setup) - Schemas in YAML-Frontmatter dokumentieren wie aktuell
receptionist.mdmacht
Test scenarios:
- Happy path: bestehende Friseur-Row liest sauber mit neuem Helper,
provideristmeta-directper Default - Happy path: neuer Test-Eintrag mit
provider: 360dialog+provider_credentials_secret_arn: arn:...wird gelesen - Edge case: Row ohne
provider-Feld (alte Row) → Helper liefertmeta-directals Default, kein Crash - Integration: CDK-Deploy ergaenzt onboarding-sessions Table ohne bestehende Tables anzufassen (drift-check)
Verification:
cdk diffzeigt nur ADD vononboarding-sessions-Table + keine Modify aufreceptionist-customerscdk deployerfolgreich,aws dynamodb describe-table --table-name onboarding-sessionszeigt TTL aktivstate.py-Unit-Test gruen fuer alle 3 Scenarios
- Unit 2: 360dialog Partner-API-Client als Lambda-Layer-Erweiterung
Goal: Wiederverwendbarer Client fuer 360dialog Partner-API (Client-Anlage, Channel-Polling, Embedded-Signup-URL-Generation) im agentic-common Layer.
Requirements: R1, R5, R9
Dependencies: Unit 1 (Schema-Felder muessen feststehen damit Client weiss was er provisioniert)
Files:
- Create:
~/source/agents-platform/layers/agentic-common/python/agentic_common/dialog360.py - Create:
~/source/agents-platform/layers/agentic-common/python/agentic_common/tests/test_dialog360.py - Modify:
~/source/agents-platform/layers/agentic-common/python/agentic_common/__init__.py(Export)
Approach:
- Client-Class
Dialog360PartnerClientmit Methoden:create_client(name, email) -> client_id,generate_embedded_signup_url(client_id, redirect_uri) -> url,list_channels(client_id) -> list[Channel],get_channel(client_id, channel_id) -> Channel - Partner-API-Key + Partner-ID aus Secrets Manager (Cached pro Lambda-Cold-Start)
- HTTP-Client
httpx(passt zu existierenden Lambdas), Timeout 10s, Retry mit Backoff bei 5xx - Base-URL aus Env (
DIALOG360_PARTNER_API_BASE, Defaulthttps://hub.360dialog.io/api/v2) - Sandbox vs Production via Env-Var trennen (Partner-Antrag ist noch nicht durch, bis dahin laeuft alles gegen Sandbox)
- Local-Storage-Region beim Channel-Setup auf
eu-germanyhardcoded — Helper-Methodeset_channel_local_storage(channel_id, region)
Patterns to follow:
agentic_common.bedrockundagentic_common.secretsals Stil-Vorlage (Class-mit-Cache, Lambda-Cold-Start-aware)- Pytest-Tests mit
httpx_mock(kein echter Netz-Call in Unit-Tests)
Test scenarios:
- Happy path:
create_clientreturntclient_idaus stub 200-Response - Happy path:
list_channelsparst Response-Liste korrekt - Error path: 401 von Partner-API →
Dialog360AuthErrormit klarer Message - Error path: 5xx → 3 Retries dann
Dialog360ApiError - Error path: Timeout → klar erkennbar in Logs
- Integration: gegen 360dialog-Sandbox-Account ein echter Smoke-Test (nicht in CI, manuell vor Unit-3-Bau)
Verification:
pytest layers/agentic-common/python/agentic_common/tests/test_dialog360.pygruen, 6+ Tests- Manueller Smoke gegen Sandbox:
create_client+list_channelsreturnt erwartete Werte - Code-Review: kein API-Key oder Partner-ID in Log-Output (Sanitization-Check)
- Unit 3: Provisionierungs-Lambda + 360dialog-Webhook-Route in mcp-whatsapp
Goal: Webhook-Route die signaturverifiziert eingehende 360dialog-Lifecycle-Events annimmt + Provisionierungs-Lambda die Channel-API-Key in Secrets Manager schreibt und receptionist-customers-Row anlegt.
Requirements: R2, R3, R4, R5, R8
Dependencies: Unit 1 (Schema steht), Unit 2 (Client verfuegbar)
Files:
- Modify:
~/source/mcps/mcp-whatsapp/src/mcp_whatsapp/server.py(neuecustom_routePOST /webhook/360dialog) - Create:
~/source/mcps/mcp-whatsapp/src/mcp_whatsapp/dialog360_webhook.py(Signatur-Verify + Dispatch) - Create:
~/source/agents-platform/lambdas/onboarding-provisioner/main.py - Create:
~/source/agents-platform/infra/lib/onboarding-stack.ts(neuer CDK-Stack) - Create:
~/source/agents-platform/lambdas/onboarding-provisioner/tests/test_main.py - Modify:
~/source/agents-platform/infra/bin/app.ts(Stack-Instanziierung)
Approach:
- mcp-whatsapp Route
POST /webhook/360dialog: Signatur-Verify (HMAC-SHA-256 mit Partner-Webhook-Secret), Event-Type-Switch (channel.activated,channel.deactivated,channel.error) - Bei
channel.activated: SQS-Message an Provisionierungs-Queue mitclient_id+channel_id+phone_number_id+session_id(aus Webhook-Payload) - Provisionierungs-Lambda SQS-getriggert (Async-Decoupling, Webhook-Endpoint antwortet sofort 200 — wichtig damit 360dialog nicht retried)
- Provisionierungs-Lambda:
- Holt Channel-Details via Partner-API (
get_channel) — inkl. API-Key - Schreibt API-Key in Secrets Manager
receptionist/tenant/<slug>/360dialog-api-key - Conditional-Write in
receptionist-customersmit PKphone_number_idundprovider=360dialog,provider_credentials_secret_arn=<arn>,local_storage_region=eu-germany,state.active=false(manuell aktivieren erst nach Marvin-Pruefung) - Updated
onboarding-sessions[session_id].status = active - Setzt Local-Storage auf
eu-germanyvia Partner-API (falls noch nicht geschehen) - Telegram-Push an Marvin: „Neuer Channel live:
/ <phone_number>”
- Holt Channel-Details via Partner-API (
- Idempotency:
channel_idals Idempotency-Key, Conditional-Writeattribute_not_exists(channel_id)
Execution note: Start with characterization-Test fuer Signatur-Verify (Edge: invalid signature, replay attack, missing header) bevor andere Logik gebaut wird. Sicherheits-kritischer Code zuerst test-first.
Patterns to follow:
- mcp-whatsapp bestehende
POST /webhookals Vorlage fuer FastMCP custom_route BelegPipelineStackals CDK-Stack-Vorlage fuer onboarding-stack.ts (Lambda + SQS + DDB-Permissions + Secrets-Permissions)agentic_common.telegramfuer den Push
Test scenarios:
- Happy path: valider Webhook
channel.activated→ SQS-Message landet - Happy path: SQS-Trigger → Secrets Manager hat neuen Key,
receptionist-customershat neue Row,onboarding-sessionsStatusactive, Telegram-Push erfolgt - Edge case: gleicher Webhook zweimal (Replay) → zweite Provisionierung ist no-op (Conditional-Write greift)
- Edge case: Webhook fuer unbekannte
session_id→ in Log, kein Crash, kein Schreiben in DDB - Error path: invalid HMAC-Signatur → 401, kein Schreiben in SQS
- Error path: fehlender Signature-Header → 401
- Error path: Partner-API-Call fuer
get_channelschlaegt fehl → Lambda retried via SQS-Visibility-Timeout, nach 3 Fails in DLQ - Error path: Secrets-Manager-Write fehlschlaegt → DLQ, Telegram-Alarm
- Integration: End-to-End in Sandbox — Webhook stub → SQS → Lambda → Secrets + DDB. Manuelle Run, nicht CI.
Verification:
pytest lambdas/onboarding-provisioner/tests/gruencdk deploy OnboardingStackerfolgreich- Webhook-Smoke mit
curl+ valider HMAC liefert 200; mit invalider HMAC 401 aws dynamodb scan --table-name receptionist-customerszeigt nach Smoke neue Row
- Unit 4: Onboarding-API-Lambda (Session-Start + Finalize) mit Function URL
Goal: Backend-API die vom Onboarding-Page-JS aufgerufen wird — startet Onboarding-Session, gibt Embedded-Signup-URL zurueck, finalisiert nach Browser-Callback.
Requirements: R1, R6, R7
Dependencies: Unit 1 (Sessions-Table existiert), Unit 2 (Partner-API-Client verfuegbar)
Files:
- Create:
~/source/agents-platform/lambdas/onboarding-api/main.py - Create:
~/source/agents-platform/lambdas/onboarding-api/tests/test_main.py - Modify:
~/source/agents-platform/infra/lib/onboarding-stack.ts(Lambda + Function URL ergaenzen)
Approach:
- Single-Lambda mit Routen-Switch (kein API Gateway noetig — Function URL ist ausreichend, CORS konfigurierbar)
- Routen:
POST /api/start-onboardingmit{lead_email, customer_slug, persona_name, business_name}→ erstellt Session, callscreate_client, returnt{session_id, embedded_signup_url}GET /api/onboarding-status?session_id=...→ returnt aktuellen Status (pending|pending_channel_activation|active|failed)
- CORS: Origin
https://onboarding.agenticventures.dewhitelisten, andere refusen - Rate-Limit: 5 Requests/Min/IP via Lambda-eigene DDB-Counter (oder Cloudflare-WAF davor, eleganter)
- Cloudflare-Worker oder -Rule davor um die Lambda-Function-URL nicht direkt exposeable zu machen (Domain
api.onboarding.agenticventures.de→ Cloudflare-Tunnel oder Worker-Proxy)
Patterns to follow:
- Lambda-Function-URL mit AuthType=NONE + CORS in CDK (
addFunctionUrl({ authType: lambda.FunctionUrlAuthType.NONE, cors: {...} })) agentic_common.loggingfuer strukturiertes Logging mitrequest_id
Test scenarios:
- Happy path: valide POST
/api/start-onboarding→ 200 mitsession_id+ URL, DDB-Row angelegt - Happy path: GET status returnt aktuellen Wert
- Edge case: POST mit fehlendem
lead_email→ 400 mit Fehlerbeschreibung - Edge case: 6. Request in einer Minute → 429
- Error path: Partner-API down → 503, Session-Row mit Status
failedundfailure_reason - Error path: bekannter Lead startet Session erneut → neue Session-Row (kein Duplicate-Check, Sessions sind separate Events)
- Integration: vollstaendiger Flow Lambda → Partner-API-Sandbox → DDB
Verification:
- Unit-Tests gruen
curlvon einer fremden Origin wird per CORS abgelehntcurlvononboarding.agenticventures.deOrigin erlaubt- DDB-Row enthaelt erwartete Felder nach Smoke
- Unit 5: Reconciliation-Cron-Lambda
Goal: Alle 15 Min Channel-Liste vom Partner-API holen und mit receptionist-customers abgleichen — verpasste Webhooks aufraeumen.
Requirements: R9
Dependencies: Unit 2 (Partner-Client), Unit 3 (Provisionierungs-Lambda existiert + ist idempotent)
Files:
- Create:
~/source/agents-platform/lambdas/onboarding-reconciler/main.py - Create:
~/source/agents-platform/lambdas/onboarding-reconciler/tests/test_main.py - Modify:
~/source/agents-platform/infra/lib/onboarding-stack.ts(EventBridge-Cron + Lambda)
Approach:
- EventBridge-Rule
rate(15 minutes)→ Lambda - Lambda:
list_channelsfuer alle bekanntenclient_ids ausonboarding-sessions(Status !=active) - Pro Channel: Wenn Channel aktiv und
receptionist-customershat noch keine Row → SQS-Message an Provisionierungs-Queue (Unit 3 Idempotency greift) - Telegram-Push wenn Reconciliation Channels findet die nicht durch Webhook kamen (frueh-Warn fuer Webhook-Probleme)
Patterns to follow:
agent-daily-briefingals EventBridge-Cron-Lambda-Vorlage- AgenticVenturesAgent-Construct nutzen wenn moeglich
Test scenarios:
- Happy path: alle Sessions sind
active→ kein Schreiben, Telegram-Stille - Happy path: 1 Channel aktiv aber nicht in
receptionist-customers→ SQS-Message + Telegram-Notice - Edge case: keine pending Sessions → fruehes Return
- Error path: Partner-API down → Log + Telegram, kein Crash
- Integration: gegen Sandbox mit manuell „verpasstem” Channel — Reconciler fix das auf
Verification:
- Unit-Tests gruen
- CloudWatch Logs zeigen 15-Min-Rythmus
- Telegram-Notice kommt bei Test-Szenario
- Unit 6: Onboarding-Page Next.js Static
Goal: Browser-Seite die Lead den 4-Schritt-Flow durchklicken laesst — Form fuer Customer-Daten, 360dialog Embedded Signup-Widget-Einbettung, Status-Polling nach Callback.
Requirements: R1, R7
Dependencies: Unit 4 (API-Lambda existiert)
Files:
- Create:
~/source/agentic-ventures-website/app/onboarding/whatsapp/page.tsx(oder neues~/source/av-onboarding/Repo — TBD beim Bau) - Create:
~/source/agentic-ventures-website/app/onboarding/whatsapp/_components/SignupForm.tsx - Create:
~/source/agentic-ventures-website/app/onboarding/whatsapp/_components/EmbeddedSignupTrigger.tsx - Create:
~/source/agentic-ventures-website/app/onboarding/whatsapp/_components/StatusPolling.tsx - Create:
~/source/agentic-ventures-website/app/onboarding/whatsapp/_components/SuccessPage.tsx - Modify: CDK-Stack der av-website wenn separate Subdomain noetig (oder direkt als Route in der bestehenden Site, Subdomain-Cutover spaeter)
Approach:
- Schritt 1: Form
lead_email,customer_slug,persona_name,business_name→ submit ruft Unit-4-Lambda - Schritt 2: Embedded-Signup-URL wird in neuem Tab oder iframe geoeffnet (360dialog-Doku entscheidet was best practice ist — vermutlich Pop-up wegen Meta-OAuth)
- Schritt 3: Polling-Status-Page (alle 3s GET
/api/onboarding-statusbisactiveoderfailed, max 10 Min) - Schritt 4: Success-Page mit naechsten Schritten („Wir haben dir eine Bestaetigung an
geschickt”) oder Failure-Page mit Re-Try - Kein User-Login auf der Page (Embedded-Signup-Token reicht als Identitaets-Indikator)
- Brand-Kit aus
agentic-ventures-brand-kitfalls verfuegbar (siehe Routing)
Patterns to follow:
av-cockpitals Next.js Static Export Vorlage- Tailwind v4 + bestehender av-website Look-and-Feel
Test scenarios:
- Happy path: Form-Submit funktioniert, Embedded-Signup-Popup oeffnet
- Happy path: Polling erkennt
active-Status und zeigt Success - Edge case: Polling-Timeout nach 10 Min → klare Fehlermeldung mit Support-Email
- Edge case: Form-Validation: leere Felder, ungueltige Email
- Error path: API antwortet 5xx → Retry-Button mit Fehlermeldung
- Integration: End-to-End in Sandbox (Marvin onboardet sich selbst als Test-Channel)
Verification:
- Static-Export erfolgreich (
pnpm build) - S3-Deploy + CloudFront-Invalidation laeuft
https://onboarding.agenticventures.deliefert die Page- Manueller End-to-End-Test in Sandbox erfolgreich
- Unit 7: End-to-End-Smoketest in Sandbox + Doku
Goal: Kompletter Self-Onboarding-Flow von Marvin selbst durchgespielt + dokumentiert, fuer Lead-3-Pitch-Demo.
Requirements: R1-R9 (alle)
Dependencies: Units 1-6 deployed
Files:
- Create:
intern/runs/<datum>-smoke-onboarding-self-test/_index.md - Modify:
intern/projekte/whatsapp-bsp-migration/_index.md(Phase-3-Status aktualisieren) - Modify:
intern/capabilities/receptionist.md(Provider-Pattern dokumentieren)
Approach:
- Marvin startet selbst einen Onboarding-Flow mit Test-Email + Test-Channel im Sandbox
- Tracking: jede Stage abhaken, Edge-Cases triggern (Browser-Schliessen, Re-Try, double-Webhook)
- Cleanup: Test-Channel manuell wieder entfernen in 360dialog-Sandbox
- Doku: Run-Report mit Screenshots/Logs, Liste der Friktionen die Lead 3 sehen wuerde
Test scenarios:
- Happy path: kompletter Flow unter 5 Minuten
- Edge case: Browser mitten im Meta-Flow geschlossen → Reconciliation fix das
- Edge case: Webhook 30 Sek verzoegert → User sieht Polling-Pending dann Success
- Integration: WhatsApp-Inbound an die neue Test-Nummer wird vom Receptionist-Brain beantwortet (Smoke fuer R4)
Verification:
- Run-Report in
intern/runs/mit Outcome - Lead-3-Demo-Ready-Status im
_index.mdgesetzt
System-Wide Impact
- Interaction graph:
mcp-whatsappbekommt zweite Webhook-Route — bestehende Meta-Route bleibt unangetastetreceptionist-brainbekommt neue Rows inreceptionist-customers— Brain-Code bleibt unangetastet, nur Reader-Helper bekommt neue Felder- Lambda Function URL bekommt erstmal eigene URL (nicht hinter Cloudflare-Tunnel) — Cloudflare-Worker-Proxy als optionale Haertung wenn noetig
- Error propagation:
- Webhook-Failures → SQS-Retry → DLQ → Telegram-Push → Reconciliation als Fallback
- Embedded-Signup-Abbruch → Session bleibt pending, TTL raeumt nach 7d auf, Lead kann Re-Try
- Partner-API-Outage → Lambda-Failures bleiben in DLQ, Reconciler holt nach wenn API wieder da
- State lifecycle risks:
- Doppel-Onboarding derselben Phone-Number: Conditional-Write in
receptionist-customersmit PKphone_number_idgreift (kein Duplicate) - Session expired aber Channel ist aktiv: Reconciliation findet Channel und erstellt Row trotzdem (Audit-Trail dann ohne
session_id-Korrelation)
- Doppel-Onboarding derselben Phone-Number: Conditional-Write in
- API surface parity:
- mcp-whatsapp Multi-Provider-Refactor (Phase 1) MUSS bevor Phase 3 live geht durch sein — Brain redet sonst weiter Meta-Direct auch fuer neue 360dialog-Channels
- mcp-whatsapp Schnittstelle zur Brain bleibt gleich (
send_text(phone_number_id, text)) — interne Provider-Diskriminierung
- Integration coverage:
- End-to-End-Smoke (Unit 7) ist die einzige echte Pruefung — Unit-Tests pro Lambda decken nicht die Cross-Service-Interaktion
- Unchanged invariants:
- Friseur (Meta-Direct, Phone-Number
1170948102758111) bleibt unangetastet —provider: meta-directals Default sichert Backward-Compat - Bestehende mcp-whatsapp Meta-Webhook-Route bleibt 1:1
- Receptionist-Brain Tool-Loop bleibt unangetastet
- Friseur (Meta-Direct, Phone-Number
Risks & Dependencies
| Risk | Mitigation |
|---|---|
| Partner-Antrag bei 360dialog dauert > 2 Wochen | Phase-3-Bau ist Antrag-unabhaengig — Sandbox-Mode genuegt fuer Build + Test. Aktivierung wartet auf Vertrag. |
| Lead 3 dropt mid-Build | Bau ist sunk cost €0 zusaetzlich (kein Partner-Plan vor Aktivierung). Plan bleibt zukunftsfaehig fuer naechsten Lead. |
| Embedded-Signup-Spec aendert sich bei Meta | 360dialog ist der Buffer — sie passen ihr Widget an. Unsere API-Calls sind 360dialog-API-stabil. |
| Webhook-Signatur-Doku unvollstaendig oder anders als erwartet | Unit 3 startet mit Signatur-Verify als Characterization-Test, kein Build vorwaerts bis Verify gruen ist |
| 360dialog Sandbox != Production (Schema-Differenzen) | Unit 7 End-to-End-Smoke explizit gegen Sandbox; nach Partner-Vertrag-Aktivierung erneut Smoke gegen Production-Test-Channel BEVOR Lead 3 onboarden darf |
| Lambda Function URL ist exponiert (Brute-Force) | Rate-Limit + CORS am Lambda; optional Cloudflare-Worker-Proxy als Haertung in Iteration 2 |
| Sensitive Daten (Partner-API-Key) in CloudWatch | Sanitization-Helper in agentic_common.logging (Liste verbotener Felder) + Code-Review |
| Code-Verrottung durch Meta-API-Drift (HeyJulia-Lesson 2025: Cloud API v18 → v23 brach ohne Hinweis die alte Integration) | 360dialog-Hub-URL waba-v2.360dialog.io ist versions-stabil — 360dialog uebernimmt die Meta-Versions-Mappings intern. Alle neuen Channels gehen daher ueber 360dialog. Friseur (Meta-Direct) bleibt aus Resilienz-Hedge-Grund, sollte aber im Q3-Q4 2026 migriert werden bevor naechster Versions-Break (Phase 4 origin). |
Documentation / Operational Notes
- Docs to update nach Plan-Abschluss:
intern/capabilities/receptionist.mdSchema-Section + Provider-Patternintern/capabilities/repos/mcp-whatsapp.mdneue Route ergaenzenintern/capabilities/agents-platform.mdListe der aktiven Agents umonboarding-provisioner,onboarding-api,onboarding-reconcilererweiternintern/firma/web-properties.mdonboarding.agenticventures.deergaenzenintern/wissen/prozesse/neuer Eintrag „360dialog-Partner-Onboarding-Flow” als wiederverwendbarer Pattern fuer kuenftige BSP-Integrationen
- Operational:
- Telegram-Notice fuer Channel-Aktivierungs-Events (informativ, kein Page)
- CloudWatch-Alarm auf SQS-DLQ-Tiefe > 0 (Page wenn Provisionierung dauerhaft scheitert)
- CloudWatch-Alarm auf Lambda-Function-URL 5xx-Rate > 10%/5min
- Partner-API-Key Rotation: jaehrlich, Reminder als TODO in
intern/firma/active-work.md
- Rollout:
- Sandbox-Test mit eigenem Channel
- Production-Smoke nach Partner-Vertrag-Aktivierung mit dediziertem Test-Channel
- Erst dann Lead-3-Onboarding-Link rausgeben
Sources & References
- Origin:
intern/projekte/whatsapp-bsp-migration/_index.md(Path C Sequencing, Phase 3 Definition) - Research-Run:
intern/runs/2026-05-18-research-360dialog-whatsapp-bsp/_index.md(Pricing, DSGVO, End-to-End-Smoke +1 555 Test-Nummer) - AVV:
assets/legal/360dialog/2025-04-360dialog-AVV-Partner-Klienten.pdf - Receptionist-Plattform:
intern/capabilities/receptionist.md - Agents-Plattform:
intern/capabilities/agents-platform.md - Hosting-Pattern Fargate-Tunnel:
intern/wissen/prozesse/mcp-hosting-fargate-tunnel.md - mcp-whatsapp:
intern/capabilities/repos/mcp-whatsapp.md - 360dialog Integrated Onboarding: https://docs.360dialog.com/partner/onboarding/integrated-onboarding.md
- 360dialog Partner API: https://docs.360dialog.com/partner/partner-api/overview
- 360dialog Embedded Signup: https://docs.360dialog.com/docs/hub/embedded-signup
- 360dialog Local Storage: https://docs.360dialog.com/docs/hub/local-storage.md