Axerity Docs
Concepts

Multi-tenancy

How organizations isolate your data — and why one user can belong to several.

Axerity is multi-tenant: your data lives alongside other customers' data in the same database, separated by an orgId on every row.

The hierarchy

User
 └─ Membership (role: OWNER / ADMIN / MEMBER)
     └─ Organization
         ├─ LedgerAccount[]
         ├─ JournalEntry[]
         ├─ Folder[] / File[]
         ├─ OrgApiKey[]
         └─ OrgPeriodLock

A User can be a member of multiple Organizations. An Organization owns its own books and files. The user's "active org" is stored on the user row and used by every dashboard query.

How isolation is enforced

Two layers:

1. The orgProcedure middleware (for oRPC) and the API key context (for REST). Both resolve a single org and attach orgId to the request context.

2. Every database query filters by orgId. The convention is nonnegotiable: any read or write touching an org-scoped row includes { where: { orgId: context.orgId } }. Plus a defensive check after fetching: if the row's orgId doesn't match, throw 404.

So even if an attacker forged an ID for another org's resource, the fetch returns null (the where filters it out), and 404 is the only possible response. There is no path that returns cross-org data.

Why two layers

Defense in depth. The middleware ensures the org context is set correctly per request. The per-query filter catches any bug in the middleware or handler. Both have to fail for a leak to occur.

API keys are per-org

When you generate an API key, it's bound to one specific organization. There's no "user-scoped" key that can switch orgs.

This means:

  • Revoking a key kills access to that one org only.
  • Inviting a teammate to an org doesn't give them keys.
  • Keys can outlive their creator (still works if the creating user leaves), or be killed when they do.

Switching orgs in the UI

Click the org pill at the top of the sidebar. The active org changes, the dashboard re-fetches, and you see a different set of books. The "active org" is stored on the user row server-side, so the choice persists across devices.

On this page