# juanfer93/passive_crm_nestjs architecture

> Architecture diagram of the GitHub repository juanfer93/passive_crm_nestjs, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-16). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/juanfer93/passive_crm_nestjs
- Repository: https://github.com/juanfer93/passive_crm_nestjs

## Overview

1. This repo is a NestJS backend that sits between inbound messaging channels and the VIVA OS. Its core job is conversational intake: receive lead messages, maintain conversational memory, qualify the lead, extract structured fields, and publish events outward. It does not own operational execution such as calls, tasks, appointments, or follow-up execution; that boundary belongs to VIVA.

2. The application is split into three feature modules under `src/features`: `meta-messaging-webhook`, `sofia-engine`, and `whatsapp-web`. The first is the main conversational pipeline, the second is the internal event/decision bridge to VIVA, and the third is a transport adapter for WhatsApp Web that feeds the same conversation engine.

3. In `meta-messaging-webhook`, the architecture follows Nest’s controller → use case → domain service → infrastructure adapter layering. The presentation layer exposes the webhook controller and signature guard; the application layer contains the orchestration use cases such as accepting the webhook, verifying it, processing incoming messages, ensuring user profiles, and running due follow-ups; the domain layer holds entities, ports, and pure services; the infrastructure layer implements adapters for Mongo, Meta, OpenAI, GHL, VIVA, and background execution.

4. The inbound message flow starts at a Meta webhook request, passes through `MetaSignatureGuard`, then the controller hands it to `accept-meta-webhook` / `verify-meta-webhook` and the message-processing use case. Before any conversational logic runs, the system checks idempotency using a Mongo-backed message receipt store so duplicate platform deliveries do not create duplicate side effects.

5. Conversation state is persisted in MongoDB and treated as the source of truth for conversational memory. The repository includes schemas for conversation state and message receipts, plus domain entities for customer profile, dealer profile, assistant context, follow-up state, incoming messages, media content, and lead custom fields. This is the main data boundary where raw channel events become durable lead memory.

6. The AI/conversation subsystem is centered on extracting structured lead data from unstructured chat. OpenAI adapters are used for assistant replies, media analysis, and likely transcript/image understanding, while domain services normalize and derive fields such as vehicle interest, down payment, language, appointment date, and lead temperature. Dealer-specific prompts shape the conversational behavior and qualification flow.

7. The system also has a clear media-handling branch: audio is transcribed, images are analyzed, and unsupported media is marked as non-textual while the conversation continues. That keeps the qualification flow resilient across Messenger, Instagram, and WhatsApp without making media processing a hard dependency for every incoming message.

8. Qualification and profile enrichment are separated from transport concerns. Services such as dealer profile resolution, lead custom field normalization, courtesy reply generation, and reactivation/follow-up logic encapsulate business rules for turning message history into actionable lead state. The application layer coordinates these rules rather than embedding them in controllers.

9. External CRM and business-event integrations are adapters behind ports. The repo includes sinks for GHL and a composite CRM sink, plus a Viva Sofia event publisher. This means the conversation engine can sync lead updates outward without knowing whether the target is GHL, VIVA, or both.

10. The VIVA boundary is explicit and important: NestJS emits Sofia events like `lead.created`, `lead.updated`, `buyer_dna_updated`, `appointment.created`, and `document.received` to `POST /api/sofia/event`. The `sofia-engine` module is the inbound side of that contract on the VIVA-facing boundary, with its own controller, access guard, application services, and Mongo persistence for Sofia actions, activities, and recommendations.

11. Background work is isolated from request handling. The `background` infrastructure contains a Node task runner and a follow-up worker, and there is a `process-due-follow-ups` use case in the application layer. This separation lets the webhook path stay low-latency while scheduled or deferred actions run asynchronously.

12. WhatsApp is treated as an additional transport, not a separate brain. The `whatsapp-web` module provides a client service and controller so WhatsApp Web messages enter the same conversational architecture, reusing the same memory, extraction, and event-emission patterns as Meta messaging.

13. The repository is organized as a classic Nest monolith with strong internal boundaries rather than microservices. `AppModule` composes the feature modules, while the surrounding scripts support simulation of chat and media flows for local testing. The architecture diagram should therefore show one NestJS runtime with multiple channel ingress points, a shared conversation core, Mongo persistence, and outbound adapters to OpenAI, CRM systems, and VIVA.

