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
- Overall System Architecture
- Database Layer
- Queue & Worker Architecture
- Ingestion Engine & Loaders
- Vector Database Layer — Qdrant
- Embedding Pipeline
- RAG & Retrieval Pipeline
- Chat & Conversation Engine
- Multi-Tenant Isolation & Auth
- Sync Orchestrator
- External Integrations & Channels
- File Storage & Media Pipeline
- LLM Orchestration & Model Router
- Observability & Monitoring
- Gaps & Recommendations
1. Overall System Architecture
ZappWay is a pnpm monorepo structured into 3 applications and 2 package trees. Theapps/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
- Enable cloud logging — Uncomment Axiom or use Datadog / Grafana Loki for production log retention.
- Add rate limiting — Per-organization token-bucket on chat endpoints.
- Implement DLQ — BullMQ supports
deadLetterQueueoption; enable for all 3 queues. - Embedding fallback —
text-embedding-3-largefrom OpenAI (3072-dim compatible) as secondary. - Qdrant snapshots — Cron-based snapshot to S3 for disaster recovery.
- Test coverage — Integration tests for the RAG pipeline and ingestion workers as a starting priority.
Architectural Strengths
Vocabulary
· Last updated: March 2026

