Tenancy & Authentication
One database per tenant
Each tenant is one database: one self-contained directory under <root>/dbs/<name>/ holding its catalog, delta log and segments. The database lifecycle is filesystem-simple — move, archive or delete a directory.
There is no internal cluster. Horizontal scale is database→node routing, external and manual: put heavy tenants on their own nodes, point their connection strings there.
Authentication
users.json at the root maps each user to a SCRAM-SHA-256 verifier (salt, iterations, stored key — never the password) and to exactly one database:
CREATE USER acme PASSWORD 's3cret' DATABASE acme;
- pg-wire authenticates with SCRAM-SHA-256; the connection is refused unless the requested database is the user's own. That wall is the entire authorization model — no roles, no grants.
- ILP carries no credentials by design; an ILP listener is bound to one database in the config (
listen.ilp_db) and should be firewalled to the devices that feed it.
On top of that wall sit exactly two management bits, not a role system. Admins are bound to no database and run only the management statements (CREATE/DROP DATABASE, CREATE/ALTER/DROP USER, SHOW DATABASES/USERS); the first one is defined in the config file (the postgres/sa pattern) and stays out of SQL's reach, further admins are created over SQL. Owners are ordinary database users that additionally manage the users of their own database — a tenant runs its own credential lifecycle (dashboard vs device logins) without seeing anything beyond its wall.
TLS on pg-wire is optional ([tls] in the config); clients that ask for SSL get a polite N when it is off.