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:
- id: UUID primary key, which is the row's own identity. The
tenant_idcolumn is the system tenant's, because the registry belongs to it and its check requires that of every row. - code: Unique text code for stable referencing (e.g., 'system', 'acme')
- hostname: Unique hostname for tenant routing during login
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.