Technical solution

Built on proven technology

Contineo combines semantic search (RAG) over your content with a language model that answers only from verified sources — with a citation and version.

The examples on this page (sections, tags, queries) come from a generic company. Contineo is domain-agnostic — a “policy” is just one kind of document and a “unit” just one kind of organisation. For a real deployment into a large organisation, see the case study below.

Back to home

Architecture and data flow

Architecture and data flow

Input channels → processing (chunking + tagging) → MongoDB (the core: hybrid search) → AI adapters (embedding, rerank, generation) → interfaces. The core is identical in cloud and on-prem — $rankFusion runs the same way in Atlas and in self-hosted Community 8.2. Only three adapters differ, and they are selected by tenant configuration. The AI always receives just the relevant passages; your data stays in your database. Including two feedback loops: curation (quality control) and ticket escalation.

Key pillars

RAG + Hybrid Search

The $rankFusion hybrid query (vector 60 % + fulltext 40 %) is the core of the system and runs identically in MongoDB Atlas and in self-hosted Community 8.2. Answers are produced only from the retrieved passages.

Swappable AI adapters

Embedding, rerank and generation are three independent adapters selected by tenant configuration, not by code. Cloud: Voyage and Claude. On-prem: Infinity or TEI and vLLM with the model of your choice (Qwen3, EuroLLM, Gemma).

Citations and versions

Every answer states the source and version. A new import never loses the old one — always citing the valid wording.

Multi-tenant and security

A hierarchy of organisations (headquarters → regional → local units) as separate tenants. Public content is visible to everyone; internal content only to members of that unit. Audit trail on every knowledge change.

Input channels (content & integrations)

One layer through which content flows: PDF documents and policies, FAQs, websites (RSS), internal guidelines, MCP connectors (Drive, SharePoint, Confluence…) and e-mail (IMAP) — unified into one index. A connected identity source (e.g. sportnet.online) provides identity here, not content.

Helpdesk and e-mail

Mailbox monitoring, ticketing and prepared replies with escalation from search.

Quality control & curation

Not machine learning of the model, but human curation: an admin rates and approves an answer, it is stored as a new pair (qa_pair) and embedded back. A new pair never silently overrides an approved document.

Key data flows

01

Answering (RAG + Hybrid)

The query is classified (fulltext / vector / hybrid). $rankFusion merges $vectorSearch and $search — identically in both modes. Rerank and generation are then handled by the adapter from the tenant profile: $rerank in the database and the Claude API in the cloud, Infinity and vLLM on-prem. The answer is streamed with a source citation.

02

Ticket escalation

A failure = low similarity score or a negative rating. After 3 failures on the same topic the bot offers to create a ticket, including the full conversation context.

03

Quality control & curation

Not machine learning but human curation: approved answers from ContineoLearning and edited e-mail replies are stored as a qa_pair and embedded back into the knowledge base. A new pair never silently overrides an approved document.

Main collections

The design separates knowledge (the RAG core) from conversations and tickets. Versioning ensures importing a new version never loses the older one.

document_chunks — the RAG core

{
  _id, documentId, versionId,
  sourceType: "pdf",            // pdf | faq | rss | qa | email

  // tagging (used for filtering at search time)
  sectionKey: "smernice",
  companyCode: "ACME-BA",       // "ACME" = applies company-wide
  scope: "company",         // global | company | region
  language: "sk",

  // content
  articleRef: "čl. 4 ods. 2",
  heading: "Práca z domu (home office)",
  text: "Zamestnanec má nárok na home office...",

  // vector + identita vektorového priestoru
  embedding: [0.0123, -0.044, ...],   // 1024 dims
  embeddingModel: "voyage-4",         // POVINNÉ — ktorý model vektor vyrobil
  embeddingDim: 1024,                 // kontrola pri zápise aj čítaní
  embeddingProvider: "atlas-auto",    // atlas-auto | infinity | tei
  embeddedAt: ISODate(),              // pre plánovanie re-embedu

  isActive: true,               // false = archived version
  effectiveFrom, effectiveTo
}

tickets

{
  ticketNumber: "CNT-2026-000412",
  source: "bot",                // bot | email
  status: "open",               // lifecycle below
  priority: "normal",
  sectionKey: "hr",
  companyCode: "ACME-BA",
  requester: { email, name, userRef },
  subject, conversationId,      // full context if from bot
  assignedTo, slaDueAt,
  resolution: { answeredBy, qaPairId, closedAt },
  tags: []
}

Hybrid search query ($rankFusion)

