User Journey: First run

Table of Contents

This page documents a user journey: An empty installation is brought to life: the system administrator, the first tenant and the first sign-in.

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

"Get me from an empty installation to a system I can work in." The person creates the system administrator, then the first tenant with its parties and its administrator, then signs that administrator in. The journey is done when the installation leaves bootstrap mode and the last screen reads Ready.

2. Actor and trigger

Two actors share one path. The first steps are open to anyone who reaches the installation: while system bootstrap is not complete, the system is in bootstrap mode, nobody can sign in, and the Setup page is the only page. From the first sign-in onward the actor is the tenant administrator: an account of type user, signed in, inside the first tenant. The trigger is a browser pointed at a new installation. The journey ends at Ready, when the installation stops being in bootstrap mode.

This is one of the three journeys that carry server-side state. The tenant work runs on the server, it takes minutes, and it can fail half way. The state lives in ores.workflow, so the person can close 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: first run is the only journey that can happen on an empty database.

3. Steps

  1. Welcome. The system shows the splash, "Welcome to ORE Studio", one sentence, and three unnumbered stage cards: create the administrator, create the first tenant, sign in. The person chooses Get started. No server call happens here.
  2. Create the administrator. The person enters a username (default super_admin), an email and a password. The password field applies the shared policy. The system runs system bootstrap: it creates the system administrator and nothing else. No tenant is created at this step, and nobody can sign in yet.
  3. Choose a starting point. The new tenant steps run inline, as rail steps 3 to 7. The person picks a seed profile: Empty operational, GLEIF entity or ACME demo. Each card shows a tagline, three bullets and its counts. The ACME card also shows the ACME logo. Nothing is created yet.
  4. Describe the tenant. For Empty operational the person searches the legal entities the deployment holds for the tenant's root — or leaves it out, when there is no entity yet — chooses the counterparty set, and sets the administrator's password. For GLEIF entity the person searches the legal entities the deployment holds and chooses the one the tenant is built around; the card states how many parties that entity's hierarchy would create. For ACME demo the profile fills in the code, name, hostname and administrator username and email; the details show as a summary behind Change settings, and the tenant administrator reuses the system administrator's password. No starting point asks its administrator to change that password at first sign-in: the choice is the profile's, and a profile that wants the change states it in its row.
  5. Review. The person reads one summary: starting point, tenant name and code, administrator, and the profile's parameters. The screen states how many steps the profile runs. Nothing is created until the person confirms.
  6. Provisioning. The person confirms, and the system starts the provision workflow for the first tenant. The rail lists one line per workflow step, and each line reads pending, running, done or failed. This is the step that carries the state. The person can leave the page. A failed step stops the instance, the tenant stays bootstrapping, and a retry resumes from the failed step; the completed steps are kept.
  7. Registration. The installation can now accept registrations. The system administrator decides whether it does, and confirms the first tenant as the tenant a registration lands in. Nothing is created here, and a refusal still leaves a working installation: it only means accounts come from an administrator. The door reports both answers from then on.
  8. Hand off. The tenant is ready. The person chooses Continue as tenant admin, which signs out, signs in as the tenant administrator and opens their first sign-in, or Hand off to someone else, which signs out and shows the username to pass on. The web keeps the administrator's password in memory only until this point; it is never written to storage.
  9. First sign-in. The tenant administrator sets a password of their own when the profile asks for one, which neither starting point does today, and chooses the party to start in when they work in more than one. Where registration is on they also nominate the party a new account joins and the role it receives, beside the party they choose to work as. Neither nomination is required: an installation that accepts registrations without them creates accounts that wait for an administrator. This is onboard: a person's first use of a tenant that already exists.
  10. Ready. The system confirms the installation. The person goes home, or to the Tenants page to create another tenant.

One flat step rail. The new tenant steps are written once, as a library of step definitions, and first run expands them inline. The person sees the Welcome screen first, and then one rail of nine steps, never a journey inside a journey. Steps that change server state are final: there is no Back past them.

4. Screens and wireframes

One page per journey, with a flat step rail on the left and one step at a time. Welcome is the only screen without the rail. The rail is the whole journey, so the page needs no separate progress display.

wireframe_first_run.png

Figure 1: First run: one flat step rail on the left, the current step on the right.

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.

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

The prototype settled three things. Journeys are data: one page renders an ordered list of step definitions, so first run reuses the new tenant steps rather than copying them. Every deployment is multi-tenant, so first run never asks about tenancy. And ACME asks for nothing, in first run and in the new tenant journey alike.

6. Entities composed

Entity What it contributes Model
account The system administrator, and the tenant administrator the profile creates: username, email, account type, password (write only) ores.iam.account
tenant Code, name, hostname, type and status of the first tenant ores.iam.tenant
tenant_type The classification the provision step sets on the tenant ores.iam.tenant_type
tenant_status The tenant moves from bootstrapping to active ores.iam.tenant_status
account_party The account-party association the first sign-in chooses between ores.iam.account_party
Seed profile The ordered workflow steps the profile selects, and its parameters ores.iam.seed_profile
Registration defaults The switch, the default tenant, the default party and the default role the journey sets, so the door can answer Sign up Registration and Onboarding Defaults

Three values must never reach this screen: password_hash, password_salt and any cleartext password after it is sent. The password fields write; no read returns a hash.

7. Operations and messages

