Skip to main content

Architecture

How IntelliApps is built — the three data planes (control, app-data, assets), the stateless MCP + HTTP surface, the build-to-publish flow, the served routes, the Identity Bridge, and the runtime injected into every page.

IntelliApps is a stateless service: it holds no per-user or per-session state in process. Every request carries the identity it needs, so the service scales horizontally behind a load balancer with no sticky sessions.

The three data planes

Persistence is deliberately split into three independent planes so each can be scaled, secured, and swapped on its own.

PlaneStoresBackendIsolation
Control planeApp definitions, HTML, versions, shares, users/roles, comments, poll votes, annotations, forms + submissions, MCP metadataMongoDBOne database, per-document app_id
App-data planeGenerated per-app datasets and live read/write collectionsPostgreSQLOne schema per app (app_<app_id>), one typed table per collection
Asset planeBinary assets (images, fonts) referenced by appsS3-compatible object storageContent-addressed by SHA-256 (deduplicated)

Pluggable backends

Each plane has a pluggable backend so the test suite (and local runs) can operate with no live servers: platform_backend = mongo | memory, appdata_backend = postgres | memory, asset_backend = s3 | memory. Production uses mongo / postgres / s3. See Configuration → Data planes.

The two surfaces

IntelliApps exposes exactly two things on its single ASGI app:

  1. An MCP server at /mcp — a stateless Streamable HTTP MCP endpoint the IntelliAsk builder agent connects to. It exposes the tools that create apps, import datasets, save HTML, set the theme, preview, publish, export, and manage collections/forms. Identity is resolved per request from headers (below).
  2. HTTP display routes — the human-facing surface that serves previews, published pages, downloads, and the per-app runtime data/collection APIs.

Served routes (port 8000)

RoutePurpose
/Neutral landing splash (lists no apps — apps are unlisted by design)
/mcpStateless Streamable HTTP MCP endpoint (builder agent)
/health, /readyLiveness / readiness probes
/preview/...Signed, time-limited preview of a working version
/p/...Published shareable page
/a/{app_id}/...Per-app runtime surface — data, forms, collections, and the live collab/stream / collection stream SSE endpoints
/download/...Signed, time-limited self-contained export download
/runtime/...Static runtime assets (app-base.css, bundled ECharts)

Request identity

Because the service is stateless, identity is resolved per request from headers set by the IntelliAsk container (never trusted from the public internet — published pages use their own signed tokens instead):

HeaderMeaning
X-App-Service-KeyShared service key authenticating the IntelliAsk container to IntelliApps (must equal HTML_APP_MCP_API_KEY)
X-IntelliAsk-User-IDThe acting user's stable IntelliAsk id
X-IntelliAsk-User-EmailThe acting user's email

The MCP server config injected into IntelliAsk carries the identity as {{INTELLIASK_USER_ID}} / {{INTELLIASK_USER_EMAIL}} runtime placeholders that LibreChat resolves per user, so every builder action is attributed to the real signed-in user. See Connecting to IntelliAsk.

From build to published page

A typical app moves through these stages, each an MCP tool call from the builder agent:

  1. Create — an app shell is created with a durable app_id.
  2. Import data (optional) — a spreadsheet is streamed in bounded chunks (append_dataset_rows) into the app-data plane, idempotent by (import_id, chunk_index).
  3. Author — the agent saves HTML (save_app_html); each save is an immutable version.
  4. Bootstrap — on serve, the service injects a window.APP_DATA bootstrap (app id, version, the data/forms/collections API bases, datasets, theme, and brand logo) so the page can reach its live data and render its theme with no external calls.
  5. Preview / Publish / Export — the owner previews (signed token), publishes to a shareable page, or exports one self-contained HTML file (the export inlines everything and has no server dependency).

APP_DATA is always injected

The window.APP_DATA bootstrap is injected unconditionally — even for apps that never imported a dataset (forms-only or collection-only apps) — so APP_DATA.meta.dataApi / formsApi / collectionsApi are always defined and a page's live features can always reach their same-origin API.

The page runtime

Served pages link a small runtime, injected by the service:

  • /runtime/app-base.css — the design system: the --iha-* CSS variables that define the visual themes (go-light, go-dark, light, dark) plus base component styles. Charts read their colours from these variables so they recolour with the theme.
  • A bundled ECharts build — vendored so charts render offline with no CDN.
  • Injected chrome (ES5, CSP-safe) — the opt-in published-page features (ask-the-data, comments, polls, presence, applause, follow-the-presenter, annotations, forms SDK) are injected as small, CSP-safe ES5 scripts that talk only to the page's own same-origin runtime API. See Published-page features.

The Identity Bridge

Published pages carry two deliberately isolated identity planes:

  • Platform Feature Auth Plane — one global per-app toggle governing whether the platform-owned features (comments, annotations, pins, forms, reactions) attribute the authenticated IntelliAsk user. A short-lived signed token in an embedded view_url hands the identity off from an authenticated click to the direct page load, which the page exchanges for a per-viewer identity cookie.
  • App Code Auth Plane — optional and off by default. When enabled, only the owner/policy-approved subset of identity claims is exposed to the app's own generated HTML/JS, filtered server-side against the org allow-list.

See Security → Identity Bridge for the full model and its env knobs.

Last updated on