A question from unit “ACME-BA”, section internal policies, valid version only. $rankFusion combines vector (Voyage AI auto-embed) and fulltext search; $rerank orders results by relevance.

db.document_chunks.aggregate([
  { $rankFusion: {
      input: {
        pipelines: {
          vector: [{ $vectorSearch: {
            index: "rag_vector_index",   // index viazaný na embeddingModel
            path: "embedding",
            queryVector: queryEmbedding, // z adaptéra podľa profilu
            numCandidates: 200, limit: 20,
            filter: { sectionKey: { $eq: "smernice" },
                      companyCode: { $in: ["ACME-BA","ACME"] },
                      isActive: { $eq: true } }
          }}],
          fulltext: [{ $search: {
            index: "rag_text_index",
            text: { query: queryText, path: "text" }
          }}]
        }
      },
      combination: { weights: { vector: 0.6, fulltext: 0.4 } }
  }},
  { $limit: 20 },
  { $project: {
      text: 1, heading: 1, articleRef: 1,
      score: { $meta: "rankFusionScore" }  // -> signál pre eskaláciu
  }}
])

// Tento dotaz je identický v cloude aj on-prem.
// Rerank je samostatný krok MIMO neho, podľa profilu tenanta:
//   cloud   -> { $rerank: { index: "rag_rerank_index",
//                           query: queryText, limit: 8 } }
//              sa pripojí ako ďalší stage (MongoDB Atlas 8.3+)
//   on-prem -> POST /rerank na Infinity/TEI nad výsledkom vyššie
//
// Počet kandidátov na vstupe rerankera drž rovnaký (20),
// aby boli oba režimy porovnateľné na eval sade D9.

Swappable adapters and the tenant profile

Embedding, rerank and generation are three independent adapters. Which one is used is decided by a record in the tenant_profiles collection — not by code. A single installation therefore serves cloud and on-prem customers at the same time, on the same search core.

tenant_profiles — adapter selection

{
  companyCode: "ACME",          // kľúč, zhodný s chunkami
  tier: "T1",                   // T1 shared | T2 enclave | T3 air-gap
  dataResidency: "eu",          // eu | on-prem | air-gap

  providers: {
    embedding: {
      kind: "atlas-auto",       // atlas-auto | infinity | tei
      model: "voyage-4", dim: 1024,
      index: "rag_vector_index"
    },
    rerank: {
      kind: "atlas-stage",      // atlas-stage | infinity | tei | none
      model: "rerank-2", topK: 8
    },
    generation: {
      kind: "anthropic",        // anthropic | openai
      model: "claude-sonnet-5",
      citations: true, promptCaching: true
    }
  }
}

// Ten istý tenant v uzavretom režime — mení sa len profil:
//   embedding:  { kind: "infinity", model: "voyage-4-nano", dim: 1024 }
//   rerank:     { kind: "infinity", model: "BAAI/bge-reranker-v2-m3" }
//   generation: { kind: "openai", url: "http://vllm:8000/v1",
//                 model: "Qwen3-8B", citations: false }

What differs between the modes

The core is identical, but full feature parity does not exist. These are the differences to account for when choosing a mode.

CapabilityCloudOn-prem
$rankFusion hybrid searchyesyes — identical
Automated embedding in the databaseyescalls the Voyage API — unusable air-gapped
$rerank inside the pipelineyesno — rerank in the application layer
Verifiable citations (Citations API)yesno — citations requested via the prompt
Prompt cachingyesprefix caching in vLLM, different semantics
Data never leaves the perimeternoyes

Vectors are not portable between models — changing the embedding model means a full re-embed of the corpus. The decision and its consequences are documented in ADR-001.

Content tagging

Every chunk answers three questions — what it is about (section), whom it applies to (company/scope) and which version. Values are picked from a controlled list, not free text.

Section list

vseobecneGeneral information
smerniceInternal policies
hrHR & people
ekonomickeFinance
it_aplikacieIT & applications
gdprGDPR & legal

Scope of validity

  • scope: global + HQ (e.g. ACME) → applies company-wide
  • scope: company + unit code → applies to that unit only
  • scope: region → applies to a regional level

Examples of tagged chunks

// company-wide policy (applies to all units)
{ sourceType: "pdf", sectionKey: "smernice",
  companyCode: "ACME", scope: "global",
  articleRef: "čl. 4 ods. 2", isActive: true }

// document specific to one unit
{ sourceType: "pdf", sectionKey: "hr",
  companyCode: "ACME-BA", scope: "company",
  articleRef: "čl. 8", isActive: true }

