Processes

GoConva runs as three deployable pieces: The voice worker is separate on purpose — voice sessions are long-lived and CPU-bound in a way that would degrade API latency if colocated.

Request path

A request enters the LoopBack sequence, passes through middleware, and reaches a controller. Controllers validate and route; services hold the logic; repositories talk to MongoDB. Authorization uses Casbin, with policies in src/casbin/. Two authentication strategies coexist: JWT for users, and workspace API keys presented in the x-api-key header.
CORS preflight requests bypass the LoopBack sequence entirely — only the cors.origin callback runs. When debugging a failing preflight, instrument that callback; adding logging to the sequence will show you nothing.

Data model

MongoDB, accessed through LoopBack repositories. The workspace is the tenant boundary: agents, connections, knowledge bases, CRM records, and API keys all carry a workSpaceId, and queries are scoped by it. All workspaces share one database today. The trade-offs of splitting per workspace are recorded in ADR 0004.

Real-time

Socket.IO delivers live updates — new messages, conversation state, execution progress.
Production runs multi-instance behind a load balancer, and Socket.IO emits do not cross instances. An event emitted on instance A never reaches a client connected to instance B. Do not build a feature that depends on push alone without a shared adapter; the @socket.io/redis-adapter dependency is present for this reason.

Integrations

Each external service has a controller for its OAuth flow and a service wrapping its API. Credentials live in a connection record, encrypted at rest, keyed by a profile string. Adding an integration means: a controller exposing GET /connect/{service}, a service implementing testConnection and the calls you need, registration in ConnectController, and workflow steps that expose it to agents.

Voice

A call arrives at Twilio, which hands it to LiveKit over SIP. The Python worker joins the room, runs speech-to-text, drives the agent, and speaks the reply. LiveKit posts lifecycle events back to /webhooks/livekit so the conversation closes out when the call ends. The chat widget’s voice mode uses the same worker and LiveKit rooms, minus SIP and the phone number.

Knowledge and retrieval

Knowledge base sources — uploads, crawled URLs, documents — are chunked, embedded, and stored in Chroma. Retrieval happens at answer time and is scoped to the agent’s configured sources.

Background work

BullMQ and RabbitMQ handle asynchronous work: campaign dispatch, conversation summarization, CRM counter maintenance, and knowledge base ingestion. Long or bursty work belongs on a queue, not in a request.