ores.iam.tenant

Table of Contents

Core entity for multi-tenancy support. Each tenant represents an isolated organisation with its own users, roles, and data. The system tenant is a special tenant used for shared reference data and system administration; its id is the maximum UUID value (ffffffff-ffff-ffff-ffff-ffffffffffff).

Tenants are identified by:

1. Flags

:system_tenant_visible: is stated because a tenant row is stored under the system tenant, not under itself: every row of this table carries tenant_id = ffffffff-ffff-ffff-ffff-ffffffffffff. Without the flag every read is filtered to tenant_id = <the caller's tenant>, which no row of this table satisfies, so a tenant can be listed but never read by key – and a read by key is what a history request, a delete and a single-record read all do.

The reads are guarded, as every generated read is, and here it matters more than most: the registry names every tenant the deployment holds. The roster reads it through iam.v1.tenants.list, and a read of every tenant is the deployment's to give: the list and the get need iam::tenants:read, which a person holds only in system administration and the reporting service holds to schedule each tenant's reports.

It is not a widening of what a caller may see. The row that filter excluded is the caller's own tenant, and a tenant admin is the one person who should see it.

The system tenant holds the shared reference data and the platform administration, so terminating or suspending it is close to unrecoverable. The dedicated lifecycle functions refuse it, and the generic delete and update paths must refuse it too: a check states that the row whose id is the system tenant stays active, which no write path can bypass. Suspending or terminating the system tenant is a constraint violation rather than a silent status change.

2. Columns

2.1. id

UUID uniquely identifying this tenant.

The system tenant has the maximum UUID value, ffffffff-ffff-ffff-ffff-ffffffffffff. A tenant row's own identity is this column and never tenant_id: the registry is the system tenant's, so the table's check requires every row, this one included, to carry the system tenant in tenant_id. A predicate that asks tenant_id which tenant a row describes therefore answers "the system tenant" for all of them.

2.2. code

Unique code for stable referencing. Its shape is the deployment's and not a form's: a lowercase letter first, then lowercase letters, digits and underscores, at most fifty characters. check_tenant_code states that to a caller as a sentence, and the table's check holds every other writer to it.

Examples: 'system', 'acme', 'demo'.

// no_generator_suffix: the "-<idx>" the template appends is not a shape this
// code may have, and the index starts again with every run, so a second run
// against the same database would ask for codes the first run's tenants hold.
// The index is joined with an underscore and followed by eight hex digits of
// a uuid, and the noun is lowercased because a faker noun can be an
// abbreviation such as "CD".
[idx]{
    std::string code(faker::word::noun());
    for (auto& character : code)
        if (character >= 'A' && character <= 'Z')
            character = static_cast<char>(character - 'A' + 'a');
    return code + "_tenant_" + std::to_string(idx) + "_" +
           std::string(faker::string::uuidV4()).substr(0, 8);
}()

2.3. name

Human-readable display name for the tenant.

std::string(faker::company::companyName())

2.4. type

Tenant type classification (FK to tenant_types). The synthetic generator emits the canonical automation type: the type/status insert validations reject any value with no active tenant_type row, and the seed data (iam_tenant_types_populate.sql) seeds the four system-tenant types, of which automation is the system-process default.

"automation"

2.5. description

Detailed description of the tenant.

std::string(faker::lorem::sentence())

2.6. hostname

Unique hostname for tenant routing.

// no_generator_suffix: the "-<idx>" the template appends is a process counter
// that starts again with every run, so a second run against the same database
// would ask for hostnames the first run's tenants hold. The hostname carries
// eight hex digits of a uuid instead.
std::string(faker::word::noun()) + "-" + std::string(faker::string::uuidV4()).substr(0, 8) +
    ".example.com"

2.7. status

Tenant lifecycle status (FK to tenant_statuses).

"active"

2.8. is_registration_default

Whether self-registrations land in this tenant when the address they arrive at names no tenant. At most one live row may hold it, because two tenants flagged as the default is a question with no answer.

The flag belongs to the super administrator. The write policy on this table admits only the system tenant, and every tenant row carries the system tenant, so only a super administrator may write a tenant row at all. That is also why the default party and the default role are not columns here: a tenant administrator could not set them.

false

3. SQL

3.1. Flags

3.2. Checks

The code and the hostname are shapes the deployment states, and the table says so as well as the service that provisions a tenant: check_tenant_code and check_tenant_hostname refuse a request with a sentence a person can read, and these hold every other caller to the same rule. A code whose shape is only checked by one caller is a code the deployment does not really state; a hostname that states a port is a principal the login cannot resolve.

expression
"id" <> 'ffffffff-ffff-ffff-ffff-ffffffffffff'::uuid or "code" = 'system'
"id" <> ores_utility_system_tenant_id_fn() or "status" = 'active'
"tenant_id" = ores_utility_system_tenant_id_fn()
"code" ~ '^[a-z][a-z0-9_]{0,49}$'
"hostname" <> ''
position(':' in "hostname") = 0

3.3. Delete sets

expression
status = 'terminated'

3.4. Indexes

name columns unique current_only where_extra
registration_default_tenant_uniq tenant_id true false is_registration_default and valid_to = ores_utility_infinity_timestamp_fn()

4. Insert trigger

4.1. Validations

column validation_function
type ores_iam_validate_tenant_type_fn
status ores_iam_validate_tenant_status_fn

5. C++

5.1. Flags

5.2. Repository

5.3. Domain includes

#include <string>
#include <boost/uuid/uuid.hpp>

5.4. Entity includes

#include <string>

5.5. Conventions

5.6. Table display

column header
code Code
name Name
type Type
hostname Hostname
status Status
modified_by Modified By
version Version

5.7. Presentation

5.7.1. Detail fields

field label widget type is_key is_required placeholder
code Code codeEdit line_edit true true Enter tenant code
name Name nameEdit line_edit   true Enter display name
type Type typeEdit line_edit     Enter tenant type
hostname Hostname hostnameEdit line_edit     Enter hostname
status Status statusEdit line_edit     Enter status

5.7.2. Columns

enum_name field header type width
Code code Code string 120
Name name Name string 200
Type type Type string 100
Hostname hostname Hostname string 180
Status status Status string 100
Version version Version int 80
ModifiedBy modified_by Modified By string 120
RecordedAt recorded_at Recorded At timestamp 150

5.8. Custom repository methods

6. See also

  • ores.iam — component group overview.

Emacs 29.3 (Org mode 9.6.15)