Skip to main content

Architectural Overview

This document provides a high-level overview of the WhatsApp Agent's architecture. It is intended for developers who want to understand how the system works, how to contribute, and how to extend its functionality.

Core Principles

The system is built on several key software design principles:

  • Domain-Driven Design (DDD): We model the software around the business domain of interactive user sessions. The core logic is isolated in a domain layer, free from infrastructure concerns.
  • Event Sourcing: Instead of storing the current state of our entities, we store a full history of the events that have happened to them. This provides a complete audit log, makes debugging easier, and allows for powerful data analysis.
  • Ports and Adapters (Hexagonal Architecture): The core application logic is completely decoupled from external services like databases, messaging queues, and third-party APIs. This is achieved through ports (interfaces) and adapters (implementations), making the system highly pluggable and testable.

System Diagram

The following diagram illustrates the flow of information through the system, from an incoming WhatsApp message to a notification being sent to a CRM.

Request Flow Walkthrough

  1. Webhook Reception: A user sends a message to the WhatsApp number. The WhatsApp Cloud API sends a webhook to the application's /webhook endpoint.
  2. Command Translation: The API layer receives the webhook payload and translates it into a specific Command (e.g., InitiateSession).
  3. Command Handling: The command is dispatched to its corresponding handler in the application layer.
  4. Aggregate Hydration: The handler uses an event-sourced repository to load the relevant InteractiveSession aggregate. The repository reads all historical events for that session from the PostgreSQL event store and replays them to reconstruct the aggregate's current state.
  5. Business Logic: The handler invokes a method on the aggregate. The aggregate performs its business logic and, if successful, produces one or more new Domain Events.
  6. Event Persistence & Publishing: The handler saves the aggregate. The repository appends the new events to the event store and publishes them to an in-process Event Bus.
  7. Asynchronous Event Handling: An event bus subscriber (e.g., ArqEventPublisher) receives the event and enqueues a job in Redis for an ARQ worker to process it asynchronously. This decouples the API response from side effects.
  8. Worker Processing: An ARQ worker picks up the job and dispatches the event to the relevant Event Handler in the application layer (e.g., FileUploadedEventHandler).
  9. Side Effects: The event handler executes the side effect logic, such as using a CrmService adapter to send a notification to the CRM or an S3Storage adapter to manage files.