Skip to main content

Overview

Architecture

Introduction

Cirata Symphony is a multi-tenant data orchestration platform that enables users to operate distributed extensions which connect to and interact with the Symphony control plane. It serves as both a runtime environment and a coordination hub, integrating external systems, managing workflows, and extending both user interface and API functionality in a modular and extensible way.

The platform emphasizes runtime flexibility, dynamic extension, and composable orchestration. Its design is grounded in strong tenant isolation, a message-oriented core based on NATS, and a stateless, clustered control plane that scales horizontally and integrates seamlessly into diverse infrastructure environments.

Tenancy and Isolation

Each user in Symphony is treated as a distinct tenant. Tenants may also be associated with broader groups—such as teams or organizations—that define shared visibility boundaries for resources and data. This allows collaborative access where appropriate, while preserving isolation by default.

All user data, extensions, and messaging permissions are isolated through the security model enforced by communication through NATS. Symphony leverages NATS's subject-based authorization model to ensure strict separation between tenants. By default, users cannot access resources created by others; however, users within the same organization may opt to explicitly share data or services with other members of their group, and those members may opt to accept those shared resources.

Core Components

Control Plane

The Cirata Symphony control plane is a stateless, horizontally scalable service that may run as a single process or a distributed cluster. It does not rely on shared disk or centralized databases. Instead, it uses NATS for persistent coordination, messaging, and metadata storage.

The control plane provides key platform services including authentication and authorization, a dynamic single-page application for the user interface, an extensible REST API, a NATS-based messaging interface, JetStream-backed metadata stores, and OTLP telemetry (metrics, logs, and traces). All orchestration, UI, and API features provided by Symphony are exposed through this unified control layer.

Extensions

Extensions are external runtime services—often executed as containers, virtual machines, or bare processes—that connect to the Symphony server via NATS. These extensions register their presence and features dynamically at runtime by publishing metadata to a JetStream key-value store.

Each extension authenticates using a token that encapsulates a credential and the network address of the Symphony instance. The extension's metadata includes descriptions of its available microservices, any OpenAPI specifications for HTTP services that it wants the Symphony instance to expose for it, and UI contributions such as routes, resources, or widgets. Cirata Symphony uses this metadata to immediately and dynamically update its UI and API surface area.

Extensions can be ephemeral and decoupled from the Symphony server. When an extension disconnects, its metadata will expire, and Symphony can indicate that the extension is not in an operating state. If it reconnects later, its persisted data in JetStream remains available for continuity. Extensions are free to implement their own additional mechanisms for maintaining state independently of the Symphony server.

API and Interface Model

Programmatic Interfaces

Cirata Symphony exposes a variety of interfaces for programmatic access. Its messaging layer is built on NATS, where subjects serve as the primary abstraction for routing messages and requests. Extensions implement services on specific NATS subjects, and Symphony mediates access through strict subject-level permissions.

The Symphony REST API is generated automatically by interpreting OpenAPI specifications published by extensions. These HTTP endpoints are mapped directly to NATS subjects, allowing external clients to invoke extensions' services over HTTP without needing knowledge of where those services are implemented.

A command-line tool is provided for operational tasks such as inspecting system metadata, invoking extension services, or managing orchestration workflows. In addition, Symphony provides full-featured client libraries for Python, Java, Go, and Rust, enabling users to interact with the platform's messaging and control APIs programmatically.

User Interface

Symphony's UI is implemented as a single-page React application that supports dynamic extension by user-contributed components. When an extension connects and registers UI routes and components, Symphony compiles the provided TypeScript code and integrates it seamlessly into the browser interface. This approach allows the user interface to evolve at runtime, with extensions defining their own interactive workflows, dashboards, or management panels.

The JavaScript libraries needed to compile and render extension UI components are obtained in one of three ways depending on the deployment's dependency resolution mode (configured in Admin → Settings):

  • Proxy mode (default): bare specifiers in extension JSX are fetched on demand from the jsDelivr CDN (cdn.jsdelivr.net) via a server-side proxy and cached in memory. Requires outbound HTTPS access to cdn.jsdelivr.net.
  • Mixed mode: extensions that ship a pre-built dependency bundle resolve their imports locally; bare specifiers not in the bundle fall through to the jsDelivr proxy.
  • Bundle-only mode: the jsDelivr proxy is disabled. Extensions must ship pre-built dependency bundles for every non-platform import. Suitable for air-gapped, compliance-restricted, or supply-chain-hardened deployments. Symphony requires no outbound HTTPS in this mode.

The platform's own UI assets (React, Babel, MUI, htmx, Mermaid, oidc-client-ts, etc.) are vendored locally and served from /vendor/* regardless of mode — they never depend on outbound HTTPS.

See Outbound Network Access for details and guidance on network-restricted environments, and Bundling UI Dependencies for how an extension ships a bundle.

Orchestration Model

Symphony does not directly implement scheduling, workflow graphs, or orchestration DAGs within the control plane itself. Instead it provides a common, secure and scalable platform for exposing functionality to your choice of execution engine. Whether you use an orchestration technology like Prefect, Airflow or Dagster, Cirata Symphony simplifies access to your data systems. Build your orchestration logic in your preferred systems, or develop extensions that coordinate the behavior of your systems.

