Skip to content

Architecture

flowchart LR
    Admin[Platform administrator<br/>browser or MCP client<br/>Keycloak role platform-admin]
    User[Platform user<br/>browser or MCP client<br/>Keycloak account linked to a user]

    subgraph AdminPortal[Admin portal · iceberg-platform]
        AdminAPI[FastAPI admin portal :3000<br/>UI and /mcp<br/>Keycloak client iceberg-admin]
    end
    subgraph UserPortal[User portal · iceberg-workspaces]
        UserAPI[FastAPI user portal :3002<br/>UI and /mcp<br/>Keycloak client iceberg-users]
        Docker[Trusted Docker daemon<br/>or Kubernetes API]
        Notebook[Session marimo container<br/>or pod]
    end
    subgraph Extension[Extension, e.g. Conversational BI, dbt, Ingestion or OpenMetadata · own Compose project or Helm chart]
        ExtApp[Gateway: UI, API and /mcp<br/>Keycloak clients of the extension]
        Worker[Query worker]
    end
    subgraph Core[Shared core · iceberg-platform]
        Keycloak
        Bridge[Extension Bridge<br/>/bridge/v1 :3005]
        Polaris[Apache Polaris]
        Storage[RustFS S3 and IAM]
        Postgres[(PostgreSQL metadata)]
    end
    subgraph ThirdParty[Third party: external data share]
        Recipient[DuckDB or other Iceberg client]
    end

    Admin --> AdminAPI
    User --> UserAPI
    User --> ExtApp
    UserAPI -.->|Link| ExtApp

    AdminAPI & UserAPI & ExtApp -->|Sign-in| Keycloak
    AdminAPI --> Polaris
    AdminAPI --> Storage
    UserAPI --> Polaris
    UserAPI --> Docker --> Notebook
    UserAPI -->|HTTP and WebSocket proxy| Notebook
    Notebook -->|User credentials| Polaris
    Notebook -->|Vended credentials| Storage
    ExtApp -->|User context, automation principals| Bridge
    Bridge --> Polaris
    Worker -->|Short-lived Iceberg REST token| Polaris
    Worker -->|Vended credentials| Storage
    Polaris --> Postgres

    User -.->|Client ID, secret and DuckDB script| Recipient
    Recipient -.->|Read-only client credentials| Polaris
    Recipient -.->|Vended read-only credentials| Storage

    style AdminPortal fill:#3b82f61a,stroke:#3b82f6,stroke-width:2px
    style UserPortal fill:#10b9811a,stroke:#10b981,stroke-width:2px
    style Extension fill:#8b5cf61a,stroke:#8b5cf6,stroke-width:2px
    style Core fill:#64748b1a,stroke:#64748b,stroke-width:1px
    style ThirdParty fill:#f59e0b1a,stroke:#f59e0b,stroke-width:2px,stroke-dasharray:6 4

The two portals are separate applications with separate sign-ins. The admin portal accepts only Keycloak accounts with the platform-admin role and manages teams, users, databases and storage. The user portal accepts only Keycloak accounts linked to a platform user, and serves catalog browsing, shares and notebooks. Signing in with an account meant for the other portal fails: platform-admin is not a platform user, and a platform user is not an administrator.

Extensions are a third kind of application, for platform users. Each one runs in its own Compose project, or with its own Helm chart, and signs in through its own Keycloak clients, whose tokens Polaris refuses. It reaches the core only through the Extension Bridge, which runs in the platform project next to the admin portal. The user portal links to each registered extension. See the Extension Bridge.

The third party never signs in to a portal. A team administrator hands over the share credential, and the recipient reads only the shared tables, views and semantic models through Polaris and RustFS.

Services

File Project Services
compose.yaml iceberg-platform Admin portal, Extension Bridge, Keycloak, Polaris, PostgreSQL, RustFS, pgAdmin, monitoring
compose.users.yaml iceberg-workspaces User portal, plus the notebook image build
extensions/conversationalbi/compose.yaml iceberg-conversationalbi Optional Conversational BI extension, released separately (see extensions)
extensions/dbt/compose.yaml iceberg-dbt Optional dbt extension: API, MCP and viewer, and the launcher of isolated run containers, released separately
extensions/ingestion/compose.yaml iceberg-ingestion Optional Ingestion (dlt) extension: page, API and MCP, and the launcher of isolated run containers, released separately
extensions/openmetadata/compose.yaml iceberg-openmetadata Optional OpenMetadata sync of listed data shares, with its own installer and release
  • Keycloak signs in people and MCP clients. Polaris holds all application metadata (teams, users, databases, shares) and enforces data permissions; see the resource model. There is no separate application database. Polaris also stores the Apache Ossie semantic models of each namespace (beta in Polaris 1.8, see semantic models).
  • The user portal joins the platform network and doesn't depend on the admin portal. Catalog browsing and notebooks use the signed-in user's own token. The portal uses its platform identity only for directory lookups and for the database and share actions of team administrators.
  • Both portals keep sessions in memory (deployment boundaries) and serve /mcp for MCP clients, which authenticate every request with their own bearer token.

Extensions

Extensions add functionality in their own Compose project (or Helm chart) and release cycle, and reach the core only through the Extension Bridge (bridge service, /bridge/v1), Iceberg REST and S3. See the Extension Bridge.

Notebooks

  • Each team and environment shares one filespace volume, across all its databases.
  • Each session and database runs in its own container on a private network with the portal, Polaris and RustFS. The container runs as a non-root user with a read-only root filesystem and resource limits, and it never receives the Docker socket or platform secrets.
  • Logging out, switching team or environment, or losing access stops that session's containers. Saved files persist.

The Helm chart runs the same services on Kubernetes, with notebooks and extension runs as pods in namespaces of their own instead of containers on the Docker host. With Compose, the user portal controls Docker and is therefore a trusted service. The same goes for the internal monitor collector, which feeds the admin portal's Infrastructure page, and for the launchers of the dbt and Ingestion extensions (dbt-launcher, ing-launcher), which start their isolated run containers. See the security model.

Repository layout

Path Purpose
server/ Administration API, OIDC, Polaris and RustFS adapters
public/ Admin UI and shared fonts/favicon
user_portal/ User API, notebook lifecycle and proxy
user_portal/public/ User interface
user_portal/notebook/ Notebook image, connection helpers and example notebooks
scripts/ Setup, integration checks and release tooling
pgadmin/ Preconfigured pgAdmin connection (Compose only)
deploy/helm/ The platform's Helm chart; see Kubernetes
dev/kubernetes/ Maintainer tooling for Kubernetes: kind and Scaleway test clusters, network checks; not released
.agents/skills/ Agent skills that ship in the installation folder
test/ Unit and authorization tests
docs/ Documentation site, built with Zensical (zensical.toml): installer users at the top level, docs/develop/ for building and internals
contracts/bridge/ Extension Bridge contract: OpenAPI, table-property, network and handshake conventions
extensions/ Extensions with their own versions and releases: extensions/conversationalbi, extensions/dbt, extensions/ingestion and extensions/openmetadata; each but OpenMetadata has a chart in deploy/helm/
presentation/ reveal.js deck, published under /presentation/ of the documentation site and excluded from source releases