Skip to content

πŸ€– Agent and n8n Integration Architecture (Post-MVP Vision)

Scope: POST-MVP ONLY - This is a FUTURE architecture, NOT for MVP Status: Vision / Archived (Superseded by simplified-mvp-architecture.md) Date Moved to Vision: 2025-10-13 Purpose: Documents potential future AI agent integration if we add AI post-MVP

Important Note

THIS IS NOT THE MVP ARCHITECTURE. The MVP uses deterministic, rule-based processing with no AI agents (see ../05-architecture/simplified-mvp-architecture.md).

This document describes a potential future architecture if we decide to add AI agents post-MVP based on customer demand and revenue to support the infrastructure.

Future Vision: How AI Agents Could Integrate

If we add AI agents post-MVP, this is how deterministic automation (n8n) and AI reasoning (LangGraph) could work together:

Overview

GetCimple uses a two-layer architecture:

  • n8n: Handles deterministic automation, routing, and scheduling
  • LangGraph Agent: Provides AI-powered reasoning and complex workflows

This separation ensures reliability, scalability, and clear responsibilities.

High-Level Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        User Interactions                         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   WhatsApp     β”‚   Web App      β”‚   Email        β”‚   Slack      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚                 β”‚                 β”‚              β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜                 β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                 β”‚                                 β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚                    n8n Workflows                   β”‚
        β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
        β”‚  β”‚ Deterministic Automation Layer:             β”‚  β”‚
        β”‚  β”‚ β€’ Message routing & formatting              β”‚  β”‚
        β”‚  β”‚ β€’ Schedule triggers (daily checks)         β”‚  β”‚
        β”‚  β”‚ β€’ Simple notifications                     β”‚  β”‚
        β”‚  β”‚ β€’ Webhook handling                         β”‚  β”‚
        β”‚  β”‚ β€’ API orchestration                        β”‚  β”‚
        β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚ HTTP/REST
                             β–Ό
                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚  Cloudflare Workers   β”‚ (Auth, Rate Limit)
                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚   GetCimple Agent     β”‚
                 β”‚     (LangGraph)       β”‚
                 β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
                 β”‚  β”‚ AI Reasoning:   β”‚  β”‚
                 β”‚  β”‚ β€’ Assessments   β”‚  β”‚
                 β”‚  β”‚ β€’ Q&A           β”‚  β”‚
                 β”‚  β”‚ β€’ Reports       β”‚  β”‚
                 β”‚  β”‚ β€’ Extraction    β”‚  β”‚
                 β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚    Supabase     β”‚
                    β”‚   (Database)    β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Detailed Component Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                              External Users                              β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   WhatsApp   β”‚   Web App    β”‚    Slack     β”‚    Email     β”‚   API      β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
       β”‚              β”‚              β”‚              β”‚             β”‚
       β”‚         β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”         β”‚              β”‚             β”‚
       β”‚         β”‚SvelteKitβ”‚         β”‚              β”‚             β”‚
       β”‚         β”‚ (ag-ui) β”‚         β”‚              β”‚             β”‚
       β”‚         β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜         β”‚              β”‚             β”‚
       β”‚              β”‚              β”‚              β”‚             β”‚
       β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜             β”‚
              β”‚               β”‚           β”‚                       β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ n8n Container  β”‚  β”‚ Cloudflare Workers   β”‚      β”‚ Direct API Call  β”‚
    β”‚ (Docker/VPS)   β”‚  β”‚ (Edge Gateway)       β”‚      β”‚ (Authenticated)  β”‚
    β”‚                β”‚  β”‚                       β”‚      β”‚                  β”‚
    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚  β”‚ β€’ Auth (Kinde)       β”‚      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚ β”‚ Workflows: β”‚ β”‚  β”‚ β€’ Rate Limiting      β”‚                β”‚
    β”‚ β”‚            β”‚ β”‚  β”‚ β€’ Request Routing    β”‚                β”‚
    β”‚ β”‚ β€’ WhatsApp β”‚ β”‚  β”‚ β€’ CORS              β”‚                β”‚
    β”‚ β”‚ β€’ Slack    β”‚ β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                β”‚
    β”‚ β”‚ β€’ Cron     β”‚ β”‚             β”‚                            β”‚
    β”‚ β”‚ β€’ Webhooks β”‚ β”‚             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β”‚                         β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”˜                         β”‚
             β”‚ HTTP                            β”‚ HTTPS
             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                β”‚         Fly.io Container                   β”‚
                β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
                β”‚  β”‚      FastAPI Application            β”‚   β”‚
                β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚   β”‚
                β”‚  β”‚  β”‚   LangGraph Agent Core       β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”‚ Workflow Components:    β”‚ β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”‚                         β”‚ β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”‚ β€’ ComplianceWorkflow    β”‚ β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”‚ β€’ QuestionWorkflow      β”‚ β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”‚ β€’ ReportWorkflow        β”‚ β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”‚ β€’ ExtractionWorkflow    β”‚ β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚            β”‚                 β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”‚   Pydantic AI Layer     β”‚ β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚ β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”‚  β”‚ Type Validation β”‚   β”‚ β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”‚  β”‚ β€’ Request DTOs  β”‚   β”‚ β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”‚  β”‚ β€’ Response DTOs β”‚   β”‚ β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”‚  β”‚ β€’ State Objects β”‚   β”‚ β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚ β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚                              β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”‚   LLM Integration     β”‚  β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β”‚  (Claude/OpenAI)      β”‚  β”‚  β”‚   β”‚
                β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚   β”‚
                β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚   β”‚
                β”‚  β”‚                                     β”‚   β”‚
                β”‚  β”‚  FastAPI Routes:                    β”‚   β”‚
                β”‚  β”‚   POST /api/agent/assess            β”‚   β”‚
                β”‚  β”‚   POST /api/agent/question          β”‚   β”‚
                β”‚  β”‚   POST /api/agent/report            β”‚   β”‚
                β”‚  β”‚   POST /api/agent/extract           β”‚   β”‚
                β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
                β”‚                                            β”‚
                β”‚  Dependencies: (installed via uv)          β”‚
                β”‚   β€’ langgraph==0.0.28                     β”‚
                β”‚   β€’ pydantic-ai==0.0.3                    β”‚
                β”‚   β€’ fastapi==0.104.1                      β”‚
                β”‚   β€’ anthropic==0.18.1                     β”‚
                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                    β”‚
                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                        β”‚   Supabase Postgres    β”‚
                        β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
                        β”‚  β”‚ β€’ Agent State   β”‚   β”‚
                        β”‚  β”‚ β€’ Audit Logs    β”‚   β”‚
                        β”‚  β”‚ β€’ Compliance    β”‚   β”‚
                        β”‚  β”‚ β€’ Multi-tenant  β”‚   β”‚
                        β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Responsibility Matrix

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Capability        β”‚   n8n Handles    β”‚   Agent Handles    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Message Routing     β”‚       βœ“          β”‚                    β”‚
β”‚ Schedule/Cron       β”‚       βœ“          β”‚                    β”‚
β”‚ Webhooks           β”‚       βœ“          β”‚                    β”‚
β”‚ Simple Alerts      β”‚       βœ“          β”‚                    β”‚
β”‚ API Integration    β”‚       βœ“          β”‚                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Compliance Logic   β”‚                  β”‚         βœ“          β”‚
β”‚ Question Analysis  β”‚                  β”‚         βœ“          β”‚
β”‚ Report Generation  β”‚                  β”‚         βœ“          β”‚
β”‚ Risk Assessment    β”‚                  β”‚         βœ“          β”‚
β”‚ Policy Extraction  β”‚                  β”‚         βœ“          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Request Flow Example