One example of this is the intelligence extension, which uses a language model capable of orchestrating activity across all Symphony services through a common interface. While Cirata Symphony does not provide built-in cron scheduling, extensions are free to integrate external schedulers or emit time-based events via NATS to coordinate execution.

Storage and State

Symphony uses NATS JetStream as its default persistence layer. All platform metadata, such as extension feature declarations, orchestration state, and user configuration, is stored in JetStream key-value stores. Extensions may also use their own key-value stores provided by the Symphony server to persist their own state across restarts.

NATS JetStream provides built-in support for time-to-live (TTL), expiration, and stream pruning, which Symphony relies upon to automatically remove stale extension data when an extension becomes unavailable. Extensions are also free to manage their own data independently, using any external persistence mechanisms they prefer.

Security Model

Cirata Symphony employs a zero-trust security model based on standard identity providers and fine-grained messaging permissions. User access to the UI and APIs is governed via identity provided through integration with an OpenID Connect (OIDC) provider, enabling centralized authentication and federated identity management.

Programmatic access—such as from extensions or automation clients—is governed using tokens derived from API Keys. Each token embeds a network address and secret that together determine the NATS identity and permissions granted to the caller. These permissions govern access to specific NATS subjects, which automatically extend to REST endpoints and UI components.

Administrators can further refine access using Role-Based Access Control (RBAC), which maps groups from the OIDC identity provider to Symphony roles. Each role defines a set of publish and subscribe permissions on NATS subjects, allowing fine-grained control over which users can access specific extensions, services, and administrative functions.

For secret management, Cirata Symphony exposes an abstraction that can be backed by various external secrets managers (e.g., HashiCorp Vault). Extensions and CLI tools use Symphony APIs to retrieve secrets without having to manage low-level integrations directly.

Deployment and Topology

Cirata Symphony is available in two deployment modes: as a hosted service, or as a self-managed installation. Self-hosted Symphony instances are fully independent and may be operated by individual organizations, teams or even individual users. Multiple instances can also be federated through NATS clustering to form a single logical Symphony network, sharing metadata and messaging capabilities in real time.

Because the control plane is stateless and uses NATS for communication and persistence, it can be deployed as a resilient cluster with no shared disk requirements. All inter-node communication and coordination flows through NATS and its consensus-backed storage primitives.

Example Topologies

Minimal Deployment

A single host runs the Symphony server (with bundled Keycloak for authentication) and one or more extensions. This is suitable for evaluation, development, and small-scale production use.

Production Deployment

In production, extensions are typically deployed on separate hosts, close to the data or systems they manage. For example, a Data Migrator extension runs on a host with access to the source and target file systems, while an AI extension runs where GPU resources are available.

Extensions require network access to the Symphony server's NATS port (4222) and should be deployed where they can reach the data or systems they manage.

High-Availability Production Deployment

For production environments that require fault tolerance, deploy a cluster of three or more Symphony instances behind a load balancer. Each instance holds a complete copy of all replicated state, so any node can serve any request independently. If a node fails, the remaining nodes continue operating and extensions automatically reconnect to a healthy node. See the High Availability guide for full setup instructions.

Network Ports

The following ports are used by Symphony and may need to be opened between hosts. All ports support TLS encryption.

PortProtocolDirectionServiceDescription
443TCP/TLSInboundHTTPSUI, REST API, and WebSocket (via nginx reverse proxy)
80TCPInboundHTTPRedirects to HTTPS
4222TCP/TLSInboundNATSMessaging—used by extensions, CLI, and client libraries
8080TCPInternalHTTPSymphony internal HTTP server (behind reverse proxy)
9222TCPInternalWebSocketSymphony internal WebSocket server (behind reverse proxy)
443TCP/TLSOutboundHTTPSjsDelivr CDN (cdn.jsdelivr.net) — JavaScript libraries for extension UIs. Required only when dependency resolution mode is proxy or mixed. Not required in bundle-only mode.

NATS TLS (port 4222) is optional and configured on the server side. When enabled, all native NATS connections must use TLS. Client SDKs detect this automatically. See TLS and Certificates for configuration details.

Observability and Monitoring

Symphony provides integrated observability features for both platform services and extensions. The platform and extensions emit OTLP (OpenTelemetry) telemetry—metrics, logs, and traces—which the Observability Extension collects over NATS and can export to backends such as Prometheus, Grafana, or InfluxDB.

Extension liveness is inferred by tracking whether its metadata has been updated recently. If an extension disconnects without explicitly removing its registration, the platform uses automatic TTL expiration to clean up its state. Audit logs are written to a system-owned JetStream store, capturing key actions and system events for future analysis.

Extension Lifecycle and Discovery

Extensions in Cirata Symphony are dynamic and stateless by design. There is no required packaging or build process—they simply connect, publish features, and begin operating. When an extension registers new UI components, microservices, or OpenAPI definitions, those changes are reflected immediately in the running Symphony instance.

Cirata Symphony uses standard NATS microservice discovery patterns to route requests to extensions. Since metadata is persisted in JetStream, clients and users can discover available extensions even before the extension is live. However, any functionality that depends on runtime execution will only become available once the extension is connected and serving traffic.

This fluid extension model gives users flexibility to build and iterate on functionality without restarting or reconfiguring the platform, and allows Symphony deployments to scale organically with usage.