ores.iam.account_messages

Table of Contents

The account protocol messages.

1. Includes

#include "ores.iam.api/domain/account.hpp"
#include "ores.iam.api/domain/account_contact_information.hpp"
#include "ores.iam.api/domain/login_info.hpp"
#include "ores.iam.api/domain/session.hpp"
#include "ores.utility/domain/protocol.hpp"
#include <optional>
#include <string>
#include <vector>

2. Messages

The publish trigger is declared here beside the operations, because it is a subject IAM owns and nothing else states it: the DQ artefact-type row that publishes onto it carries the same string in SQL, and a constant generated from here is what the registrar subscribes with.

2.1. publish_accounts_from_dq_request

/**
 * @brief The workflow step that publishes a DQ-cleared accounts bundle.
 *
 * A trigger rather than a request: the DQ publisher sends it and reads no
 * reply, so it states a subject and no response. Its body is the DQ artefact
 * the server-side function knows how to expand, which is why it declares no
 * fields.
 */

2.2. save_account_request

2.2.1. principal

2.2.2. password

/**
 * @brief The account's initial password, in the clear, to be hashed
 * server-side.
 *
 * The only credential a request carries, and the only direction one
 * travels. The hash the server derives from it is written to the account's
 * credential row and never leaves it.
 */

2.2.3. email

2.2.4. account_type

2.3. update_account_request

2.3.1. account_id

2.3.2. email

2.3.3. full_name

/**
 * @brief The account holder's full (real) name. Empty clears it.
 */

2.3.4. default_party_id

/**
 * @brief Party to set as the account's default quick-login party.
 * Empty clears the default. Must be one of the account's assigned
 * parties (validated server-side).
 */

2.3.5. job_title

/**
 * @brief Job title / functional role of the person holding this
 * account (e.g. "Head of Desk", "Senior Trader"). Empty clears it.
 */

2.3.6. reports_to_account_id

/**
 * @brief The account this person reports to. Empty clears it. Must
 * be another account in the same tenant (validated server-side).
 */

2.3.7. image_id

/**
 * @brief Profile picture for this account. Empty clears it. Must
 * reference an existing image (validated server-side).
 */

2.3.8. change_reason_code

2.3.9. change_commentary

2.4. update_account_response

2.4.1. success

2.4.2. message

2.5. save_account_response

2.5.1. success

2.5.2. message

2.5.3. account_id

2.6. delete_account_request

2.6.1. account_id

2.7. delete_account_response

2.7.1. success

2.7.2. message

2.8. account_operation_result

2.8.1. success

2.8.2. message

2.9. lock_account_request

2.9.1. account_ids

2.10. lock_account_response

2.10.1. results

2.11. unlock_account_request

2.11.1. account_ids

2.12. unlock_account_response

2.12.1. results

2.13. reset_password_request

2.13.1. account_ids

2.13.2. new_password

2.14. reset_password_response

2.14.1. success

2.14.2. message

2.14.3. results

2.15. change_password_request

2.15.1. current_password

2.15.2. new_password

2.16. change_password_response

2.16.1. success

2.16.2. message

2.17. update_my_email_request

2.17.1. email

2.18. update_my_email_response

2.18.1. success

2.18.2. message

2.19. set_my_default_party_request

/**
 * @brief A member's write on the party quick sign-in uses.
 *
 * The session names the account, so the request cannot aim the write at
 * another account, and the write needs no permission. The party must be one
 * the account is associated with, or the write is refused: the server checks
 * the association rather than trusting the caller.
 *
 * An empty =party_id= clears the stored default. A party id is a UUID, so an
 * empty string is unambiguous, and this is the only way the request can say
 * "no default" — the reason the member's screen had no clear control before.
 */

2.19.1. party_id

/**
 * @brief The party to store as the default, or empty to clear it.
 */

2.20. set_my_default_party_response

2.20.1. success

2.20.2. message

2.21. select_party_request

2.21.1. party_id

2.22. switch_party_request

/**
 * @brief Re-scopes an *already-logged-in* session to a different party.
 *
 * Deliberately a separate subject/handler from select_party rather than a
 * relaxed version of it: select_party only accepts a narrowly-scoped,
 * single-use token (audience "select_party_only") issued exclusively by
 * the login flow, by design -- see account_operations_handler.hpp's select_party for
 * why. switch_party accepts a normal, already-authenticated session token
 * instead (any token that is NOT that single-use one), so an account with
 * access to more than one party (e.g. a tenant admin with cross-entity
 * access) can change which party's data is in view mid-session without
 * logging out and back in. Same party-membership check and new-token
 * issuance as select_party otherwise.
 */