sequenceDiagram
    participant W as WhatsApp User
    participant N as n8n
    participant C as Cloudflare
    participant A as LangGraph Agent
    participant D as Database

    W->>N: "What's our Essential Eight status?"
    Note over N: Parse message<br/>Extract tenant
    N->>C: POST /api/agent/assess
    C->>C: Verify auth
    C->>A: Forward request
    Note over A: Route to workflow<br/>Load context<br/>Run assessment
    A->>D: Get compliance data
    D->>A: Return data
    Note over A: Apply rules<br/>Generate insight
    A->>C: JSON response
    C->>N: Forward response
    Note over N: Format for WhatsApp
    N->>W: "Essential Eight Status: ML2 85% ⚠️<br/>3 gaps need attention..."

Integration Points

n8n to Agent API Calls

n8n Workflow Nodes              Agent API Endpoints
─────────────────              ──────────────────

HTTP Request Node    ────→     POST /api/agent/assess
{                              {
  "url": "{{API}}/assess",       "type": "compliance_check",
  "body": {                      "tenant_id": "abc123",
    "tenant": "{{tenant}}",      "frameworks": ["e8"],
    "type": "compliance"         "context": {...}
  }                            }
}

HTTP Request Node    ────→     POST /api/agent/question
{                              {
  "url": "{{API}}/question",     "question": "What is MFA?",
  "body": {                      "tenant_id": "abc123",
    "q": "{{message}}",          "history": [...]
    "tenant": "{{tenant}}"     }
  }
}

