03 / Develop · Core concepts

Core concepts ​

The vocabulary this section assumes — in the order the pieces actually connect. Read the flow once to build the mental model, then use the reference below to look a term up. Ready to build? Start Build a satellite.

The model in one line ​

VENI-AI is a set of Self-Contained Systems (SCS): the Shell owns identity and hosts the launchpad; each satellite is a full app — its own UI, API and database — that plugs in and owns its whole stack (repo, data and deploy). You build a satellite. Architecture →

How a satellite works ​

The path from a user opening your app to your API answering a request. Each step names the concepts it leans on:

  1. Federation — your UI is a Module Federation remote that exposes ./ShellEntry. The Shell imports it and mounts it at /<slug> at runtime — it hands your app a DOM container and your app calls ReactDOM.createRoot() into it — so a user moves between apps with no full page reload.
  2. Sign-in — the Shell signs the user in (local, Google, or any OIDC provider) and issues a Shell token: an RS256 JWT it broadcasts to your UI over a BroadcastChannel. A late-mounting remote must call requestToken() or it misses that broadcast.
  3. Token exchange — your API never trusts the Shell token directly. It verifies it against the Shell's JWKS (public keys at /api/.well-known/jwks.json — no shared secret) and exchanges it (POST /api/auth/exchange) for its own service token: an HS256 JWT carrying your local user's id, roles and permissions. A local user is provisioned on first sign-in. The handshake →
  4. Authorization — your handlers enforce access with guards from utils/auth-guards (requireAuth, requirePermission, …) against the token's roles and resource:action permission codes, resolved from your database at exchange time. Authorization →
  5. Data — your app owns its data in its own Postgres, defined and migrated with Drizzle — no shared tables. Every token carries an organizationId (the tenant): scope every query by it, and extend AuditedRepository so created_by / updated_by fill themselves. Multi-tenancy →
  6. Talking to other systems — for a live answer, call another app over Connect RPC (synchronous, plain HTTP with a Protobuf/JSON body). To stay in sync without calling on the hot path, publish and consume domain events on the Redis Streams event bus and keep a local read model — a satellite never reads another system's database. Integration →

Term reference ​

Quick lookup once the flow makes sense.

The platform

TermWhat it is
SCS (Self-Contained System)The platform's first rule — each app owns its whole stack (repo, database, deploy) and stays independent of the others.
ShellThe host app. Owns identity (users, organizations, roles), signs people in, and hosts the launchpad every app federates into. Shell →
Satellite (remote app)An app you build that plugs into the Shell — its own repo, DB and deploy, but rendered inside the Shell UI.
LaunchpadThe Shell's home screen that lists and opens the registered apps.

Frontend

TermWhat it is
Module FederationThe Vite feature that loads your UI into the Shell at runtime. Your app exposes ./ShellEntry; the Shell mounts it at /<slug>.
Mount patternHow a remote renders — the Shell passes a DOM container and your app calls ReactDOM.createRoot() into it, so the two React instances never collide.

Authentication

TermWhat it is
Shell token (RS256)The JWT the Shell issues at sign-in, signed with an RSA private key. Your app verifies and exchanges it — never trusts it directly.
Service token (HS256)Your app's own JWT, minted during the exchange, carrying your local user's id, roles and permissions. This is what your API checks.
JWKSThe Shell's public keys, at /api/.well-known/jwks.json. Your API verifies a Shell token against them, with no shared secret.
Token exchangeThe one call (POST /api/auth/exchange) that turns a Shell token into your service token, provisioning a local user on first sign-in. Generated for you.
Token broadcastHow a federated UI receives the Shell's token — over a BroadcastChannel. A late-mounting remote must call requestToken() or it misses the broadcast.

Backend stack

TermWhat it is
BunThe JavaScript runtime + package manager the platform runs on. bun install, bun run dev.
HonoThe lightweight web framework your API's routes are built on.
IgnisVENI's framework layer over Hono — the BaseApplication composition root, decorators (@controller, @get), the auth strategy, the health endpoint.
DrizzleThe type-safe SQL toolkit for defining tables (pgTable) and running migrations against Postgres.
RepositoryThe data-access layer — a class that owns the queries for one table. Extend AuditedRepository so audit columns fill themselves. The repository →

Authorization & data

TermWhat it is
Roles & permissionsThe RBAC model in the token — roles (e.g. admin) and resource:action codes (e.g. events:write), resolved from your DB at exchange time.
GuardsFunctions from utils/auth-guards (requireAuth, requirePermission, requireOwnerOrAdmin, …) that enforce roles/permissions at the top of a handler.
organizationIdThe tenant every token carries. Scope every query by it so one org never sees another's rows.

Cross-system

TermWhat it is
Connect RPC (gRPC)Synchronous server-to-server calls — plain HTTP with a JSON/Protobuf body. Use it to fetch live data from another system.
Redis Streams event busAsynchronous messaging — an app publishes events (XADD), others subscribe (XREADGROUP) and keep a local copy.
Read modelYour local copy of another system's data, kept fresh off the event bus, so your app is fast and still works when that system is down.

See also ​