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
- 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.
- 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. - 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
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 ofprototype/first-run-journey, merged intomain- 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, asis_registration_defaulton 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.
- 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. - The starting points are data.
ores.iamowns the profile, its parameter schema and the step-kind catalogue, and the readsiam.v1.seed_profiles.list,iam.v1.seed_profiles.get,iam.v1.seed_profile_steps.list-by-seed-profile-idandiam.v1.seed_profile_parameters.list-by-seed-profile-idanswer 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. - One provision request serves every tenant.
iam.v1.ops.provision_tenanttakes 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. - 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_changedevent is not the progress contract: its payload is anentity_change_eventthat no one schema can read for every entity. - A retry resumes a stopped run.
workflow.v1.ops.retry_workflow_instancere-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. - A forced change fires when a profile asks for one. The profile's
force_password_changereaches 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 withpasswordResetRequired: trueat 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. - 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
- Identity and Access Management — the Tenant lifecycle: System bootstrap, Provision, Onboard, Seed profile
- Document type: user_journey
- How do I add a PlantUML diagram?
- Setup journeys