User Journey: New party

Table of Contents

This page documents a user journey: A tenant administrator adds a party and links the accounts that work in it.

A user journey describes what one person is trying to do, before anything is built. It is a design document that outlives any sprint, so it names the screens, the entity fields each screen shows, and the operations and messages each step needs.

1. Goal

"I want a legal entity my team can work as, with the accounts that work in it." The tenant administrator finds the legal entity among those the deployment holds, or adds it by name when it has no LEI, names the party, and chooses the accounts that work in it. The journey is done when the party is active, its essential data is published, and its accounts can sign in to it.

2. Actor and trigger

The tenant administrator: an account of type user that holds the tenant-administrator role, signed in, and acting inside one tenant. The trigger is New party on the Parties page. It also starts from Add another party at the end of this journey. The manual path, "It has no LEI: add it by name", is the same journey with the search skipped. The tenant administrator never chooses the tenant: the session already names it.

This is one of the three journeys that carry server-side state. Provisioning runs on the server and can fail half way. The state lives in ores.workflow, so the person can leave the page and come back, and the shell can drive the same steps. Every other group in this corpus describes a journey that keeps no such state. The order is fixed: this journey needs a running installation, a signed-in tenant administrator and a tenant that is already active.

3. Steps

  1. Find the legal entity. The person searches the legal entities the deployment holds, by name or by LEI. Each result shows the legal name, the country, the LEI and how many parties the hierarchy would create, so a subsidiary is recognisable as one. The person picks one, or chooses It has no LEI: add it by name and types the name instead. Nothing is created yet.
  2. Describe the party. The person sets a short name, taken from the legal name, and ticks the accounts that work in it: this is the account-party association. Accounts that work in the party can sign in to it and act for it, and can switch between parties later. The tenant administrator's own account is ticked by default. There is no data-size question: counterparties are tenant-wide, and the party's bundles come from the tenant's seed profile.
  3. Review. The person reads one summary: legal entity, LEI, short name, the accounts, and the party data. The screen states that nothing is created until the person confirms.
  4. Provisioning. The person confirms, and the system starts the provision workflow for the party. The party stage is one request and its run is one step kind, so the rail lists the profile's provision_party step, which publishes the party's bundles, activates the party and marks its onboarding complete, and the run joins the caller to the party. Each line reads pending, running, done or failed. This is the step that carries the state. The person can leave the page and come back. A failed step stops the instance, the party stays inactive, and a retry resumes from the failed step; the completed steps are kept.
  5. Next steps. The party is active. The page offers three exits: switch to the new party and work in it now, set up its books, or add another party. The person can also just go back; the Parties page lists the new party as active. Where the deployment accepts self-registration, the page may also nominate this party as the one a new account joins; the tenant's first sign-in nominates it, and this is where a second party takes it over.

The rail is flat: a person sees five steps. Steps that change server state are final, so there is no Back past them.

4. Screens and wireframes

The same journey page as the tenant journeys: a flat step rail on the left and one step at a time. The party header, the short name and the LEI, appears on every step after the legal entity is chosen.

wireframe_new_party.png

Figure 1: New party: a flat step rail on the left, the legal-entity search results, and one step at a time.

5. Prototype

Accepted by the user on 2026-09-22. The prototype is merged into main and kept there as the record; the accepted commit names the state. The built journey keeps its five steps, its two ways of naming a party and its three exits; what it does not carry is the accounts picker, which the prototype showed and nothing writes.

Accepted commit
97d63a01f2, the tip of prototype/new-party-journey, merged into main
Source
doc/prototypes/setup/new-party/index.html
Open
/OreStudio/doc/prototypes/setup/new-party/ once the site is built, or the file directly
Design record
Task: Prototype the new party journey

The party journey was the first built on the shared journey page, and it proved the step library: the tenant journey's steps and the party journey's steps come from the same place. It also settled two things. Counterparties are tenant-wide, so the Qt wizard's dataset-size question is gone. And the accounts that work in the party are chosen here, in the describe step, not in a later wizard.

6. Entities composed

Entity What it contributes Model
party Short name, legal name, status and type of the party being created ores.refdata.party
party_identifier The LEI of the legal entity, under the LEI scheme ores.refdata.party_identifier
party_id_scheme Names the identifier scheme the LEI belongs to ores.refdata.party_id_scheme
party_status The party moves to active at the activate step ores.refdata.party_status
party_type The classification the create step sets ores.refdata.party_type
account The accounts the picker offers, and the one that runs the journey ores.iam.account
account_party The accounts that work in the party — the association this journey writes ores.iam.account_party
counterparty The tenant-wide counterparties the tenant's seed profile already published ores.refdata.counterparty
GLEIF legal entity Legal name, country, LEI and parent, read from the register ores.dq.lei_entity and ores.dq.lei_relationship

No password or secret appears on this screen at all. The person chooses which accounts work in the party; the accounts themselves are created elsewhere.

7. Operations and messages

Step Operation Subject Status
Find the legal entity Search the legal entities the deployment holds, by name or LEI dq.v1.ops.search_lei_entities exists
Describe the party List the accounts that may work in the party iam.v1.accounts.list exists
Describe the party Read the existing account-party associations iam.v1.account_parties.list exists
Review Add the party and start its run iam.v1.ops.provision_party exists
Review Create the party row, under the tenant's own party refdata.v1.parties.put exists
Provisioning Publish the party's essential data iam.v1.ops.provision_party exists
Provisioning Record the legal entity it was built from refdata.v1.party_identifiers.put exists
Provisioning Activate the party refdata.v1.parties.put exists
Provisioning Mark the party provisioning complete iam.v1.ops.provision_party exists
Provisioning Join the caller to the party iam.v1.ops.provision_party exists
Provisioning Retry from the failed step workflow.v1.ops.retry_workflow_instance exists
Next steps Switch to the new party iam.v1.ops.switch_party exists
Next steps Read the party's books refdata.v1.books.list exists