HTTP Request Node    ────→     POST /api/agent/report
{                              {
  "url": "{{API}}/report",       "type": "board_quarterly",
  "body": {                      "tenant_id": "abc123",
    "type": "board",             "period": "Q1-2025"
    "period": "Q1"             }
  }
}

WhatsApp Integration Flow

User types in WhatsApp: "Check our compliance"
                            β”‚
                            β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ n8n: WhatsApp Webhook Trigger                β”‚
β”‚ β€’ Extracts: phone number, message, timestamp β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ n8n: Tenant Lookup Node                      β”‚
β”‚ β€’ Query DB for tenant by phone               β”‚
β”‚ β€’ Get user context                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ n8n: Route by Keywords                       β”‚
β”‚ β€’ "compliance" β†’ /api/agent/assess           β”‚
β”‚ β€’ "report" β†’ /api/agent/report               β”‚
β”‚ β€’ Question β†’ /api/agent/question             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ n8n: HTTP Request to Agent                   β”‚
β”‚ β€’ Add auth headers                           β”‚
β”‚ β€’ Include tenant context                     β”‚
β”‚ β€’ Set timeout (30s)                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ LangGraph Agent Processing                   β”‚
β”‚ β€’ Understand intent                          β”‚
β”‚ β€’ Execute workflow                           β”‚
β”‚ β€’ Generate response                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ n8n: Format Response                         β”‚
β”‚ β€’ Convert JSON to WhatsApp format            β”‚
β”‚ β€’ Add emojis for status                      β”‚
β”‚ β€’ Truncate if > 1600 chars                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ n8n: Send WhatsApp Reply                     β”‚
β”‚ β€’ Via Twilio API                             β”‚
β”‚ β€’ Track delivery status                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

LangGraph and Pydantic Integration

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Incoming Request                          β”‚
β”‚                  (from n8n or API)                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚
                        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                 FastAPI Endpoint                            β”‚
β”‚  @app.post("/api/agent/assess")                            β”‚
β”‚  async def assess_compliance(                               β”‚
β”‚      request: ComplianceRequest  # ← Pydantic Model        β”‚
β”‚  ) -> ComplianceResponse:        # ← Pydantic Model        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚
                        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              Pydantic AI Validation Layer                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ class ComplianceRequest(BaseModel):                 β”‚   β”‚
β”‚  β”‚     tenant_id: UUID                                 β”‚   β”‚
β”‚  β”‚     assessment_type: Literal["e8", "iso", "risk"]   β”‚   β”‚
β”‚  β”‚     context: Dict[str, Any]                         β”‚   β”‚
β”‚  β”‚     include_evidence: bool = True                   β”‚   β”‚
β”‚  β”‚                                                     β”‚   β”‚
β”‚  β”‚     @validator('tenant_id')                         β”‚   β”‚
β”‚  β”‚     def validate_tenant(cls, v):                    β”‚   β”‚
β”‚  β”‚         # Check tenant exists & authorized          β”‚   β”‚
β”‚  β”‚         return v                                    β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚ Validated & Typed
                        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  LangGraph Workflow                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ workflow = StateGraph(ComplianceState)              β”‚   β”‚
