Architecture

Understanding how Orbis works under the hood

Architecture

Orbis uses a layered architecture that separates concerns between the frontend, backend, and plugin system.

System Overview

graph TB
    subgraph User["User Interface"]
        Pages[Plugin Pages ]
        Components[UI Components ]
    end
    
    subgraph Frontend["Frontend Layer"]
        Renderer[Schema Renderer ]
        StateStore[Zustand State Store ]
        ActionExecutor[Action Executor ]
        Router[React Router ]
    end
    
    subgraph Backend["Backend Layer"]
        Commands[Tauri Commands ]
        PluginRT[Plugin Runtime ]
        AuthService[Auth Service ]
        DBLayer[Database Layer ]
    end
    
    subgraph Plugins["Plugin System"]
        WASM[WASM Sandbox ]
        Manifest[Plugin Manifest ]
        Schemas[UI Schemas ]
    end
    
    subgraph Storage["Storage Layer"]
        SQLite[(SQLite)]
        PostgreSQL[(PostgreSQL)]
        Filesystem[(Filesystem)]
    end
    
    Pages --> Components
    Components --> Renderer
    Renderer --> StateStore
    Renderer --> ActionExecutor
    ActionExecutor --> Commands
    
    Commands --> PluginRT
    Commands --> AuthService
    PluginRT --> WASM
    PluginRT --> DBLayer
    AuthService --> DBLayer
    DBLayer --> SQLite
    DBLayer --> PostgreSQL
    DBLayer --> Filesystem
    
    Manifest --> Schemas
    Schemas --> Renderer

Layers Explained

1. User Interface Layer

The visible part of the application where users interact with plugins.

Responsibilities:

  • Display plugin pages
  • Handle user input
  • Show feedback (toasts, modals, etc.)

Key Insight: Users don’t see “Orbis” - they see plugin UIs rendered from schemas.

2. Frontend Layer

React application that interprets schemas and manages state.

ComponentPurpose
Schema RendererConverts JSON schemas to React components
State StoreManages reactive page state with Zustand
Action ExecutorProcesses action schemas (clicks, form submits)
RouterHandles navigation between plugin pages

3. Backend Layer

Rust-powered backend running in Tauri.

ServicePurpose
Tauri CommandsIPC bridge between frontend and backend
Plugin RuntimeLoads and executes WASM plugins
Auth ServiceHandles authentication and sessions
Database LayerAbstracts SQLite/PostgreSQL access

4. Plugin System

Sandboxed plugin execution environment.

ComponentPurpose
WASM SandboxSecure plugin execution
Plugin ManifestDeclarative plugin configuration
UI SchemasJSON-based UI definitions

5. Storage Layer

Pluggable database backend supporting two modes:

  • SQLite: Embedded database for standalone mode
  • PostgreSQL: External database for client-server mode
  • Filesystem: For storing plugin assets and user data

Deployment Modes

Orbis supports two deployment architectures:

Standalone Mode

Everything runs locally on the user’s machine.

graph LR
    subgraph Desktop["User's Computer"]
        App[Orbis App] 
        DB[(SQLite)]
        Plugins[Plugins ]
    end
    
    App --> DB
    App --> Plugins

Use Cases:

  • Personal productivity apps
  • Development and testing
  • Offline-first applications

Client-Server Mode

Multiple clients connect to a shared backend.

graph TB
    subgraph Clients["Client Machines"]
        Client1[Orbis Client 1 ]
        Client2[Orbis Client 2 ]
        Client3[Orbis Client 3 ]
    end
    
    subgraph Server["Server"]
        API[Orbis Server ]
        DB[(PostgreSQL)]
        PluginHost[Plugin Host ]
    end
    
    Client1 --> API
    Client2 --> API
    Client3 --> API
    API --> DB
    API --> PluginHost

Use Cases:

  • Team collaboration
  • Enterprise deployments
  • Multi-user applications

Data Flow

Rendering Flow

How a plugin page gets displayed:

sequenceDiagram
    participant User
    participant Router
    participant Renderer
    participant State
    
    User->>Router: Navigate to /plugin/page
    Router->>Renderer: Load PageDefinition
    Renderer->>State: Initialize state from definition
    State-->>Renderer: Initial state
    Renderer-->>User: Rendered UI

Interaction Flow

How user interactions are processed:

sequenceDiagram
    participant User
    participant Component
    participant Action
    participant State
    participant Backend
    
    User->>Component: Click button
    Component->>Action: Execute on_click actions
    Action->>State: update_state action
    State-->>Component: State updated
    Component-->>User: UI re-renders
    
    alt API call needed
        Action->>Backend: call_api action
        Backend-->>Action: Response
        Action->>State: Update with response
        State-->>Component: State updated
        Component-->>User: UI re-renders
    end

Security Architecture

Plugin Sandboxing

Plugins run in isolated WASM sandboxes with:

  • No direct filesystem access (requires permissions)
  • No network access (requires permissions)
  • Memory isolation (separate address space)
  • Capability-based security (explicit permission grants)
rust
// Plugin permissions in manifest
{
  "permissions": [
    { "type": "network", "allowed_hosts": ["api.example.com"] },
    { "type": "storage", "scope": "plugin-data" }
  ]
}

Authentication Flow

sequenceDiagram
    participant User
    participant Frontend
    participant Backend
    participant DB
    
    User->>Frontend: Enter credentials
    Frontend->>Backend: login command
    Backend->>DB: Validate credentials
    DB-->>Backend: User data
    Backend->>Backend: Generate JWT
    Backend-->>Frontend: Session token
    Frontend->>Frontend: Store in state
    Frontend-->>User: Redirect to app

Performance Considerations

Schema Renderer

The SchemaRenderer processes JSON schemas into React components. Key optimizations:

  • Expression caching (avoid re-parsing)
  • Memoization for static components
  • Virtual scrolling for large lists

State Management

Zustand with Immer provides:

  • Immutable updates without boilerplate
  • Selective re-renders via subscriptions
  • Efficient nested state updates

Plugin Loading

  • Lazy loading of plugin pages
  • Manifest caching
  • Hot reload in development

Extension Points

Orbis is designed for extensibility:

Extension PointMechanism
New componentsAdd to ui.rs + components.ts + renderer.tsx
New actionsAdd to ui.rs + actions.ts
Custom schemasPlugin manifest pages array
Backend APIsTauri commands + plugin routes

Next Steps