VersolaVersola/docs
versola.kzGitHub

Architecture

Architecture Planes

Versola is organized into three logical planes, each consisting of independently deployable services. Each service owns its own database with no shared schema. All inter-service communication happens through well-defined HTTP APIs.

Control Plane

  • Components: central + central-ui + central DB
  • Purpose: Platform configuration and management
  • Responsibilities: Administrators manage tenants, clients, scopes, roles, and permissions through the admin dashboard. central is the single source of truth for all configuration.

Data Plane

  • Components: auth + auth DB
  • Purpose: User authentication
  • Responsibilities: Handles OAuth 2.1/OIDC flows, issues tokens, manages authentication sessions, validates credentials and challenges, stores users and their authentication data. Syncs client and scope configuration from central.

Traffic Plane

  • Components: edge + edge DB
  • Purpose: User traffic proxying and authorization
  • Responsibilities: Accepts requests from browsers/applications, manages browser sessions, evaluates CEL authorization rules (roles and permissions), proxies requests to upstream backends with injected auth headers. Syncs configuration and JWKS from central.

System Context

flowchart TB
    admin[["👤 Admin<br/><i>Manages platform</i>"]]
    user[["👤 End User<br/><i>Accesses apps</i>"]]

    versola["⚡ Versola<br/><b>Identity & Authorization Platform</b>"]

    upstream{{"🔌 Upstream<br/>Backend APIs"}}
    notifications{{"📧 Notification Channel<br/>Notifications"}}

    admin -->|Manage| versola
    user -->|Auth| versola
    versola -->|Proxy| upstream
    versola -->|Request Notification| notifications

    style admin fill:#a78bfa,stroke:#a78bfa,color:#fff
    style user fill:#34d399,stroke:#34d399,color:#fff
    style versola fill:#58a6ff,stroke:#e6edf3,color:#fff,stroke-width:3px
    style upstream fill:#6e7681,stroke:#e6edf3,color:#fff
    style notifications fill:#6e7681,stroke:#e6edf3,color:#fff

Container Diagram

flowchart TB
    admin[["👤 Admin"]]
    user[["👤 User"]]

    subgraph versola["⚡ Versola Platform"]
        ui["central-ui<br/><i>Lit/TS</i><br/>Dashboard"]
        central["central<br/><i>Scala/ZIO</i><br/>Config"]
        edge["edge<br/><i>Scala/ZIO</i><br/>Proxy"]

        db_central[("central DB")]
        db_edge[("edge DB")]

        auth["auth<br/><i>Scala/ZIO</i><br/>OAuth"]
        db_auth[("auth DB")]
    end

    upstream{{"🔌 Upstream<br/>APIs"}}
    notifications{{"📧 Notifications<br/>OTP"}}

    admin -->|Manage| ui
    user -->|Login| edge

    ui -->|API| central
    central -->|R/W| db_central
    edge -->|R/W| db_edge
    edge -->|SSO| auth
    auth -->|R/W| db_auth
    edge -.->|Sync| central
    auth -.->|Sync| central

    edge -->|Proxy| upstream
    auth -->|Request| notifications

    style admin fill:#a78bfa,stroke:#a78bfa,color:#fff
    style user fill:#34d399,stroke:#34d399,color:#fff
    style ui fill:#58a6ff,stroke:#e6edf3,color:#fff
    style central fill:#58a6ff,stroke:#e6edf3,color:#fff
    style edge fill:#58a6ff,stroke:#e6edf3,color:#fff
    style auth fill:#58a6ff,stroke:#e6edf3,color:#fff
    style db_central fill:#1f6feb,stroke:#e6edf3,color:#fff
    style db_edge fill:#1f6feb,stroke:#e6edf3,color:#fff
    style db_auth fill:#1f6feb,stroke:#e6edf3,color:#fff
    style upstream fill:#6e7681,stroke:#e6edf3,color:#fff
    style notifications fill:#6e7681,stroke:#e6edf3,color:#fff
    style versola fill:#161b22,stroke:#e6edf3,stroke-width:2px,color:#e6edf3

Web OAuth Login & Proxy Flow

This flow is used for browser-based applications where edge acts as a session proxy.

sequenceDiagram
    autonumber
    participant B as Browser
    participant E as edge
    participant A as auth
    participant U as Upstream

    B->>E: GET /login/:presetId
    E-->>B: 302 → auth /authorize (PKCE, state)

    note over B,A: Challenge flow (password / OTP / passkey)

    A-->>B: 302 → edge /complete?code=…&state=…
    B->>E: GET /complete?code=…
    E->>A: POST /token (code + PKCE verifier)
    A-->>E: access_token + refresh_token
    E->>E: Store refresh token in DB
    E-->>B: 302 → app  +  Set-Cookie: EDGE_SESSION (JWT)

    note over B,E: Session active — every request carries the cookie

    B->>E: GET /resources/api/v1/data
    E->>E: Validate JWT, evaluate CEL rules
    E->>U: Forward + inject Authorization header (Basic / Bearer)
    U-->>E: 200 OK
    E-->>B: 200 OK (upstream Set-Cookie stripped)

Mobile OAuth Flow

This flow is used for native mobile applications. The key difference: the mobile app receives the authorization code via a deep link (custom URI scheme) and exchanges it directly with auth to obtain tokens. The app stores tokens securely (Keychain/Keystore) and includes the access token in the Authorization header when making requests through edge. The edge proxy validates the token and applies CEL authorization rules before forwarding to upstream APIs.

sequenceDiagram
    autonumber
    participant M as Mobile App
    participant A as auth
    participant E as edge
    participant U as Upstream

    M->>A: GET /authorize (PKCE, state, redirect_uri=app-scheme://)

    note over M,A: Challenge flow (password / OTP / passkey)

    A-->>M: 302 → app-scheme://callback?code=…&state=…
    M->>M: Extract code from deep link
    M->>A: POST /token (code + PKCE verifier)
    A-->>M: access_token + refresh_token
    M->>M: Store tokens securely (Keychain / Keystore)

    note over M,E: Session active — app sends requests with access_token

    M->>E: GET /resources/api/v1/data + Authorization: Bearer {access_token}
    E->>E: Validate JWT, evaluate CEL rules
    E->>U: Forward + inject Authorization header (Basic / Bearer)
    U-->>E: 200 OK
    E-->>M: 200 OK

    note over M,A: Token refresh when access token expires

    M->>A: POST /token (grant_type=refresh_token)
    A-->>M: new access_token + refresh_token