Step Operation Subject Status
Welcome Read whether the system is in bootstrap mode iam.v1.ops.bootstrap_status exists
Create the administrator Create the system administrator iam.v1.ops.create_initial_admin exists
Choose a starting point List the seed profiles, their steps and their parameters iam.v1.seed_profiles.list exists
Describe the tenant Provision a tenant from a seed profile, the first tenant included iam.v1.ops.provision_tenant exists
Provisioning Follow the workflow instance's progress workflow.v1.ops.get_workflow_steps exists
Provisioning Retry from the failed step workflow.v1.ops.retry_workflow_instance exists
Hand off Sign out iam.v1.ops.logout exists
Hand off Sign in as the tenant administrator iam.v1.ops.login exists
Hand off Re-ask the deployment when the administrator was created none exists
First sign-in Set a new password iam.v1.ops.change_password exists
First sign-in Choose the party to start in iam.v1.ops.select_party exists
Registration Read the policy the door reports: the switch and the defaults iam.v1.ops.registration_policy exists
Registration Set whether the deployment accepts self-registration a settings write missing
Registration Confirm the first tenant as the tenant a registration lands in iam.v1.tenants.put exists
First sign-in Nominate the party a new account joins refdata.v1.parties.put exists
First sign-in Nominate the role a new account receives iam.v1.roles.put exists

iam.v1.ops.bootstrap_status and iam.v1.ops.create_initial_admin are declared in ores.iam.bootstrap_messages and need no session, because the system is in bootstrap mode. iam.v1.ops.bootstrap_status answers whether the deployment still needs an administrator and whether it has a tenant of its own: it is set up when it has both. The account and tenant subjects need a session. The starting point is answered by the three reads iam.v1.seed_profiles.list, iam.v1.seed_profile_steps.list-by-seed-profile-id and iam.v1.seed_profile_parameters.list-by-seed-profile-id, which the browser composes into one card per profile. 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 one verb that provisions a tenant is iam.v1.ops.provision_tenant. It takes the profile code, the tenant fields, the administrator fields and the profile's parameter values, creates the tenant and its administrator, and answers at once with the id of the run that executes the steps the profile orders. It serves every tenant, the first one included.

8. What is missing

One thing the journey reaches for is not in place:

  • The registration step has nothing to write to yet. The read that reports the switch and the defaults exists — iam.v1.ops.registration_policy — but no interface sets the switch outside SQL, so the step and the two nominations are design-only until the settings write and the screen land. The defaults the nominations point at are settable now, as is_registration_default on the tenant, the party and the role.

Nothing else is missing from the journey's own path: the starting point asks the deployment for the tenant's root legal entity rather than taking a code nobody can check, both other Setup journeys have rails of their own, and projects/ores.web/scripts/verify-first-run.ts walks this journey's path on a fresh database and asserts every answer.

Everything else the journey reaches for exists, and the list below is the record of what each part turned out to be.

  1. The journey's state is a workflow instance. A journey is a definition and not a server-side object, so no journey entity was added anywhere. The run's state is a workflow instance in ores.workflow, and the page follows it through the progress read. A browser that reloads half way through comes back to the setup rail, because the gate answers the deployment and not the tab: the route table keeps the browser on the journey while the deployment still needs an administrator or still has no tenant of its own.
  2. The starting points are data. ores.iam owns the profile, its parameter schema and the step-kind catalogue, and the reads iam.v1.seed_profiles.list, iam.v1.seed_profiles.get, iam.v1.seed_profile_steps.list-by-seed-profile-id and iam.v1.seed_profile_parameters.list-by-seed-profile-id answer them. Operational, GLEIF entity and ACME demo are rows, so a third profile is a row and a new step kind is code. The page builds each card and its form from the rows and holds no profile of its own.
  3. One provision request serves every tenant. iam.v1.ops.provision_tenant takes the profile code, the tenant fields, the administrator fields and the profile's parameter values, and returns the instance id of the run it starts, the first tenant included. The tenant and its administrator exist by the time it answers, and the steps the starting point orders run afterwards.
  4. Progress is read, not pushed. The page asks the progress read again while the run is open and renders the rail from the answer: the run's state, the step it is executing, and one line per step. The engine's workflow_instance_changed event is not the progress contract: its payload is an entity_change_event that no one schema can read for every entity.
  5. A retry resumes a stopped run. workflow.v1.ops.retry_workflow_instance re-dispatches the step a run stopped on and leaves the completed steps and their results alone. Discard stays a separate administrator action, iam.v1.ops.reset_tenant, because the contract keeps completed work.
  6. A forced change fires when a profile asks for one. The profile's force_password_change reaches the account the provisioner creates, and the login answer carries the account record's flag, so a profile that asks for the change is answered with passwordResetRequired: true at first sign-in and its administrator sets a password only they know. Neither Operational nor ACME demo asks. The profile's other hand-over choice, reusing the creating administrator's password, is read for the ACME demo card, and the browser sends the creating administrator's password in the request's administrator field, because a server cannot read the password its caller signed in with.
  7. The policy is read, not copied. The validator states its rules once as a record and enforces that record, and a read answers with it before anybody has signed in. Every password field in the journey is built from that answer, so a deployment that tightens a rule tightens the screen.

One thing the first proof found has since been corrected: the Operational card's LEI import was said to have no staged GLEIF data to read, and it has. The code that failed was a mistyped LEI, and the publication inserts 668 parties for a correct one against the same tenant. The journey behaved as designed either way – the rail showed the failed step and the retry was offered.

9. Related journeys

  • New tenant — the same steps run on their own there, for every tenant after the first
  • New party — add another legal entity once the installation is up
  • Sign in — the tenant administrator's later sign-ins, and where a forced change lands
  • Sign up — the door this journey opens or closes: the deployment's switch, the tenant a registration lands in, and the party and role a new account receives
  • Keep my details current — the profile the tenant administrator completes after their first sign-in
  • Tune the tenant — change the first tenant's settings once it is active

10. Related knowledge

11. See also

Emacs 29.3 (Org mode 9.6.15)