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.
| Plane | Stores | Backend | Isolation |
|---|---|---|---|
| Control plane | App definitions, HTML, versions, shares, users/roles, comments, poll votes, annotations, forms + submissions, MCP metadata | MongoDB | One database, per-document app_id |
| App-data plane | Generated per-app datasets and live read/write collections | PostgreSQL | One schema per app (app_<app_id>), one typed table per collection |
| Asset plane | Binary assets (images, fonts) referenced by apps | S3-compatible object storage | Content-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:
- 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). - 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)
| Route | Purpose |
|---|---|
/ | Neutral landing splash (lists no apps — apps are unlisted by design) |
/mcp | Stateless Streamable HTTP MCP endpoint (builder agent) |
/health, /ready | Liveness / 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):
| Header | Meaning |
|---|---|
X-App-Service-Key | Shared service key authenticating the IntelliAsk container to IntelliApps (must equal HTML_APP_MCP_API_KEY) |
X-IntelliAsk-User-ID | The acting user's stable IntelliAsk id |
X-IntelliAsk-User-Email | The 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:
- Create — an app shell is created with a durable
app_id. - Import data (optional) — a spreadsheet is streamed in bounded chunks
(
append_dataset_rows) into the app-data plane, idempotent by(import_id, chunk_index). - Author — the agent saves HTML (
save_app_html); each save is an immutable version. - Bootstrap — on serve, the service injects a
window.APP_DATAbootstrap (app id, version, thedata/forms/collectionsAPI bases, datasets, theme, and brand logo) so the page can reach its live data and render its theme with no external calls. - 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_urlhands 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