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.

Emacs 29.3 (Org mode 9.6.15)