β”‚  β”‚                                                     β”‚   β”‚
β”‚  β”‚ # Define state with Pydantic                        β”‚   β”‚
β”‚  β”‚ class ComplianceState(BaseModel):                   β”‚   β”‚
β”‚  β”‚     request: ComplianceRequest                      β”‚   β”‚
β”‚  β”‚     current_step: str                               β”‚   β”‚
β”‚  β”‚     evidence: List[Evidence]                        β”‚   β”‚
β”‚  β”‚     scores: Dict[str, float]                        β”‚   β”‚
β”‚  β”‚     reasoning: List[ReasoningStep]                  β”‚   β”‚
β”‚  β”‚                                                     β”‚   β”‚
β”‚  β”‚ # Workflow nodes                                    β”‚   β”‚
β”‚  β”‚ workflow.add_node("validate", validate_input)       β”‚   β”‚
β”‚  β”‚ workflow.add_node("gather", gather_evidence)        β”‚   β”‚
β”‚  β”‚ workflow.add_node("assess", run_assessment)         β”‚   β”‚
β”‚  β”‚ workflow.add_node("report", generate_report)        β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚
                        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   LLM Integration                           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ # Only called when needed                           β”‚   β”‚
β”‚  β”‚ async def interpret_ambiguous_requirement(          β”‚   β”‚
β”‚  β”‚     requirement: str,                               β”‚   β”‚
β”‚  β”‚     context: AssessmentContext  # Pydantic         β”‚   β”‚
β”‚  β”‚ ) -> Interpretation:            # Pydantic         β”‚   β”‚
β”‚  β”‚     response = await llm.complete(                  β”‚   β”‚
β”‚  β”‚         prompt=ASSESSMENT_PROMPT,                   β”‚   β”‚
β”‚  β”‚         context=context.dict()                      β”‚   β”‚
β”‚  β”‚     )                                               β”‚   β”‚
β”‚  β”‚     return Interpretation.parse_obj(response)       β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Data Type Flow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ n8n Workflow (JavaScript)                            β”‚
β”‚                                                      β”‚
β”‚ const requestBody = {                                β”‚
β”‚   tenant_id: msg.extractedTenantId,                  β”‚
β”‚   assessment_type: "e8",                             β”‚
β”‚   context: {                                         β”‚
β”‚     message: msg.whatsappText,                       β”‚
β”‚     user_phone: msg.from                             β”‚
β”‚   }                                                  β”‚
β”‚ }                                                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚ JSON over HTTP
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ FastAPI + Pydantic (Python)                          β”‚
β”‚                                                      β”‚
β”‚ class ComplianceRequest(BaseModel):                  β”‚
β”‚     tenant_id: UUID                                  β”‚
β”‚     assessment_type: AssessmentType                  β”‚
β”‚     context: Dict[str, Any]                          β”‚
β”‚                                                      β”‚
β”‚     class Config:                                    β”‚
β”‚         json_schema_extra = {                        β”‚
β”‚             "example": {                             β”‚
β”‚                 "tenant_id": "123e4567-...",         β”‚
β”‚                 "assessment_type": "e8",             β”‚
β”‚                 "context": {...}                     β”‚
β”‚             }                                        β”‚
β”‚         }                                            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚ Typed Python Objects
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ LangGraph State (Pydantic Models)                    β”‚
β”‚                                                      β”‚
β”‚ class ComplianceState(BaseModel):                    β”‚
β”‚     request: ComplianceRequest                       β”‚
β”‚     current_step: WorkflowStep                       β”‚
β”‚     evidence: List[Evidence]                         β”‚
β”‚     scores: Dict[Framework, Score]                   β”‚
β”‚     reasoning: List[ReasoningStep]                   β”‚
β”‚     final_output: Optional[ComplianceResponse]       β”‚
β”‚                                                      β”‚
β”‚     def next_step(self) -> WorkflowStep:            β”‚
β”‚         """Determine next workflow step"""           β”‚
β”‚         ...                                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Component Deployment

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   Infrastructure                         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   n8n (VPS)     β”‚  Agent (Fly)   β”‚  Gateway (CF)       β”‚
β”‚                 β”‚                β”‚                     β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Ubuntu 22   β”‚ β”‚ β”‚ Container  β”‚ β”‚ β”‚ Workers Script  β”‚ β”‚
β”‚ β”‚ Docker      β”‚ β”‚ β”‚ Python 3.11β”‚ β”‚ β”‚ TypeScript      β”‚ β”‚
β”‚ β”‚ n8n:latest  β”‚ β”‚ β”‚ uv package β”‚ β”‚ β”‚ Wrangler deploy β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚                 β”‚                β”‚                     β”‚
β”‚ Resources:      β”‚ Resources:    β”‚ Resources:          β”‚
β”‚ β€’ 2 vCPU        β”‚ β€’ 4 vCPU      β”‚ β€’ 10ms CPU          β”‚
β”‚ β€’ 4GB RAM       β”‚ β€’ 8GB RAM     β”‚ β€’ 128MB RAM         β”‚
β”‚ β€’ 20GB SSD      β”‚ β€’ 10GB volume β”‚ β€’ Global Edge       β”‚
β”‚                 β”‚ β€’ Multi-regionβ”‚                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Managed by: Pulumi (Infrastructure as Code)