// IT FAQ for an internal app (FAQ, not a policy)
{ sourceType: "faq", sectionKey: "it_aplikacie",
  companyCode: "ACME", scope: "global",
  articleRef: null, isActive: true }

Rules for consistent tagging

  • sectionKey and companyCode always from the list, never free text.
  • Company-wide policies: HQ + scope global — don't copy per unit.
  • Fill articleRef for policies — it's used in the citation.
  • On a new version don't delete old chunks — set isActive: false + effectiveTo.

Ticket lifecycle

A ticket is created from the bot or e-mail and moves through states:

newarrived, auto-triage in progress (section, unit, suggested reply)
openassigned to an admin, being worked on
waitingwaiting for input from the requester (SLA paused)
resolvedreply sent; an edit on send = a new qa_pair
closedclosed; reopen returns to open

Integrations

E-mail (IMAP)

Two monitored mailboxes (tickets + standard questions); the worker routes them into a ticket or the learning flow.

Identity & CRM source (e.g. sportnet.online)

Login via OAuth and a CRM as the source of truth about people and organisational units: users are created automatically, roles and groups follow membership in a unit/team (via a mapping table or manually). Contineo has its own database and doesn't write back. In the sports deployment this source is sportnet.online (see the case study).

RSS / web

For general information the worker periodically pulls RSS; new items → documents → chunks.

MCP connectors

Pluggable sources via MCP — Google Drive, SharePoint, Confluence, Notion, Slack and more. Content is indexed like any other source.

Security and operations

  • Access by membership in an organisation/unit and groups (automatically from a connected identity source, e.g. sportnet.online in sports); who may upload content is allow-listed manually. Audit trail on every knowledge change.
  • SSO login: Microsoft Entra ID, Google Workspace (sportnet.online in sports too); public content also without login.
  • A version citation in every answer and archiving of old document versions.
  • Quality monitoring: score, escalation rate and ratings as feedback.
  • Multi-tenant hierarchy (headquarters → regional → local units): public content visible to all, internal content isolated per organisation.
  • Data privacy: content stays in your database and storage; the AI answers strictly from your content (RAG), no public consumer AI is used.
  • Runtime mode chosen per tenant: cloud (EU residency, zero-retention agreement) or fully on-prem — neither content nor queries leave your infrastructure. A single installation serves both kinds of customer at once.

Identity and access control

Sign-in via existing SSO; an access right is a mandatory filter derived from the session and applied to both branches of hybrid search ($vectorSearch and $search).

Identity providers (NextAuth) → one canonical session

OAuth / OIDCprimary login; in the sports deployment e.g. sportnet.online + source of memberships and roles
Microsoft Entra IDSSO for employees' corporate accounts
Google WorkspaceSSO (alternative)
Identity source CRM / APIsource of truth about people and organisational units; mapping to companyCode, roles and groups
Own databaseaccounts outside SSO (credentials)

Security principles

  • Server-side only — the filter is built from the session, never from client parameters.
  • Default-deny — anything not explicitly allowed is not returned; without identity, public content only.
  • Filter before the LLM — the model sees only allowed chunks; it can't be bypassed by a prompt (applies to citations too).
  • Auto-provisioning — users, roles and groups are created and synced from the CRM (login + webhook).

Two deployment modes

Public widget

anonymous; sees only public content across the whole hierarchy.

Internal portal (SSO)

signed-in; sees public + internal content of the units they're related to.

Case study

Deployment in a large organisation — a sports association (SFZ)

Contineo is domain-agnostic. This is what one real deployment into a large organisation looks like — the Slovak Football Association and its subordinate associations.

  • Tenant hierarchy: SFZ → regional → district associations as separate organisations.
  • Content: competition and transfer rules, fixtures, guidelines, IT FAQ (the ISSF app).
  • Identity: login and CRM via sportnet.online (OAuth) — users and roles by membership in an association/club.
  • Example question: “Can a player play in two matches in a single day?” → an answer citing the article and version.

Technology stack

MongoDB — the core: $rankFusion (Atlas EU or Community 8.2)Cloud · Voyage AI voyage-4 — Automated EmbeddingCloud · Voyage AI rerank-2.5 — $rerank in the databaseCloud · Claude API — Citations, prompt cachingOn-prem · Infinity / TEI — embedding + rerankOn-prem · vLLM — Qwen3, EuroLLM, GemmaNext.js 14 (App Router) · Node.js workerIntegrations: e-mail (IMAP), identity/CRM source (e.g. sportnet.online), MCP connectors