Main entry points: [`src/features/meta-messaging-webhook/application/use-cases/process-incoming-meta-message.use-case.ts`](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/application/use-cases/process-incoming-meta-message.use-case.ts) (Process message), [`src/app.module.ts`](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/app.module.ts) (App module), [`src/features/meta-messaging-webhook/presentation/controllers/meta-messaging-webhook.controller.ts`](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/presentation/controllers/meta-messaging-webhook.controller.ts) (Webhook controller), [`src/features/sofia-engine/presentation/controllers/sofia-engine.controller.ts`](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/sofia-engine/presentation/controllers/sofia-engine.controller.ts) (Sofia controller)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_runtime["Nest runtime"]
  node_main(("App bootstrap<br/>nest bootstrap<br/>[main.ts]"))
  node_app_module["App module<br/>nest module<br/>[app.module.ts]"]
end

subgraph group_meta["Meta messaging"]
  node_meta_module["Meta module<br/>feature module"]
  node_meta_controller["Webhook controller<br/>presentation"]
  node_meta_guard["Signature guard<br/>auth guard"]
  node_accept_webhook["Accept webhook<br/>use case"]
  node_verify_webhook["Verify webhook<br/>use case"]
  node_process_message["Process message<br/>use case"]
  node_ensure_profile["Ensure profile<br/>use case"]
  node_due_followups["Due follow-ups<br/>use case"]
  node_extractor["Message extractor<br/>app service"]
  node_dealer_profile["Dealer profile<br/>app service"]
  node_lead_normalizer["Field normalizer<br/>domain service"]
  node_conversation_store[("Conversation store<br/>mongo repo")]
  node_idempotency_store[("Receipt store<br/>mongo store")]
  node_openai_adapter["OpenAI adapter"]
  node_crm_sink["CRM sink<br/>outbound sink"]
  node_viva_publisher["VIVA publisher<br/>event adapter"]
  node_bg_runner["Background runner<br/>task runner"]
  node_followup_worker["Follow-up worker"]
end

subgraph group_sofia["Sofia engine"]
  node_sofia_module["Sofia module<br/>feature module"]
  node_sofia_controller["Sofia controller<br/>presentation"]
  node_sofia_guard["Access guard<br/>auth guard"]
  node_sofia_bridge["Webhook bridge<br/>app service"]
  node_sofia_core["Sofia logic<br/>app services"]
  node_sofia_persistence[("Sofia storage<br/>mongo schemas")]
end

subgraph group_whatsapp["WhatsApp web"]
  node_whatsapp_module["WhatsApp module<br/>feature module"]
  node_whatsapp_controller["WhatsApp controller<br/>presentation"]
  node_whatsapp_client["Client service<br/>transport service"]
end

node_main -->|"bootstraps"| node_app_module
node_app_module -->|"imports"| node_meta_module
node_app_module -->|"imports"| node_sofia_module
node_app_module -->|"imports"| node_whatsapp_module
node_meta_controller -->|"protected by"| node_meta_guard
node_meta_controller -->|"delegates"| node_accept_webhook
node_meta_controller -->|"delegates"| node_verify_webhook
node_accept_webhook -->|"invokes"| node_process_message
node_process_message -->|"checks"| node_idempotency_store
node_process_message -->|"parses"| node_extractor
node_process_message -->|"ensures"| node_ensure_profile
node_process_message -->|"loads"| node_dealer_profile
node_process_message -->|"reads/writes"| node_conversation_store
node_process_message -->|"uses"| node_openai_adapter
node_process_message -->|"derives"| node_lead_normalizer
node_process_message -->|"syncs"| node_crm_sink
node_process_message -->|"emits"| node_viva_publisher
node_process_message -->|"schedules"| node_bg_runner
node_due_followups -->|"runs on"| node_followup_worker
node_bg_runner -->|"dispatches"| node_followup_worker
node_sofia_controller -->|"protected by"| node_sofia_guard
node_sofia_controller -->|"delegates"| node_sofia_bridge
node_sofia_bridge -->|"coordinates"| node_sofia_core
node_sofia_core -->|"persists"| node_sofia_persistence
node_viva_publisher -->|"delivers"| node_sofia_controller
node_whatsapp_controller -->|"uses"| node_whatsapp_client
node_whatsapp_controller -->|"feeds"| node_process_message

