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) andadapters
(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
- Webhook Reception: A user sends a message to the WhatsApp number. The WhatsApp Cloud API sends a webhook to the application's
/webhook
endpoint. - Command Translation: The API layer receives the webhook payload and translates it into a specific
Command
(e.g.,InitiateSession
). - Command Handling: The command is dispatched to its corresponding handler in the application layer.
- 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. - 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
. - 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
. - 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. - 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
). - Side Effects: The event handler executes the side effect logic, such as using a
CrmService
adapter to send a notification to the CRM or anS3Storage
adapter to manage files.