2.22.1. party_id

2.23. select_party_response

2.23.1. success

2.23.2. message

2.23.3. token

2.23.4. username

2.23.5. tenant_name

2.23.6. party_name

2.23.7. party_setup_required

/**
 * @brief True when the selected party's status is 'Inactive'.
 * The client should present the PartyProvisioningWizard immediately.
 */

2.23.8. party_setup_warning

/**
 * @brief Set when the party provisioner wizard has completed
 * (onboarding.party = true) but the party is still Inactive. The
 * client should show a message instead of re-launching the wizard.
 */

2.23.9. access_lifetime_s

/**
 * @brief Token lifetime in seconds for the newly issued token.
 *
 * Clients re-arm the proactive refresh timer using this value.
 */

2.24. change_password_request_typed

2.24.1. current_password

2.24.2. new_password

2.25. update_self_account_request

/**
 * @brief A member's write on their own account.
 *
 * The session names the account: the request carries no account id, so it
 * cannot name another account. The three fields a member owns are the whole
 * of the profile write; the three a member does not own are declared beside
 * them so a stated value is refused by name rather than dropped in silence.
 *
 * The write states the owned fields whole: an empty string replaces the
 * field with nothing. The same empty string on an unowned field means the
 * field is not stated, and the write leaves it as it is.
 */

2.25.1. full_name

/**
 * @brief The member's full (real) name. A member owns this field. Empty
 * clears it.
 */

2.25.2. job_title

/**
 * @brief Job title / functional role. A member owns this field. Empty
 * clears it.
 */

2.25.3. image_id

/**
 * @brief Profile picture, as the id of an uploaded image. A member owns
 * this field. Empty clears it.
 */

2.25.4. email

/**
 * @brief The sign-in address. An administrator owns this field: a request
 * that states it non-empty is denied with field_not_self_writable, and the
 * field is left as it is.
 */

2.25.5. default_party_id

/**
 * @brief Party used for quick login. An administrator owns this field: a
 * request that states it non-empty is denied with field_not_self_writable,
 * and the field is left as it is.
 */

2.25.6. reports_to_account_id

/**
 * @brief The account this person reports to. An administrator owns this
 * field: a request that states it non-empty is denied with
 * field_not_self_writable, and the field is left as it is. The screen carries
 * a reporting-line change as an ordinary change request, never as a write.
 */

2.25.7. change_reason_code

2.25.8. change_commentary

2.26. update_self_account_response

2.26.1. result

2.26.2. account

/**
 * @brief The account as written, so the panel can show its new version.
 * Stated only when the outcome is ok.
 */

2.27. update_self_account_contact_information_request

/**
 * @brief A member's write on their own contact record.
 *
 * The session names the account and the record is found from it, so the
 * request carries no account id and no record id, and it cannot name another
 * account's record. A member who has no contact record gets one on the first
 * write.
 *
 * The write states the nine fields whole: an empty string replaces the field
 * with nothing. A stated email must be a valid address, and a stated country
 * code must be an ISO 3166-1 alpha-2 code, or the write is refused with the
 * field named.
 */

2.27.1. street_line_1

2.27.2. street_line_2

2.27.3. city

2.27.4. state

2.27.5. country_code

2.27.6. postal_code

2.27.7. phone

2.27.8. email

/**
 * @brief The contact address colleagues use. Empty clears it. This is not
 * the sign-in address, which is the account's email and belongs to an
 * administrator.
 */

2.27.9. web_page

2.27.10. change_reason_code

2.27.11. change_commentary

2.28. update_self_account_contact_information_response

2.28.1. result

2.28.2. account_contact_information

/**
 * @brief The contact record as written, so the panel can show its new
 * version. Stated only when the outcome is ok.
 */

2.29. get_my_account_contact_information_request

/**
 * @brief A member's read of their own contact record.
 *
 * The session names the account, so the request carries no account id and
 * cannot name another account's record. The read needs no permission: it is
 * a self read on the allow-list of Authorised reads. Reading a colleague's
 * record is list_by_account_id, which needs
 * iam::account_contact_informations:read.
 */