The two iam.v1.account_parties subjects are declared in ores.iam.account_party, and iam.v1.account_parties.put_many is what writes the accounts that work in a party; the run the provision request starts joins the caller on its own. iam.v1.ops.switch_party is declared in ores.iam.account_messages, and iam.v1.accounts.list is generated from ores.iam.account. The refdata.v1.parties and refdata.v1.books subjects are generated from their entity models. All of them exist in the generated web protocol. dq.v1.ops.search_lei_entities matches a name or an LEI over the legal entities the deployment holds and states, per match, how many parties the hierarchy would create; the BFF adds a route to it and the wire client parses the reply. workflow.v1.ops.get_workflow_steps and workflow.v1.ops.retry_workflow_instance are not in the generated web protocol: the generator emits no workflow package for the browser, so the BFF adds a route for each and the wire client parses the reply.

The party stage is one request, iam.v1.ops.provision_party. It takes a party, by its identifier or its exact full name, the starting point whose party stage runs, and the legal entity the party was built from; it resolves the party in the caller's own tenant, and answers at once with the id of a run that publishes the party's bundles, records that entity as the party's LEI, activates the party, marks its onboarding complete and joins the caller to it. The starting point states which bundles a party is published from, as the arguments of its provision_party step, and a profile that orders no party step is refused. A reference that matches more than one party is refused as well, because a run acts on one party.

An empty starting point means the deployment's own party stage, which is the first profile that orders one. A tenant administrator cannot name a profile: the profiles are the system tenant's rows and a tenant reads only its own, so the service that holds both is the one that chooses. The shell's provision party therefore names none by default and the browser names none at all.

The LEI travels with the run rather than being written by it. A party identifier is stamped with the party its writing session acts in, and the person who adds a party works in another one, so the run is the only client that can record it: it writes it with a client scoped to the party it is provisioning.

Every subject in the table exists on the wire, and the shell's provision party sends iam.v1.ops.provision_party and follows the same progress read. The browser reaches the search and the request that starts a party's run through the BFF, and POST /api/provision-party is that request: it adds the party row, places it under the tenant's own party, and starts the run.

8. What is missing

  1. The chosen accounts are not written. The describe step would pick the accounts that work in the party, and the screen does not offer the picker yet, because nothing writes them: the run joins the caller alone. Writing the other chosen associations is iam.v1.account_parties.put_many, and the request that provisions a party takes no account list, so no step of the party's own run writes them. A picker whose choices went nowhere would be worse than no picker.
  2. No scripted end-to-end proof. No scripted run proves this browser's path the way projects/ores.web/scripts/verify-login.ts proves the sign-in, so the proof of the journey stays manual.
  3. No completion signal the browser can read. The engine publishes ores.workflow.workflow_instance_changed on every state change, but the payload is an entity_change_event that carries entity_ids, and the schema the browser decodes reads alpha2_codes with every field defaulted, so the browser receives an empty identifier list. The reads workflow.v1.ops.get_workflow_steps and workflow.v1.ops.retry_workflow_instance exist and are what a page follows a run with. That mismatch is owned by its capture.
  4. A party hangs under the tenant's own party, and the person does not choose where. A party hangs under another and exactly one of a tenant's parties sits at the top, so the row whose parent is unset is what a new party is placed under; a tenant that has none gets the party it has just added as its root. Choosing the parent, or moving a party afterwards, is the Draw the reporting line journey and not this one.

The rest of the journey is in place, and the list below is the record of what each part turned out to be.

  1. The legal-entity search reads the deployment's own data. dq.v1.ops.search_lei_entities matches a name or an LEI over the legal entities the deployment holds, and states, per match, how many parties the hierarchy would create. The deployment's records are the ones a tenant is built from; no live proxy to the public register is needed. The browser reaches the search through a BFF route, and the party named by hand is the same journey with the search skipped.
  2. No journey record, and none is added. A journey is a definition, not a server-side object. Its progress state is a workflow instance in ores.workflow, with its entities, services and subjects, and the run is followed by the id the request answers with. Only the server-side workflow resumes, so the human steps around it do not survive a reload. The retired iam.v1.journeys.get-active candidate is dropped.
  3. The provision-party request is one stage. iam.v1.ops.provision_party takes a party, by its identifier or its exact full name, a starting point and the entity the party was built from, resolves the party in the caller's tenant, and returns a workflow instance id at once. The run publishes the bundles the starting point orders, records the entity as the party's LEI, activates the party, marks its onboarding complete and joins the administrator who asked to it, so the request carries the whole active, onboard and publish stage. The LEI is written last, because an identifier's insert bumps the version of the party it belongs to and a party saved before it would then be refused as one that moved on.
  4. The party's bundles are the starting point's. The party_essentials bundle is one of the bundles a provision_party step may order, as the step's own arguments, and every starting point that orders the kind orders it. A party's data is therefore the profile's, and the step the tenant run carries is the one the party stage runs. There is no separate publish request for a party on its own. The generic report set is the party_reporting bundle. A profile that designs each party's reports leaves it out and publishes the party's own report definitions through the party's bundle.
  5. A retry resumes a stopped run. workflow.v1.ops.retry_workflow_instance resumes a run that stopped on its failed step: it re-dispatches that step under its own identity, clears the run's error, and leaves every completed step and its result alone. The engine's recover_in_progress() stays for runs that were in progress when a service restarted.

9. Related journeys

10. Related knowledge

11. See also

Emacs 29.3 (Org mode 9.6.15)