Architecture¶
Platform Overview¶
Rose is an AI-first inbound marketing platform built as a distributed system. The production Website Agent combines a browser widget, Cloudflare edge routing, FastAPI services on Cloud Run, LangGraph orchestration, retrieval infrastructure, and external model and enrichment providers.
Agent Architecture¶
Rose agents follow a common four-layer pattern:
| Layer | Purpose | Website Agent example |
|---|---|---|
| Frontend interface | User-facing surface | React widget |
| API service | Authentication, validation, and transport | Search API |
| Agent core | Business logic and orchestration | ixchat LangGraph |
| Shared infrastructure | Retrieval, models, storage, and configuration | ixrag, ixllm, Redis, MongoDB, Neo4j |
Active Agents¶
| Agent | Frontend | Backend API | Core package |
|---|---|---|---|
| Website Agent | frontend/widget/ |
backend/apps/api/search/ |
ixchat |
See Agents Overview for beta and roadmap agents.
Deployed Cloud Run services¶
Services are hosted in GCP project inboundx, in europe-west9 (Paris), except
Factory relay in europe-west1 (Belgium). The table shows supported deployment
names, not live deployment status; optional staging targets may be absent.
— means no dedicated target. Uses production means the frontend calls the
production function rather than an isolated copy.
| Service | Purpose | Test | Staging | Production |
|---|---|---|---|---|
| Search API | Website Agent chat, streaming and retrieval for widget/MCP | search-test-test |
search-staging-staging |
search-production-production |
| Admin API | Backoffice authorization, billing and private Knowledge API access | admin-api-test |
admin-api-staging |
admin-api-production |
| Knowledge API | Ingestion state, dispatch, recovery and status | knowledge-api-test |
knowledge-api-staging |
knowledge-api-production |
| Content worker | Discovery, scrape and clean tasks; GCS artifacts | knowledge-content-worker-test |
knowledge-content-worker-staging |
knowledge-content-worker-production |
| IXVector API | Vector.co identification webhooks and widget visitor-ID links | ixvector-api-test |
ixvector-api-staging |
ixvector-api-production |
| R4A MCP | Buyer tools: vendor questions, alternatives, offers, trials and purchases | r4a-mcp-test |
— | r4a-mcp-production |
| Rose MCP | Claude/ChatGPT brand conversations, discovery and reply cards | — | rose-mcp-staging |
rose-mcp-production |
| Integrations API | HubSpot OAuth, CRM webhooks, email-capture tasks and sync | integrations-test-test |
integrations-staging-staging |
integrations-production-production |
create-support-ticket |
Backoffice reports and visual feedback → Linear; Cloud Function | Uses production | — | create-support-ticket |
rose-factory-relay |
Legacy developer tooling (code now in Night Shift): Linear Agent webhooks → local coding workers, until its routes move to Night Shift assigned issues; outside application environments | — | — | — |
Deployment workflows are under .github/workflows/. develop generally deploys to
test; Rose MCP is the exception and deploys to staging. Production releases
run from main through release.yml, with components selected by changed paths.
Pushes to the staging branch deploy Search, Admin and IXVector to staging.
Knowledge API and content worker staging use manual workflow dispatch.
Integrations staging uses its operator recipe; Factory relay is operator-deployed.
Search and Integrations retain <api>-<endpoint>-<environment> naming:
search-production-production is one service, not two. Newer components use one
environment suffix. Cloud Run's Container / Source / Function labels describe
how a service was deployed, not whether it is obsolete.
Knowledge API and content worker require Google IAM/OIDC; Ingress: All does
not bypass it. Other services are public at the Cloud Run boundary, with protection
varying by route: API keys, user tokens, buyer OAuth or webhook checks. Rose MCP
has no inbound authentication. IXVector's webhook uses a shared secret; its widget
/link route is unauthenticated.
ixvector handles Vector.co identification; chat vectors live in ixrag storage.
The content worker produces artifacts; the document-loader job writes them to
retrieval storage. See Knowledge ingestion control plane.
Low traffic or an old deployment date does not establish that a service is a
leftover. Before retirement, check callers, external webhooks/MCP registrations
and deployment workflows. In particular, Rose MCP and R4A MCP have different tool
contracts, and rose-mcp-staging depends on the staging Search API.
System Components¶
- Product surfaces: Astro marketing website, React widget, client backoffice, playground, and Chrome extension.
- Cloudflare edge: Astro website Worker, the
api.userose.aiunified proxy, Cloudflare Pages, GCS widget assets, and R2 GEO pages. - Cloud Run APIs shown in the diagram: Search, Admin, Knowledge, knowledge content worker, Integrations, IXVector, and Rose MCP.
- Async execution: Cloud Tasks queues, Cloud Scheduler recovery, document loading, tagging, website mapping, PostHog batch processing, HubSpot sync, the fenced FAQ rollback job, and GEO publishing.
- Data: Supabase Postgres, Redis, MongoDB, Neo4j, the
rose-scrapingGCS bucket, the widget CDN bucket, and Cloudflare R2. - Providers: model and embedding vendors, visitor enrichment providers, observability and analytics products, and CRM/tools.
Architecture Diagram¶
The diagram reads top-to-bottom through seven layers: users, product surfaces, Cloudflare edge, Cloud Run services, asynchronous orchestration, data, and external providers. Detailed arrows are limited to the real-time chat lane and the knowledge-ingestion control plane so the operational paths remain legible.
Source of truth:
docs/diagrams/rose-system-architecture.dot.just devandjust buildrender the SVG intosrc/_generated/; do not edit or commit that generated asset. See the diagram inventory for ownership rules.
Component Details¶
Product Surfaces¶
| Component | Purpose | Technology |
|---|---|---|
| Marketing website | userose.ai |
Astro 6 with @astrojs/cloudflare |
| Widget | Embeddable Website Agent | React, TypeScript, UMD bundle |
| Client backoffice | Analytics, configuration, content, and operations | React, Vite, Cloudflare Pages |
| Playground | Internal testing across clients and environments | React, Vite, Firebase Hosting |
| Chrome extension | Inject and test Rose on arbitrary sites | WXT / Chrome Extension APIs |
The standalone stats opt-out extension is a developer tool and is intentionally not shown in the hosted runtime diagram. See Frontend Overview.
Backend Packages¶
| Package | Responsibility |
|---|---|
| ixchat | Website Agent LangGraph, skills, memory, and response routing |
| ixrag | LightRAG retrieval and tenant-aware storage integration |
| ixllm | Multi-provider model routing and fallback |
| ixknowledge | Knowledge workflow contracts and domain logic |
| ixscraping | Website discovery, scraping, and cleaning logic |
| ixconfig | Typed unified configuration models and resolver |
| ixskills | Global and per-client agent skill system |
| ixmongo / ixneo4j | Tenant-aware MongoDB and Neo4j adapters |
| ixdata / ixinfra / ixweb | Data access, shared runtime utilities, and web boundaries |
| ixgeo | GEO content generation and publishing |
| ixtagging / ixevaluation | Conversation classification and evaluation tooling |
Async and Batch Execution¶
| Execution unit | Trigger | Responsibility |
|---|---|---|
| Knowledge content worker | Discovery, scrape, and clean Cloud Tasks queues | Produce immutable artifacts and report fenced results to Knowledge API |
| Document loader | Knowledge API / approved on-demand execution | Write controlled snapshots to LightRAG, MongoDB, and Neo4j |
| Tagging | Cloud Scheduler | Classify and score conversations |
| Website mapping | Scheduled Cloud Run Job | Refresh website mapping data |
| PostHog batch processor | Scheduled Cloud Run Job, production only | Convert raw batch exports into analytics tables |
| HubSpot contacts sync | Jobs API / on demand | Synchronize CRM contacts and Rose data |
| Scheduled export | Scheduled Cloud Run Job (daily), production only | Post the previous day's or week's conversations and accounts exports to client webhooks |
| FAQ update | Scheduled, production-only rollback path | Legacy direct knowledge_faqs ingestion; fenced during controlled cutover |
| GEO pipeline | On demand | Generate geo.faqs publishing content and deploy static R2 pages |
config.knowledge_faqs is chat retrieval knowledge. geo.faqs is generated
publishing content and never enters the chat ingestion path.
Data Layer¶
- Supabase Postgres: configuration, conversations, analytics, GEO content, knowledge workflow state, immutable snapshot metadata, and freshness state.
- Redis: LangGraph checkpoints, conversation memory, locks, and caches.
- MongoDB: LightRAG chunks, vectors, key-value state, and document status.
- Neo4j: tenant-aware knowledge graph nodes and relationships, extracted by the LLM
with LightRAG's default entity types (
ENTITY_TYPESis not configured). Retrieval does not filter by type; the type only reaches the model as a label next to each entity. Node names are free text, so near-duplicates never merge: it is a search index, not a curated model of the client (production audit on IX-5554). - GCS
rose-scraping: immutable source and processing artifacts for the knowledge control plane. - GCS
inboundx-cdnand Cloudflare R2: widget assets and published GEO pages.
External Providers¶
Model selection is role-based rather than one global default:
| Role | Providers |
|---|---|
| Answer generation and fallbacks | Azure OpenAI and OpenAI |
| Fast routing, signals, and suggestions | Cerebras with configured fallbacks |
| Query rewriting | Mistral |
| Scraping decisions | OpenAI Europe (gpt-5.6-terra) |
| Selectable routes | OpenRouter routes, including Anthropic, Gemini, and Groq |
| Embeddings | Azure/OpenAI embeddings |
| Identity and enrichment | Reveal, Snitcher, RB2B, Vector, and Enrich.so |
| Observability and analytics | Langfuse, Sentry, and PostHog EU |
| CRM and tools | HubSpot, n8n, Linear, Google Drive, and IndexNow |
| Payments | Stripe (Billing, Checkout, Customer Portal, Tax) for self-serve plans |
The authoritative per-task model routing lives in
backend/packages/ixchat/ixchat/chat_routing.py; the diagram deliberately
avoids model-version labels that change frequently.
Primary Data Flows¶
Chat Request¶
- The widget sends a chat request through
api.userose.ai. - The Search API validates the request and invokes
ixchat. - LangGraph starts retrieval, enrichment, and profiling work and routes the turn through the appropriate response path.
ixragreads MongoDB and Neo4j;ixllmselects the configured model route.- Tokens stream back through the API proxy while checkpoints remain in Redis and conversation/profile data is persisted in Supabase.
The complete graph is generated from code on the IXChat package page.
Knowledge Ingestion¶
- Backoffice producers call the Admin API, which authorizes the user and calls the private Knowledge API with service-to-service OIDC.
- The Knowledge API records durable operation state in Supabase before dispatching discovery, scrape, or clean work to Cloud Tasks.
- The content worker writes immutable artifacts to GCS and reports fenced results to the Knowledge API.
- After snapshots converge, the Knowledge API admits the document-loader job, the only controlled writer to LightRAG stores.
- Cloud Scheduler invokes the same API dispatcher to recover pending or ambiguous work.
See Knowledge ingestion control plane for state transitions and operational details.
Analytics¶
- The widget sends
rw_*interaction and conversion events to PostHog through the unified analytics proxy. $pageviewand$pageleaveuse only the first-party path: the widget sends PostHog's canonical event shape to a narrow unified-Worker endpoint and suppresses its PostHog copy. The Worker durably enqueues it, and a private Queue consumer batches it intoanalytics.first_party_page_events_rawusing a service-role-only RPC.- PostHog exports the events on the batch export's
include_eventsallow-list (edited in the PostHog UI) intoposthog_events_rawin Supabase. - The production-only PostHog batch processor updates visitor sessions, page views, session events, conversations, and analytics marts.
- Backoffice pages read those tables and RPCs directly through RLS-protected Supabase access.
The batch processor treats first-party storage as the sole page-event source;
retained historical PostHog page-event copies are ignored. Operational deployment steps live in
backend/cloudflare/README_clean.md; the phased cutover design is recorded in
the PostHog cost and removal ADR.
Billing¶
- A self-serve client starts an upgrade from Plan & usage. The Admin API authorizes the user against every domain of the client and returns a Stripe-hosted Checkout URL; card entry, invoices, and cancellation stay in Stripe (Checkout and the Customer Portal).
- Stripe calls the Admin API webhook. The API verifies the signature, re-reads
the subscription from Stripe, and mirrors it through a service-role-only RPC
into
billing.client_billingandconfig.self_serve_plan_entitlements. - Rose only ever reads the entitlement. A client linked to billing without an active subscription is reported as stopped.
Billing belongs to the client, not the domain. Diagrams, states, and environment setup live in Self-serve billing.