Home › Data Structure
Data structure

Tenant, client entity, debt book — in that order.

Every account, case, payment and document belongs to a debt book, which belongs to a client entity, which belongs to a tenant. Nothing skips a level, and nothing crosses a tenant boundary.

Level 1

Tenant — the top-level, isolated organisation.

Every login, every API key, every debtor record sits under exactly one tenant. The active-tenant context is checked on every request — a tenant ID supplied by a browser or API client is never, on its own, enough to reach another tenant's data. An invalid or unassigned tenant returns HTTP 403, with no silent fallback to global data.

Level 2

Client Entity — the municipality or client inside a tenant.

A tenant can hold one client entity (a municipality collecting on its own book) or several (an agency serving multiple municipalities). Each client entity's debtors, reports and communications stay separated from every other entity in the same tenant.

Tenant: Metro Municipality
↪ Client Entity: City of Johannesburg
↪ Client Entity: Municipality B
↪ Client Entity: Municipality C
Level 3

Debt Book — the imported accounts, balances and arrears.

Each debt book belongs to one client entity and one tenant. Existing import functionality carries over unchanged — debt books are additive structure on top of the ingestion pipeline, not a rebuild of it.

Minimum debt book fields

id
tenant_id
client_entity_id
name
code
source_type
source_filename
account_count
total_balance
total_arrears
status
imported_at
created_by
metadata
Enforcement

Why cross-tenant access always returns 403.

A normal tenant user cannot reach another tenant's debtors, accounts, cases, payments, documents, communications, reports, imports, AI data or audit records. PLATFORM_SUPERADMIN may explicitly select any tenant; a tenant user may select only their assigned tenants; if a user has one tenant, it becomes the default automatically.

Want to see how your own debt books would map onto this structure?