Backend Overview¶
The backend is a Python monorepo managed with Poetry. It contains deployable FastAPI services, Cloud Run jobs, command-line tools, the hosted Rose MCP service, and reusable packages shared across those applications.
Architecture¶
Repository Structure¶
backend/
├── apps/
│ ├── api/
│ │ ├── search/ # Website Agent HTTP/SSE API
│ │ ├── admin/ # Authenticated backoffice BFF
│ │ ├── knowledge/ # Knowledge workflow control plane
│ │ ├── knowledge_content_worker/ # Discovery, scrape, and clean worker
│ │ ├── integrations/ # HubSpot and integration endpoints
│ │ └── ixvector/ # Identity/enrichment webhook API
│ ├── jobs/ # Cloud Run jobs
│ ├── mcp/ # Hosted Rose MCP server
│ ├── cli/ # Operational CLIs
│ └── scraping/ # Scraping application boundary
├── packages/ # Shared Python packages
└── justfile # Backend commands
Deployable Services¶
| Service | Responsibility |
|---|---|
| Search API | Public Website Agent requests, streaming, resume, and enrichment boundaries |
| Admin API | Authorize staff/backoffice operations and call private services with OIDC |
| Knowledge API | Own durable ingestion state, guarded transitions, dispatch, recovery, and status |
| Knowledge content worker | Execute bounded content stages and write immutable GCS artifacts |
| Integrations API | HubSpot OAuth, CRM webhooks, email-capture tasks, and integration operations |
| IXVector API | Ingest identity and enrichment webhooks |
| Rose MCP | Brand conversations, vendor discovery and reply cards in Claude/ChatGPT |
| R4A MCP | Signed-in buyer tools for vendor questions, alternatives, offers, trials and purchases |
See Cloud Run services for service name patterns, access boundaries and deployment owners, including the support function and Factory relay.
The Knowledge API is the workflow source of truth. Cloud Tasks and Cloud Run deliver work but do not own workflow state. See Knowledge ingestion control plane.
Core Packages¶
| Package | Responsibility |
|---|---|
| ixchat | Website Agent LangGraph, streaming, memory, and response routing |
| ixskills | LLM selection plus deterministic application of global/client skills |
| ixrag | LightRAG retrieval, chunk processing, reranking, and tenant context |
| ixllm | Provider clients, model routing, retries, and observability |
| ixknowledge | Knowledge operation, work-item, snapshot, and ingestion contracts |
| ixscraping | Website mapping, selection, scraping, and content-cleaning logic |
| ixconfig | Typed unified configuration models and resolver |
| ixmongo / ixneo4j | Tenant-aware LightRAG storage adapters |
| ixdata | Supabase and external data access |
| ixweb | FastAPI-facing web components and request models |
| ixinfra | Environment loading, logging, networking, and shared utilities |
| ixapi_helpers | Reusable API authentication and middleware |
| ixgeo | Generated GEO content and publishing pipeline |
| ixtagging | Conversation classification and scoring |
| ixevaluation | Evaluation datasets and LLM/classifier tooling |
Website Agent Core¶
ixchat powers the Website Agent. Its LangGraph
starts retrieval, enrichment, profiling, and routing work concurrently, then
streams from the selected answer, redirect, or booking path. Model selection is
role-based: different tasks use Cerebras, Azure OpenAI, OpenAI, or Mistral, with
fallbacks. See Model residency for the EU-only route policy.
The IXChat package page embeds a graph generated directly from
ixchat/graph_structure.py; use it instead of hand-maintained node diagrams.
Model residency¶
Provider deployments live in ixllm/ixllm/deployments.toml. Package routing
modules reference them with deployment_route("<id>"); add a catalogue entry
before routing to a new model. is_eu_eligible treats a deployment as EU
(EEA + Switzerland) when it has a European endpoint and is not a Global
deployment type; Azure deployments also need reviewed deployment_type and
reviewed_on metadata. Mistral is pinned to api.eu.mistral.ai.
resolve_chat_use_case accepts a standard | eu_only residency and otherwise
inherits the request-scoped value set by residency_scope(...). Under eu_only,
derive_eu_policy keeps only the policy's EU-eligible legs in primary→fallback
order, unless the policy sets an explicit eu_override. It raises
EUResidencyUnavailableError when no eligible leg remains and EUResidencyViolationError
when an override points at an ineligible deployment.
Today only rose-chat --eu-residency and rose-eval --eu-residency enter the
eu_only scope, and only registered chat routes are filtered. Embeddings,
ixtagging and Admin generation build their clients directly. A per-client
setting is planned in IX-5094 (plan: docs/plans/2026-09-19-strict-eu-residency.md).
Retrieval and Storage¶
ixrag uses a shared LightRAG instance with tenant identity injected per
request. Storage remains shared but every document, node, and relationship is
scoped by tenantId:
| Store | Data | Isolation |
|---|---|---|
| MongoDB | Chunks, vectors, key-value state, document status | tenantId filters and composite IDs |
| Neo4j | Knowledge graph nodes and relationships | tenantId property constraints |
| Redis | LangGraph checkpoints, caches, and locks | Environment and tenant-aware keys |
| Supabase | Product, analytics, config, and workflow state | RLS/domain authorization; one shared production project |
Unified Configuration¶
Per-site behavior is resolved through typed client_configs data plus generated
Python and TypeScript contracts. The old agent_config-centric model is not the
current authoring interface. See the Unified Config System
for namespaces, precedence, validation, and rollout rules.
Cloud Run Jobs¶
| Job | Responsibility |
|---|---|
| document-loader | Controlled writer from approved source snapshots to LightRAG stores |
| tagging | Conversation classification and scoring |
| website-mapping | Website mapping refresh |
| posthog-batch-processor | Production analytics batch materialization |
| hubspot-contacts-sync | CRM synchronization |
| geo-run | GEO pipeline for one workspace, started from the backoffice |
Quick Commands¶
cd backend
just dev staging # Start the development API
poetry run pytest # Run all backend tests
poetry run pytest -m unit # Unit tests only
poetry run pytest -m integration # Integration tests only
See Backend Setup for environment setup and service-specific commands.