Multi-Tenancy
Billerang runs multiple customer organizations (tenants) on a shared platform without letting one tenant see another's data. Isolation is enforced at three layers: authentication (Keycloak realm), data (provider-scoped persistence), and onboarding (Connect Portal).
The provider is the tenant
Internally, a tenant is represented by a provider. Every business entity, from a seller down to a rated transaction, is scoped to a provider either directly or through its parent hierarchy. A request is only ever allowed to read or write rows belonging to the provider it resolved to.
Billerang supports two data isolation strategies for a provider:
- Shared schema: all tenants share one database schema, and every table carries a provider discriminator. This is the default for smaller tenants and keeps operational overhead low, since one database serves many tenants.
- Schema-per-tenant: a tenant gets its own schema (or database) for full physical isolation. This is used for tenants with strict data residency or compliance requirements, or ones large enough that noisy-neighbor performance matters.
Both strategies are served by the same application code. The persistence unit that supports this is MeveoAdminMultiTenant, as opposed to the single-tenant MeveoAdmin unit used for standalone deployments.
Keycloak realm per deployment
Authentication is delegated to Keycloak. In a multi-tenant deployment, each tenant is provisioned its own Keycloak realm, so:
- User accounts, roles, and groups for one tenant are invisible to another.
- A tenant can be onboarded or removed without touching any other tenant's identity data.
- Tokens issued for one realm carry claims (realm name, provider code) that the API uses to resolve the tenant on every call.
Single-tenant, self-hosted deployments can also run with a single realm named for the deployment, since there is only one provider to resolve.
Request flow
Every request carries its tenant identity in the bearer token. The tenant resolution filter reads it once per request and sets the provider context for the rest of the call, so downstream services never need to pass a tenant id explicitly.
Connect Portal: tenant onboarding
New tenants are provisioned through the Connect Portal, a self-service onboarding flow that:
- Creates the tenant's Keycloak realm (or a realm entry in a shared multi-realm Keycloak instance) with an initial admin user.
- Creates the provider row and its initial configuration (default currency, default seller, default calendars).
- Wires the tenant's subdomain (for example
*.connect.billerang.com) to the shared WildFly deployment.
Because onboarding is scripted through the portal, adding a tenant does not require a new application deployment. The application server, database, and API are shared; only the realm and the provider row are new.
What stays shared vs. per-tenant
| Layer | Shared across tenants | Per tenant |
|---|---|---|
| Application server (WildFly) | Yes | No |
REST API (/api/v1/) | Yes | No |
| Keycloak instance | Usually | Realm is per tenant |
| Database instance | Depends on isolation strategy | Schema or discriminator is per tenant |
| Data (sellers, customers, invoices...) | No | Always scoped to a provider |