2.30. get_my_account_contact_information_response

2.30.1. result

2.30.2. account_contact_information

/**
 * @brief The caller's contact record, or nothing when they have none yet.
 * The first update-self creates it.
 */

2.31. get_my_account_request

/**
 * @brief A member's read of their own account.
 *
 * The session names the account, so the request carries no account id and
 * cannot name another account's. The read needs no permission: it is a self
 * read on the allow-list of Authorised reads, so a member sees their own name,
 * picture and job title without holding iam::accounts:read. Reading a
 * colleague's account is iam.v1.accounts.get, which needs that permission.
 */

2.32. get_my_account_response

2.32.1. result

2.32.2. account

/**
 * @brief The caller's account, or nothing when the session names none.
 */

2.33. get_my_login_info_request

/**
 * @brief A member's read of their own sign-in state.
 *
 * The session names the account, so the request carries no account id and
 * cannot name another account's. The read needs no permission: it is a self
 * read on the allow-list of Authorised reads, so a member sees whether their
 * account is locked and when they last signed in without holding
 * iam::login_info:read. Reading another account's is iam.v1.login_info.get,
 * which needs that permission.
 */

2.34. get_my_login_info_response

2.34.1. result

2.34.2. login_info

/**
 * @brief The caller's sign-in state, or nothing when none is recorded.
 */

2.35. get_my_sessions_request

/**
 * @brief A member's read of the places their own account is signed in.
 *
 * The session names the account, so the request carries no account id and
 * cannot name another account's. The read needs no permission: it is a self
 * read on the allow-list of Authorised reads. The tenant-wide read of open
 * sessions is iam.v1.ops.get_active_sessions, which needs iam::sessions:read.
 */

2.36. get_my_sessions_response

2.36.1. result

2.36.2. sessions

/**
 * @brief The caller's sessions with no end time, newest first.
 */

2.37. my_party

/**
 * @brief One party the caller's account works in, as the member's own screen
 * reads it.
 *
 * The name, the category and the business centre come from IAM's party cache,
 * which mirrors refdata's parties per tenant; the association itself carries
 * the identifier alone. A party the cache has not seen answers with empty
 * strings rather than a half-read row.
 *
 * Declared before the response that carries it, because the generators emit
 * the messages in the order this file states them.
 */

2.37.1. party_id

2.37.2. name

2.37.3. short_code

2.37.4. party_category

2.37.5. business_center_code

2.38. get_my_parties_request

/**
 * @brief A member's read of the parties their own account works in.
 *
 * The session names the account, so the request carries no account id and
 * cannot name another account's list. The read needs no permission: it is a
 * self read on the allow-list of Authorised reads.
 *
 * The subject exists because the association read answers with a party
 * identifier and nothing on the browser's path turns one into a name: the
 * sign-in reply is the only read that names a party today.
 */

2.39. get_my_parties_response

2.39.1. result

2.39.2. default_party_id

/**
 * @brief The party quick sign-in uses, or empty when the account stores none.
 */

2.39.3. parties

2.40. set_reporting_line_request

/**
 * @brief An administrator's write on who one account reports to.
 *
 * The write names one field and nothing else, so a screen that changes the
 * reporting line does not send every other field back, and a field changed
 * elsewhere between the screen's read and this write is not silently
 * overwritten. It needs =iam::accounts:update=, as every administered account
 * write does.
 *
 * An empty =reports_to_account_id= clears the line. =expected_version= is the
 * account version the caller read: when it is stated and the account has moved
 * on since, the write is refused with a conflict rather than applied to a row
 * the caller has not seen. An absent version states no precondition.
 */

2.40.1. account_id

2.40.2. reports_to_account_id

/**
 * @brief The manager's account id, or empty to clear the line.
 */

2.40.3. expected_version

/**
 * @brief The account version the caller read, in decimal, or empty for no
 * precondition.
 *
 * Text rather than a number because empty has to be expressible on this wire,
 * as it is for every other optional value here, and because a fresh account's
 * version is 0: no integer is left over to mean "not stated".
 */

2.40.4. change_reason_code

2.40.5. change_commentary

2.41. set_reporting_line_response

2.41.1. result

2.41.2. account

/**
 * @brief The account as written, so the screen can redraw with its new
 * version. Stated only when the outcome is ok.
 */

