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.
centralis 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