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.
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
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.
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.
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.
| Capability | Cloud | On-prem |
|---|---|---|
| $rankFusion hybrid search | yes | yes — identical |
| Automated embedding in the database | yes | calls the Voyage API — unusable air-gapped |
| $rerank inside the pipeline | yes | no — rerank in the application layer |
| Verifiable citations (Citations API) | yes | no — citations requested via the prompt |
| Prompt caching | yes | prefix caching in vLLM, different semantics |
| Data never leaves the perimeter | no | yes |
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
| vseobecne | General information |
| smernice | Internal policies |
| hr | HR & people |
| ekonomicke | Finance |
| it_aplikacie | IT & applications |
| gdpr | GDPR & 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:
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 / OIDC | primary login; in the sports deployment e.g. sportnet.online + source of memberships and roles |
| Microsoft Entra ID | SSO for employees' corporate accounts |
| Google Workspace | SSO (alternative) |
| Identity source CRM / API | source of truth about people and organisational units; mapping to companyCode, roles and groups |
| Own database | accounts 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.
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.