# DeskcommCRM Architecture: Deep Dive into the AI-Native Sales CRM Built on Next.js and Supabase

> Explore the AI-native sales CRM architecture of DeskcommCRM. Learn how Next.js, Supabase, and Vercel AI Gateway power automated conversational sales workflows for enhanced efficiency.

- Repository: [Rafael Melgaço/DeskcommCRM](https://github.com/melgarafael/DeskcommCRM)
- Tags: architecture
- Published: 2026-09-12

---

**DeskcommCRM is a multi-tenant, AI-native sales platform that combines a Next.js 16 frontend, Supabase Postgres with Row-Level Security, WAHA WhatsApp integration, and a dedicated agent-engine powered by the Vercel AI Gateway to deliver automated conversational sales workflows.**

The architecture of DeskcommCRM prioritizes data isolation, extensibility, and first-class AI integration. According to the `melgarafael/DeskcommCRM` source code, the system runs as a VPS-hosted application with distinct layers for data persistence, message ingestion, AI orchestration, and background job processing.

## Core Application Layer (Next.js 16 + React 19)

The foundation of DeskcommCRM is a modern Next.js application using the App Router pattern with TypeScript.

### App Router and Tenant Isolation

The authenticated user interface lives in `app/app/`, while platform administration resides in `app/admin/`. Server Actions handle onboarding, settings, and workflow configurations. The UI components leverage **React 19** features and a custom design system located in `app/design/lib/`.

### API Handlers and Edge Middleware

REST endpoints are versioned under `/api/v1/` and located in `app/api/v1/`. Each handler validates input using **Zod**, enforces Role-Based Access Control (RBAC) via `requireRole()`, and returns standardized responses through `ok()` and `fail()` utilities. The edge middleware ([`proxy.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/proxy.ts)) injects a global `X-Request-Id` header and performs authentication guards before the Next.js router executes.

## Multi-Tenant Data Layer (Supabase + RLS)

DeskcommCRM implements strict multi-tenancy through PostgreSQL Row-Level Security (RLS) policies.

### Schema Design and Security Policies

All tenant-aware tables include an `organization_id` column protected by RLS rules defined in `supabase/migrations/`. This ensures complete data isolation between organizations at the database level. The migration files are versioned, with the baseline schema stored in [`supabase/baseline.sql`](https://github.com/melgarafael/DeskcommCRM/blob/main/supabase/baseline.sql) for idempotent fresh installations.

### Service-Role Access and Migrations

Internal routes bypass RLS using a service-role client defined in [`lib/supabase/admin.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/supabase/admin.ts). Every query using this client must explicitly filter by `organization_id` to maintain security boundaries. Schema changes ship as numbered migrations (e.g., `0023_ai_agents_module`, `0040_conversation_routing_emit`) with a comprehensive manifest documented in [`supabase/migrations/MANIFEST.md`](https://github.com/melgarafael/DeskcommCRM/blob/main/supabase/migrations/MANIFEST.md).

## WhatsApp Integration Architecture (WAHA)

The platform integrates WhatsApp messaging through **WAHA**, an external engine using the NOWEB protocol.

### Inbound Message Ingestion

Incoming WhatsApp events are processed by [`lib/waha/ingest.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/waha/ingest.ts), which creates **channel sessions** and emits structured events to the `event_log` table (e.g., `lead.created`, `message.inbound`). The system includes regex-based unsubscribe detection defined in [`lib/waha/stop-detection.test.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/waha/stop-detection.test.ts) for compliance handling.

### Media Handling and Storage

Outbound media is stored in private Supabase buckets with a `media.persist_requested` status. Signed URLs are generated through the endpoint `GET /api/v1/messages/{id}/media`, ensuring secure temporary access to files without exposing storage credentials.

## AI Agent Engine and Runtime

The AI-native capabilities center on a sophisticated agent-engine located in `lib/agent-engine/` and `lib/ai/`.

### Vercel AI Gateway Integration

The [`lib/ai/gateway.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/ai/gateway.ts) file wraps the **Vercel AI Gateway**, handling provider selection between Anthropic, OpenAI, and custom endpoints with automatic fallback logic. This abstraction adds per-tenant observability and rate limiting before routing requests to underlying LLM providers.

### Turn-Based Job Queue System

AI operations are scheduled through a priority job queue implemented in [`lib/agent-engine/queue/queue.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/agent-engine/queue/queue.ts). The queue uses PostgreSQL's `FOR UPDATE SKIP LOCKED` mechanism for efficient worker coordination, tracking jobs through statuses: `open`, `running`, and `dead`. Events trigger AI processing via `ai_agent.dispatch_requested`, resolved by [`lib/ai/dispatch.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/ai/dispatch.ts) to schedule specific turns.

### Background Worker Processes

Isolated worker containers (defined in `Dockerfile.worker`) consume the job queue asynchronously. The [`workers/ai-response-worker.handler.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/workers/ai-response-worker.handler.ts) executes model calls through `runModelCall()` in [`lib/ai/runtime/agent.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/ai/runtime/agent.ts), automatically injecting RAG context and embeddings from [`lib/ai/embed.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/ai/embed.ts) (using OpenAI's `text-embedding-3-large`). Additional workers handle sentiment analysis ([`workers/ai-sentiment-worker.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/workers/ai-sentiment-worker.ts)) and media persistence.

## Conversation Routing and Automation

After conversation creation, database triggers like `trg_conversation_routing_requested` emit routing events. The [`lib/routing/worker.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/routing/worker.ts) processes these events according to organizational configurations:

- **Round-robin**: Distributes conversations evenly across team members
- **Load-based**: Assigns to the least-busy agent
- **Manual**: Queues for human assignment

The routing system shares infrastructure with the follow-up scheduler, which generates `followup_turn` jobs processed by dedicated workers for timed re-engagement.

## Frontend and Real-Time Updates

The presentation layer uses **shadcn/ui** components styled with Tailwind CSS 4. The inbox interface (`components/inbox/`) renders messages, AI-generated replies, and media attachments. Real-time synchronization is achieved through **Supabase Realtime** listeners using `useRealtime()` hooks that watch the `messages`, `conversations`, and `event_log` tables for live updates without polling.

## Deployment and Operations

DeskcommCRM uses a containerized deployment strategy with three distinct Docker images:

1. **`app`**: The Next.js application server (`Dockerfile`)
2. **`worker`**: Background job processors (`Dockerfile.worker`)
3. **`scheduler`**: Cron-driven task runners (`Dockerfile.scheduler`)

Production deployments utilize **Traefik** as a reverse proxy (configured in [`docker-compose.traefik.yml`](https://github.com/melgarafael/DeskcommCRM/blob/main/docker-compose.traefik.yml)). Environment configuration (documented in `.env.example`) requires `AI_GATEWAY_API_KEY` for AI features, along with optional provider-specific keys like `OPENAI_API_KEY` and `ANTHROPIC_API_KEY`.

## Summary

- DeskcommCRM implements a **multi-tenant architecture** using Supabase RLS with `organization_id` scoping on every table
- The **AI Agent Engine** uses a PostgreSQL-backed job queue with `FOR UPDATE SKIP LOCKED` for reliable worker distribution
- **WhatsApp integration** occurs through WAHA ingestion pipelines that create normalized event logs
- **Next.js 16** serves both the React frontend and REST API handlers with Zod validation and RBAC middleware
- **Vercel AI Gateway** provides unified access to multiple LLM providers with tenant-aware observability
- Background workers run in isolated Docker containers for AI inference, sentiment analysis, and conversation routing

## Frequently Asked Questions

### How does DeskcommCRM ensure data isolation between tenants?

DeskcommCRM implements strict data isolation through PostgreSQL Row-Level Security (RLS) policies defined in `supabase/migrations/`. Every tenant-aware table includes an `organization_id` column, and RLS policies enforce that queries return only rows matching the current tenant. The service-role client in [`lib/supabase/admin.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/supabase/admin.ts) bypasses RLS for internal operations but requires explicit `organization_id` filters in application code.

### What AI providers does the agent-engine support?

The agent-engine supports multiple providers through the Vercel AI Gateway abstraction in [`lib/ai/gateway.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/ai/gateway.ts). The system can route requests to Anthropic (Claude), OpenAI (GPT models), or custom endpoints with automatic fallback between providers. Embeddings use OpenAI's `text-embedding-3-large` model via [`lib/ai/embed.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/ai/embed.ts) for knowledge-base indexing.

### How are WhatsApp messages processed in the architecture?

Inbound WhatsApp messages enter through WAHA and are processed by [`lib/waha/ingest.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/waha/ingest.ts), which creates channel sessions and emits `event_log` entries. Outbound messages are queued through the agent-engine's job system in [`lib/agent-engine/queue/queue.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/agent-engine/queue/queue.ts), with media stored in private Supabase buckets and served via signed URLs through the `/api/v1/messages/{id}/media` endpoint.

### What triggers AI agent responses in conversations?

AI responses are triggered by the `ai_agent.dispatch_requested` event, handled by [`lib/ai/dispatch.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/ai/dispatch.ts). This resolves the appropriate published agent version and schedules a turn in the job queue. Workers in [`workers/ai-response-worker.handler.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/workers/ai-response-worker.handler.ts) execute the actual model calls through `runModelCall()` with RAG context injection, then write responses back to the conversation thread.