Communication Flow Example

Essential Eight Assessment via WhatsApp

User Request: "Show me BuildCo compliance status"
                          β”‚
                          β–Ό
            WhatsApp ──→ n8n ──→ Workers
                                    β”‚
                                    β–Ό
                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                        β”‚  GetCimple Agent    β”‚
                        β”‚                     β”‚
                        β”‚  1. Route Request   β”‚
                        β”‚       ↓             β”‚
                        β”‚  2. Load Context    β”‚
                        β”‚       ↓             β”‚
                        β”‚  3. Check Cache     β”‚ ← Deterministic
                        β”‚       ↓             β”‚
                        β”‚  4. Apply Essential Eight Rules  β”‚ ← Deterministic
                        β”‚       ↓             β”‚
                        β”‚  5. LLM for Gaps    β”‚ ← Only if needed
                        β”‚       ↓             β”‚
                        β”‚  6. Format Response β”‚ ← Template-based
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                    β”‚
                                    β–Ό
                        "BuildCo Compliance Status:

                         Core Frameworks:
                         [E8] ML2 (85%) ⚠️
                         [S180] 2 items need board review ❌
                         [Privacy] Compliant βœ…
                         [ACSC] Following guidelines βœ…

                         3 gaps need attention:
                         1. MFA not enforced [E8] [S180]
                         2. Patch cycle > 30 days [E8]
                         3. Privacy policy review overdue [Privacy] [S180]"

Key Design Decisions

Why Separate n8n and LangGraph?

  1. Reliability: n8n handles deterministic tasks that must always work
  2. Cost: Only use expensive LLM calls when truly needed
  3. Debugging: Clear separation makes issues easier to trace
  4. Scaling: Can scale n8n and agent independently
  5. Flexibility: Easy to swap AI providers or upgrade agent logic

Why Pydantic AI?

  1. Type Safety: Catch errors before they reach production
  2. Documentation: Auto-generated API docs from models
  3. Validation: Business rules enforced at boundaries
  4. Compliance: Audit trail needs structured data

Why This Architecture?

  1. Simple for MVP: Just two main services to manage
  2. Clear boundaries: Everyone knows what each component does
  3. Easy to evolve: Can add agents or workflows independently
  4. Cost effective: Minimal infrastructure for maximum value

Implementation Checklist

  • Deploy n8n container with basic workflows
  • Set up FastAPI with LangGraph on Fly.io
  • Configure Cloudflare Workers gateway
  • Create Pydantic models for all data types
  • Implement the 4 core agent workflows
  • Connect n8n to agent via HTTP
  • Test WhatsApp integration end-to-end
  • Add monitoring and error handling
  • Document n8n workflow templates
  • Create runbooks for common issues

Related Documents: