Skip to main content
What you’ll learn: This page is the authoritative architecture reference for ZappWay, generated from a full codebase scan (commit 14982f37). It covers every major subsystem: the monorepo structure, database schema, queue/worker topology, ingestion loaders, Qdrant vector layer, embedding pipeline, adaptive multi-shot RAG, chat engine, auth, sync orchestrator, all 13 channel integrations, file storage, LLM model router, and observability.

🔢 Table of Contents

  1. Overall System Architecture
  2. Database Layer
  3. Queue & Worker Architecture
  4. Ingestion Engine & Loaders
  5. Vector Database Layer — Qdrant
  6. Embedding Pipeline
  7. RAG & Retrieval Pipeline
  8. Chat & Conversation Engine
  9. Multi-Tenant Isolation & Auth
  10. Sync Orchestrator
  11. External Integrations & Channels
  12. File Storage & Media Pipeline
  13. LLM Orchestration & Model Router
  14. Observability & Monitoring
  15. Gaps & Recommendations

1. Overall System Architecture

ZappWay is a pnpm monorepo structured into 3 applications and 2 package trees. The apps/zappway app hosts the Dashboard, Landing, Blog, and Docs. All core business logic lives in packages/zappway/lib (~160 files). A dedicated apps/workers-services app runs all background workers and the WhatsApp Bridge API in isolation, consuming jobs from Redis-backed BullMQ-Pro queues.

Application Map

Package Map


2. Database Layer

Source: packages/zappway/prisma/schema.prisma (1548 lines) · 33 models · 23 enums PostgreSQL via Prisma with fullTextSearch and fullTextIndex preview features enabled. The Organization model is the root tenant boundary — every other entity is scoped to it directly or transitively.

Full Model Inventory

Key Enums


3. Queue & Worker Architecture

Source: packages/zappway/lib/types/index.ts, apps/workers-services/workers/ Three dedicated BullMQ-Pro queues separate concerns. The load-datasource queue is the primary active queue; the other two are partially implemented.

Worker Configuration — Datasource Loader

Dedupe Mechanism: Redis SET NX with key ld:lock:{datasourceId} prevents the same datasource from running in parallel. Graceful Shutdown: Handles SIGTERM and SIGINT — closes the worker, quits Redis cleanly.

Worker Inventory


4. Ingestion Engine & Loaders

Source: packages/zappway/lib/datastores/datasources/, packages/zappway/lib/loaders/ All loaders extend DatasourceLoaderBase. The entry point taskLoadDatasource() selects the correct loader at runtime based on DatasourceType. Output is a normalized AppDocument[] array fed into the chunking engine and then into Qdrant.

Loader Mapping

WebSite Loader — Pipeline Detail

Source: packages/zappway/lib/loaders/web-site.ts (515 lines) The WebSiteLoader is the most complex loader. Its pipeline runs in 6 stages: (1) Discovery — parses sitemap XML or crawls via findDomainPages(); (2) Normalization — URL dedup, strip UTM params, lowercase hostname; (3) Blacklist filtering — applies black_listed_urls config; (4) HTTP probing — HEAD → GET with semver path repair on 404s; (5) Child management — upserts web_page child datasources, deletes orphans; (6) Enqueueing — emits child jobs with priority scores (home = 5, sitemap = 8, others = 10). Concurrency is capped at 6 via mapWithConcurrency. Plan limit applied via accountConfig[plan].limits.maxWebsiteURL (default: 25).

5. Vector Database Layer — Qdrant

Source: packages/zappway/lib/datastores/qdrant.ts (731 lines) Each Datastore maps to exactly one Qdrant collection named zw_{datastoreId}, providing strict per-tenant vector isolation. QdrantManager includes an auto-migration routine that detects dimension or distance metric mismatches and recreates the collection transparently — enabling zero-downtime embedding model upgrades.

Collection Configuration

Payload Schema (per point)


6. Embedding Pipeline

Source: packages/zappway/lib/datastores/gemini-embeddings.ts, packages/zappway/lib/multimodal-memory/ All embeddings use Gemini Embedding 2 Preview, producing 3072-dimensional vectors that match Qdrant’s VECTOR_SIZE. The pipeline uses asymmetric taskType values per call site — RETRIEVAL_DOCUMENT during ingestion and RETRIEVAL_QUERY at search time — which is critical for retrieval quality with Gemini’s asymmetric embedding model.

Configuration

Multimodal Support

embedMultimodal() accepts GeminiPart[][] where each part can be { text } or { inlineData: { mimeType, data } } (base64-encoded images, video frames, audio, PDF pages). This embeds non-text content into the same 3072-dimensional space as text, enabling true multimodal semantic search. The multimodal-memory/ module provides dedicated indexing (indexer.ts — 24.5KB), media-specific chunkers (media-chunkers.ts), collection management, search, and async queue triggers.

7. RAG & Retrieval Pipeline

Source: packages/zappway/lib/chat-v4/rag.ts (493 lines) ZappWay implements Multi-Shot Adaptive RAG with up to 6 progressive retrieval attempts across 3 quality tiers. Each attempt relaxes similarity thresholds to maximize recall while evaluateRagQuality() enables early exit when results are strong enough. A circuit breaker prevents cascading failures, and ragMemo (in-memory cache) deduplicates identical attempts within a session.

Adaptive Thresholds

Deep Mode is triggered by shouldFavorDeepRag(query) and applies higher initial thresholds. minUcount is 1 for single-datastore and 2 for multi-datastore queries. Timeouts scale from 8s (Tier 1) to 12s (Tier 3), capped by remaining chat budget. If remainingMs() < 120s, max attempts reduce to 4.

8. Chat & Conversation Engine

Source: packages/zappway/lib/chat-v4/chat.ts (1147 lines), packages/zappway/lib/agent/tools/ The chat function orchestrates system prompt assembly, message history truncation, multi-shot RAG, runtime tool building, LLM execution with streaming, and same-model provider fallback for direct Google models through OpenRouter — all within a shared time budget enforced at every checkpoint.

SSE Event Types

Runtime Tools


9. Multi-Tenant Isolation & Auth

Sources: packages/zappway/lib/auth/authConfig.ts, authAdapter.ts, and authProviders.ts Auth.js Core with a custom Prisma adapter handles server-side HTTP requests directly; next-auth/react remains client-only. Four sign-in methods are supported. On first sign-in, the platform auto-provisions the full tenant stack atomically.

Tenant Isolation by Layer

RBAC Model

Session Configuration

Locale Support: 37 locales, including RTL (Arabic, Hebrew, Persian, Urdu). Resolution order: URL path → NEXT_LOCALE cookie → i18next cookie → Accept-Language header → default en.

10. Sync Orchestrator

Source: apps/workers-services/workers/check-and-sync-cron.ts A cron-driven worker scans all datasources with status = synched, filters by lastSyncAt + syncInterval, and fans out individual load-datasource jobs. A check-stalled worker handles recovery of datasources stuck in running status beyond a configurable threshold.

11. External Integrations & Channels

Source: packages/zappway/integrations/ — 13 channel adapters All channels normalize inbound messages to the same internal Conversation + Message model and route through the unified chat-v4 engine.

Channel Capabilities

ServiceProvider Auth


12. File Storage & Media Pipeline

Source: packages/zappway/lib/aws.ts Supports S3-compatible storage (AWS S3, Cloudflare R2, MinIO) via AWS SDK v3. Files are uploaded via presigned URLs, stored under organizations/{orgId}/, and pulled by FileLoader for extraction and ingestion.

S3 Environment Variables


13. LLM Orchestration & Model Router

Source: packages/zappway/lib/config.ts (943 lines), packages/zappway/lib/chat-model/model.ts (745 lines) 50+ models across 12 providers via a unified OpenAI-SDK-compatible interface. Provider routing is automatic based on each model’s baseUrl in ModelConfig. OpenAI, Google Gemini, and OpenRouter are all accessed through the same OpenAI SDK client with different base URLs and API keys.

Model Inventory

🧠 OpenAI — Direct

🟡 Google — Direct via Gemini API

🔶 Anthropic — via OpenRouter

Other Providers — via OpenRouter

Free Tier Models: gpt_4o_mini, gpt_5_mini, gpt_5_nano, gpt_5_4_mini, gpt_5_4_nano, gemini_flash_2_0
Important: GPT-5 family models do not support manual temperature adjustment — they use automatic temperature recognition.

14. Observability & Monitoring

Source: packages/zappway/lib/logger.ts, apps/workers-services/sentry.*.config.ts Workers publish a WorkerHealth payload to Redis (health:worker:{name}, 30s TTL) every 10s. Fields: status, startedAt, lastActivityAt, jobsProcessed, jobsFailed, queueLength, system.memoryMB, system.uptimeMs. Exposed via /api/workers/health. Workers also stream real-time logs to Redis Pub/Sub channel logs:datasource for live dashboard monitoring.

15. Gaps & Recommendations

Identified Gaps

Recommendations

  1. Enable cloud logging — Uncomment Axiom or use Datadog / Grafana Loki for production log retention.
  2. Add rate limiting — Per-organization token-bucket on chat endpoints.
  3. Implement DLQ — BullMQ supports deadLetterQueue option; enable for all 3 queues.
  4. Embedding fallbacktext-embedding-3-large from OpenAI (3072-dim compatible) as secondary.
  5. Qdrant snapshots — Cron-based snapshot to S3 for disaster recovery.
  6. Test coverage — Integration tests for the RAG pipeline and ingestion workers as a starting priority.

Architectural Strengths


Vocabulary


· Last updated: March 2026