click node_main "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/main.ts"
click node_app_module "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/app.module.ts"
click node_meta_module "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/meta-messaging-webhook.module.ts"
click node_meta_controller "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/presentation/controllers/meta-messaging-webhook.controller.ts"
click node_meta_guard "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/presentation/guards/meta-signature.guard.ts"
click node_accept_webhook "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/application/use-cases/accept-meta-webhook.use-case.ts"
click node_verify_webhook "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/application/use-cases/verify-meta-webhook.use-case.ts"
click node_process_message "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/application/use-cases/process-incoming-meta-message.use-case.ts"
click node_ensure_profile "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/application/use-cases/ensure-meta-user-profile.use-case.ts"
click node_due_followups "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/application/use-cases/process-due-follow-ups.use-case.ts"
click node_extractor "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/application/services/meta-webhook-message-extractor.service.ts"
click node_dealer_profile "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/application/services/dealer-profile-resolver.service.ts"
click node_lead_normalizer "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/domain/services/lead-custom-fields-normalizer.service.ts"
click node_conversation_store "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/infrastructure/mongo/mongo-conversation-state.repository.ts"
click node_idempotency_store "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/infrastructure/mongo/mongo-message-idempotency.store.ts"
click node_openai_adapter "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/infrastructure/openai/openai-assistant.adapter.ts"
click node_crm_sink "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/infrastructure/hln/composite-crm-sink.adapter.ts"
click node_viva_publisher "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/infrastructure/viva/viva-sofia-event.adapter.ts"
click node_bg_runner "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/infrastructure/background/node-background-task-runner.ts"
click node_followup_worker "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/infrastructure/background/node-follow-up-worker.ts"
click node_sofia_module "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/sofia-engine/sofia-engine.module.ts"
click node_sofia_controller "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/sofia-engine/presentation/controllers/sofia-engine.controller.ts"
click node_sofia_guard "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/sofia-engine/presentation/guards/sofia-access.guard.ts"
click node_sofia_bridge "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/sofia-engine/application/services/sofia-webhook-bridge.service.ts"
click node_sofia_core "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/sofia-engine/application/services/sofia-decision.service.ts"
click node_sofia_persistence "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/sofia-engine/infrastructure/mongo/schemas/sofia-action.schema.ts"
click node_whatsapp_module "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/whatsapp-web/whatsapp-web.module.ts"
click node_whatsapp_controller "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/whatsapp-web/presentation/controllers/whatsapp-web.controller.ts"
click node_whatsapp_client "https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/whatsapp-web/application/services/whatsapp-web-client.service.ts"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_main,node_app_module toneBlue
class node_meta_module,node_meta_controller,node_meta_guard,node_accept_webhook,node_verify_webhook,node_process_message,node_ensure_profile,node_due_followups,node_extractor,node_dealer_profile,node_lead_normalizer,node_conversation_store,node_idempotency_store,node_openai_adapter,node_crm_sink,node_viva_publisher,node_bg_runner,node_followup_worker toneAmber
class node_sofia_module,node_sofia_controller,node_sofia_guard,node_sofia_bridge,node_sofia_core,node_sofia_persistence toneMint
class node_whatsapp_module,node_whatsapp_controller,node_whatsapp_client toneRose
```

## Components

### Nest runtime

Application bootstrap and composed feature modules

- [App bootstrap](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/main.ts): nest bootstrap · Starts the Nest application and composes feature modules · `src/main.ts`
- [App module](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/app.module.ts): nest module · Root module wiring the repository features together · `src/app.module.ts`

### Meta messaging

Main conversational intake pipeline

- [Meta module](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/meta-messaging-webhook.module.ts): feature module · Webhook intake and conversational processing feature · `src/features/meta-messaging-webhook/meta-messaging-webhook.module.ts`
- [Webhook controller](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/presentation/controllers/meta-messaging-webhook.controller.ts): presentation · Receives Meta webhook traffic and delegates orchestration · `src/features/meta-messaging-webhook/presentation/controllers/meta-messaging-webhook.controller.ts`
- [Signature guard](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/presentation/guards/meta-signature.guard.ts): auth guard · Verifies Meta webhook signatures before processing · `src/features/meta-messaging-webhook/presentation/guards/meta-signature.guard.ts`
- [Accept webhook](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/application/use-cases/accept-meta-webhook.use-case.ts): use case · Entry orchestration for inbound webhook delivery · `src/features/meta-messaging-webhook/application/use-cases/accept-meta-webhook.use-case.ts`
- [Verify webhook](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/application/use-cases/verify-meta-webhook.use-case.ts): use case · Handles webhook verification handshake · `src/features/meta-messaging-webhook/application/use-cases/verify-meta-webhook.use-case.ts`
- [Process message](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/application/use-cases/process-incoming-meta-message.use-case.ts): use case · Runs the core message intake and conversation update flow · `src/features/meta-messaging-webhook/application/use-cases/process-incoming-meta-message.use-case.ts`
- [Ensure profile](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/application/use-cases/ensure-meta-user-profile.use-case.ts): use case · Resolves or creates the user profile before qualification · `src/features/meta-messaging-webhook/application/use-cases/ensure-meta-user-profile.use-case.ts`
- [Due follow-ups](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/application/use-cases/process-due-follow-ups.use-case.ts): use case · Processes deferred follow-up work · `src/features/meta-messaging-webhook/application/use-cases/process-due-follow-ups.use-case.ts`
- [Message extractor](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/application/services/meta-webhook-message-extractor.service.ts): app service · Normalizes webhook payloads into internal message data · `src/features/meta-messaging-webhook/application/services/meta-webhook-message-extractor.service.ts`
- [Dealer profile](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/application/services/dealer-profile-resolver.service.ts): app service · Resolves dealer-specific qualification behavior and prompts · `src/features/meta-messaging-webhook/application/services/dealer-profile-resolver.service.ts`
- [Field normalizer](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/domain/services/lead-custom-fields-normalizer.service.ts): domain service · Derives structured lead fields from conversation state · `src/features/meta-messaging-webhook/domain/services/lead-custom-fields-normalizer.service.ts`
- [Conversation store](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/infrastructure/mongo/mongo-conversation-state.repository.ts): mongo repo · Persists conversation state as the source of truth · `src/features/meta-messaging-webhook/infrastructure/mongo/mongo-conversation-state.repository.ts`
- [Receipt store](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/infrastructure/mongo/mongo-message-idempotency.store.ts): mongo store · Deduplicates repeated platform deliveries · `src/features/meta-messaging-webhook/infrastructure/mongo/mongo-message-idempotency.store.ts`
- [OpenAI adapter](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/infrastructure/openai/openai-assistant.adapter.ts): ai adapter · Generates assistant replies and analyzes media or transcripts · `src/features/meta-messaging-webhook/infrastructure/openai/openai-assistant.adapter.ts`
- [CRM sink](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/infrastructure/hln/composite-crm-sink.adapter.ts): outbound sink · Composite outbound sync toward CRM systems · `src/features/meta-messaging-webhook/infrastructure/hln/composite-crm-sink.adapter.ts`
- [VIVA publisher](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/infrastructure/viva/viva-sofia-event.adapter.ts): event adapter · Emits Sofia events outward to VIVA · `src/features/meta-messaging-webhook/infrastructure/viva/viva-sofia-event.adapter.ts`
- [Background runner](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/infrastructure/background/node-background-task-runner.ts): task runner · Runs deferred work outside request handling · `src/features/meta-messaging-webhook/infrastructure/background/node-background-task-runner.ts`
- [Follow-up worker](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/meta-messaging-webhook/infrastructure/background/node-follow-up-worker.ts): worker · Executes scheduled follow-up actions · `src/features/meta-messaging-webhook/infrastructure/background/node-follow-up-worker.ts`

### Sofia engine

VIVA-facing event and decision bridge

- [Sofia module](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/sofia-engine/sofia-engine.module.ts): feature module · Inbound VIVA-side engine for Sofia actions and recommendations · `src/features/sofia-engine/sofia-engine.module.ts`
- [Sofia controller](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/sofia-engine/presentation/controllers/sofia-engine.controller.ts): presentation · Receives Sofia events on the VIVA-facing boundary · `src/features/sofia-engine/presentation/controllers/sofia-engine.controller.ts`
- [Access guard](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/sofia-engine/presentation/guards/sofia-access.guard.ts): auth guard · Protects the Sofia event ingress · `src/features/sofia-engine/presentation/guards/sofia-access.guard.ts`
- [Webhook bridge](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/sofia-engine/application/services/sofia-webhook-bridge.service.ts): app service · Bridges inbound events into Sofia processing · `src/features/sofia-engine/application/services/sofia-webhook-bridge.service.ts`
- [Sofia logic](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/sofia-engine/application/services/sofia-decision.service.ts): app services · Decision, context, learning, action, and activity services · `src/features/sofia-engine/application/services/sofia-decision.service.ts`
- [Sofia storage](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/sofia-engine/infrastructure/mongo/schemas/sofia-action.schema.ts): mongo schemas · Stores Sofia actions, activities, and recommendations · `src/features/sofia-engine/infrastructure/mongo/schemas/sofia-action.schema.ts`

### WhatsApp web

Additional inbound transport

- [WhatsApp module](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/whatsapp-web/whatsapp-web.module.ts): feature module · WhatsApp Web transport adapter · `src/features/whatsapp-web/whatsapp-web.module.ts`
- [WhatsApp controller](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/whatsapp-web/presentation/controllers/whatsapp-web.controller.ts): presentation · Ingress for WhatsApp Web messages · `src/features/whatsapp-web/presentation/controllers/whatsapp-web.controller.ts`
- [Client service](https://github.com/juanfer93/passive_crm_nestjs/blob/main/src/features/whatsapp-web/application/services/whatsapp-web-client.service.ts): transport service · Handles WhatsApp Web client interactions · `src/features/whatsapp-web/application/services/whatsapp-web-client.service.ts`

## Connections

- App bootstrap → App module: bootstraps · Application entrypoint initializes the root module
- App module → Meta module: imports · Composes the conversational intake feature
- App module → Sofia module: imports · Composes the VIVA-facing Sofia bridge
- App module → WhatsApp module: imports · Composes the WhatsApp transport feature
- Webhook controller → Signature guard: protected by · Webhook ingress is signed before handling
- Webhook controller → Accept webhook: delegates · Primary webhook intake passes to orchestration
- Webhook controller → Verify webhook: delegates · Verification requests use dedicated handshake logic
- Accept webhook → Process message: invokes · Accepted deliveries proceed into message processing
- Process message → Receipt store: checks · Duplicate platform deliveries are filtered first
- Process message → Message extractor: parses · Webhook payloads are normalized into internal message data
- Process message → Ensure profile: ensures · User profile is ready before qualification logic runs
- Process message → Dealer profile: loads · Dealer-specific behavior shapes the conversation flow
- Process message → Conversation store: reads/writes · Conversation memory is persisted as the source of truth
- Process message → OpenAI adapter: uses · Assistant replies and media understanding rely on AI adapters
- Process message → Field normalizer: derives · Structured lead fields are extracted from conversation state
- Process message → CRM sink: syncs · Lead updates are pushed to external CRM sinks
- Process message → VIVA publisher: emits · Lead and qualification events are published to VIVA
- Process message → Background runner: schedules · Deferred work is offloaded from the request path
- Due follow-ups → Follow-up worker: runs on · Follow-up processing executes asynchronously
- Background runner → Follow-up worker: dispatches · Background runner hands off deferred tasks
- Sofia controller → Access guard: protected by · Sofia ingress is access-controlled
- Sofia controller → Webhook bridge: delegates · Inbound Sofia events enter through the bridge service
- Webhook bridge → Sofia logic: coordinates · Bridge forwards events into Sofia processing services
- Sofia logic → Sofia storage: persists · Decisions, actions, and recommendations are stored in Mongo
- VIVA publisher → Sofia controller: delivers · Meta-side events are consumed by the Sofia boundary
- WhatsApp controller → Client service: uses · Controller delegates transport handling to the client service
- WhatsApp controller → Process message: feeds · WhatsApp messages enter the same conversation engine
