Skip to main content

Architecture Overview

Retrieva is a DORA-compliance RAG platform. The core flow is: upload vendor documents → AI-generated DORA gap analysis report → conversational Q&A.

Services

backend/     - Express 5 API server (ES modules, Node.js 20)
frontend/ - Next.js 16 App Router (React 19, TypeScript)

Data Flow

Gap Analysis Flow

User → Upload vendor PDF/DOCX/XLSX
→ assessmentController → assessmentQueue (BullMQ)
→ assessmentWorker:
1. fileIndex: parse → embed chunks → Qdrant
2. gapAnalysis: retrieve chunks → LLM generates DORA gap report
→ Assessment.results stored in MongoDB
→ User downloads report or queries via chat

RAG (Q&A) Flow

User Question → RAG Service
→ Embed query → Qdrant retrieval (k=15)
→ Cross-encoder re-ranking (top 5)
→ Context expansion (sibling chunks)
→ LLM generates answer with citations
→ Response streamed to frontend

Model Hierarchy

Organization  (company account — e.g. "HDI Global SE")
└── OrganizationMember (org_admin | analyst | viewer)
└── User (one user belongs to one org)
└── Workspace (vendor isolation boundary — scoped to org)
└── Assessment (per vendor DORA evaluation)
└── DocumentSource (indexed chunks in Qdrant)

Organization-First B2B Model

All vendor workspaces are scoped to an Organization. When a user belongs to an org, they automatically see every workspace that shares the same organizationId — no per-workspace invitation is required. Org-level roles map to workspace permissions:

Org roleWorkspace access
org_adminowner-level (can invite, configure, query)
analystmember-level (can query, view sources)
viewerviewer-level (read-only)

Legacy users without an organizationId fall back to the previous per-workspace WorkspaceMember access model.

Backend Request Flow

Routes → Middleware (authenticate, requireWorkspaceAccess, validateBody)
→ Controllers → Services / Workers
→ MongoDB (metadata) + Qdrant (vector store)

Key Components

Controllers

ControllerResponsibility
assessmentController.jsUpload files, start gap analysis, retrieve results
ragController.jsConversational Q&A over indexed documents
workspaceController.jsWorkspace CRUD + member management
organizationController.jsOrganization creation, team invitations, member management
authController.jsRegister, login, logout, token refresh
conversationController.jsConversation history management
exportController.jsRoI export (DORA Art. 28 Excel workbook)
healthController.jsService health checks

Workers (BullMQ)

WorkerQueuePurpose
assessmentWorker.jsassessmentJobsOrchestrates file indexing + DORA gap analysis
monitoringWorker.jsmonitoringJobs24-hour schedule: compliance threshold alerts

Key Services

ServicePurpose
services/rag.jsCore RAG pipeline: retrieval, re-ranking, answer generation
services/assessmentService.jsDORA gap analysis logic
services/alertMonitorService.jsCompliance threshold checks and alert delivery
services/roiExportService.jsEBA-compliant DORA Art. 28(3) XLSX workbook
services/fileIngestionService.jsParses PDF, DOCX, XLSX to plain text
services/emailService.jsTransactional email via Resend HTTP API
services/storageService.jsFile backup via DigitalOcean Spaces (S3-compatible)

Configuration

ModulePurpose
config/llm.jsAzure OpenAI LLM client (gpt-4o-mini)
config/embeddings.jsAzure OpenAI embeddings (text-embedding-3-small)
config/vectorStore.jsQdrant client + collection management
config/queue.jsBullMQ queue definitions
config/database.jsMongoDB connection
config/redis.jsRedis connection (BullMQ + RAG cache)

Infrastructure

                 ┌─────────────┐
HTTPS ─────→ │ Nginx │
└──────┬──────┘
┌─────────┴──────────┐
↓ ↓
┌──────────┐ ┌──────────┐
│ Frontend │ │ Backend │
│ :3000 │ │ :3007 │
└──────────┘ └────┬─────┘
┌─────┼──────┐
↓ ↓ ↓
MongoDB Redis Qdrant

Production (DigitalOcean fra1):

  • Nginx reverse proxy + Let's Encrypt SSL
  • Docker Compose with health checks
  • MongoDB Atlas (M0 free tier)
  • Qdrant v1.13.2 (self-hosted Docker)
  • Redis 7 (self-hosted Docker, 256MB)
  • DigitalOcean Spaces for file storage
  • Azure OpenAI: gpt-4o-mini + text-embedding-3-small

Multi-Tenancy

Workspace-based isolation. Every Qdrant query filters by workspaceId. The ENFORCE_TENANT_ISOLATION=true env var adds a defense-in-depth check at the vector store layer.

LLM Provider Abstraction

The provider factory (config/llmProvider.js) supports Azure OpenAI (default), OpenAI, and Anthropic. Switch via the LLM_PROVIDER env var.