2.42. reporting_tree_party

/**
 * @brief One party the reporting shape is drawn under.
 *
 * A person works in a party, and a viewer may work in several, so the shape is
 * grouped by party. The service states which parties are in scope by id; the
 * handler names them from IAM's party cache, which mirrors refdata's parties,
 * so the name and the parent are empty for a party the cache has not seen
 * rather than a half-read row.
 *
 * Declared before the node and the response that carry it, because the
 * generators emit the messages in the order this file states them.
 */

2.42.1. party_id

2.42.2. name

2.42.3. short_code

2.42.4. parent_party_id

/**
 * @brief The parent party's id, or empty when the party has none or its parent
 * is not in the scope the caller may read.
 */

2.43. reporting_tree_node

/**
 * @brief One account in the tenant's reporting shape.
 *
 * The depth counts from a root: a root is 0, its reports are 1, and so on.
 * When the read names a root, that root is 0 in the answer. An account that
 * does not reach any root — a manager who is missing, or a ring the store
 * accepted before the guard existed — is answered with depth -1 and counted in
 * the response's unrooted total.
 *
 * Declared before the response that carries it, because the generators emit
 * the messages in the order this file states them.
 */

2.43.1. account_id

2.43.2. username

2.43.3. full_name

2.43.4. job_title

2.43.5. account_type

/**
 * @brief The account's kind: =user= for a person, otherwise the kind of service
 * account. A reader tells a person from a service by it.
 */

2.43.6. image_id

/**
 * @brief The id of the account's picture, or empty when it has none. The
 * picture is drawn from this identifier, so a reader who may see the tree needs
 * no read of the account to draw the person.
 */

2.43.7. reports_to_account_id

/**
 * @brief The manager's account id, or empty when the account is a root or its
 * manager is outside what the caller may see. The second case is stated by
 * =reports_outside_scope=, so a person who has a manager is never drawn as one
 * who has none.
 */

2.43.8. depth

/**
 * @brief The number of managers between this account and a root, or -1 when it
 * reaches none.
 */

2.43.9. direct_reports

2.43.10. reports_outside_scope

/**
 * @brief Whether the account has a manager the caller may not see. The manager
 * is not named, and the account is drawn as the top of what the caller can see
 * with this marker, not as a person with no manager.
 */

2.43.11. party_ids

/**
 * @brief The ids of the parties in scope that this account works in. Empty when
 * the account is linked to none of them.
 */

2.44. get_reporting_tree_request

/**
 * @brief A reporting shape in one read: the tenant's, or what the caller may see.
 *
 * The scope follows what the caller holds. A caller with =iam::accounts:read=
 * reads the tenant's own accounts, which row-level security bounds. A caller
 * with =iam::organisation:read= and not that code reads the people they may
 * see: those who work in any party their own account works in, and everyone
 * who reports to them directly or indirectly. A node never carries an email or
 * a contact detail. A caller with neither is refused. An empty =root_account_id= asks for the whole
 * scope, ordered by depth; a stated root asks for that account's branch, so a
 * screen can open one part of a large organisation without carrying the rest.
 */

2.44.1. root_account_id

2.45. get_reporting_tree_response

2.45.1. result

2.45.2. nodes

2.45.3. parties

/**
 * @brief The parties in scope, each with the party above it when that party is
 * in scope too. A holding group's parties nest, so a viewer who works in all of
 * them sees the group drawn as the group.
 */

2.45.4. unrooted

/**
 * @brief How many accounts in the tenant reach no root. Stated so the screen
 * can say the shape is broken rather than draw a tree that is missing people.
 */

2.46. attach_account_pictures_request

/**
 * @brief Reconciles the accounts a tenant holds with the pictures they name.
 *
 * Every account that names a picture code and carries no picture gets one:
 * the image is ensured in the tenant and the account is updated. An account
 * that already carries a picture is left alone, so a repeated call writes
 * nothing.
 *
 * A trigger rather than a report: the provisioning step sends it, and an
 * operator may re-run it from a client.
 */

2.47. attach_account_pictures_response

2.47.1. result

2.47.2. image_ids

/**
 * @brief The images attached, one per account that wanted one.
 */

2.47.3. account_ids

/**
 * @brief The accounts the images were attached to.
 */

Emacs 29.3 (Org mode 9.6.15)