ores.iam.role
Table of Contents
A named collection of permissions that can be assigned to accounts. Roles group related permissions for easier management: a "Trading" role might include permissions to read and execute trades, while a "Support" role might have read-only access to most resources.
The table is bi-temporal and audited (see
projects/ores.sql/create/iam/iam_roles_create.sql): it carries
version, the four audit columns and the valid_from=/=valid_to pair
with the GIST exclusion and the delete rule, so the model takes the
ordinary audited shape and needs no shape flag.
The model describes the table alone. The hand-written domain struct also
carried a std::vector<std::string> permission_codes that no column
backs – it is denormalised from ores_iam_role_permissions_tbl by an
RBAC join. A joined shape is a message or a query result, never an entity
member, so the member is not modelled and the generated role.hpp
replaces it; the join itself stays in the hand-written authorization
layer.
The entity's canonical CRUD subjects are generated: role_registrar owns
list/get/get-many/put/put-many/delete on iam.v1.roles.*. The
authorization operation model declares a different set under the same
prefix – iam.v1.roles.assign, .revoke, .by-account,
.permissions and .suggest-commands – so the two coexist rather than
compete, and no handler is suppressed here.
1. Flags
2. Natural keys
3. Columns
3.1. name
Unique name for the role within its tenant (for example "Trading",
"Sales", "Admin"). It is the natural key, so the generated table adds
the partial unique index on (tenant_id, name) the hand-written table
already had.
std::string("Role_") + ctx.alphanumeric(6)
3.2. id
Unique identifier for the role.
3.3. description
Human-readable description of the role's purpose and scope.
std::string("Synthetic test role")
4. SQL
4.1. Flags
5. C++
5.1. Flags
5.2. Repository
5.2.1. read_latest_by_name
Reads the latest active role with the given natural-key name, scoped to
the caller's tenant. The generated CRUD set reads by primary key only and
its by-column finder is named for a code column, so the natural-key
read this entity's consumers already use stays a declared paste block
rather than a second, differently-named method on the repository.
std::vector<domain::role> read_latest_by_name(context ctx, const std::string& name);
std::vector<domain::role> role_repository::read_latest_by_name(context ctx, const std::string& name) { static const auto max(make_timestamp(MAX_TIMESTAMP, lg())); const auto tid = ctx.tenant_id().to_string(); const auto query = sqlgen::read<std::vector<role_entity>> | where("tenant_id"_c == tid && "name"_c == name && "valid_to"_c == max.value()); return execute_read_query<role_entity, domain::role>( ctx, query, [](const auto& entities) { return role_mapper::map(entities); }, lg(), "Reading latest role by name."); }
5.3. Domain includes
#include <chrono> #include <boost/uuid/uuid.hpp> #include <string>
5.4. Entity includes
#include <string> #include "sqlgen/Timestamp.hpp" #include "sqlgen/PrimaryKey.hpp"
5.5. Conventions
5.6. Table display
| column | header |
|---|---|
| id | ID (UUID) |
| name | Name |
| description | Description |
| modified_by | Modified By |
| version | Version |
5.7. Presentation
The screen's declaration. A role is addressed by its name, the natural key,
which is what the route's path segment carries and what the BFF asks the entity
by; the surrogate id is generated and the form does not offer it.
5.7.1. Detail fields
| field | label | widget | type | is_key | is_required | placeholder |
|---|---|---|---|---|---|---|
| name | Name | nameEdit | line_edit | true | true | Enter a role name |
| description | Description | descriptionEdit | text_edit | Enter a description |
5.7.2. Columns
| enum_name | field | header | type | width |
|---|---|---|---|---|
| Name | name | Name | string | 200 |
| Description | description | Description | string | 480 |
5.8. Paste blocks
6. See also
- ores.iam — component group overview.