Audience: consultant. Prerequisite: 00 — Start here.
This is the spine. Every other page in the guide is a zoom-in on one stage of it. Follow this page top to bottom to run an engagement start to finish.
The states an engagement moves through
The stages below are what you do. This is what the engagement is while you do it — eleven states, and the platform will not let you skip the two that are guarded.
stateDiagram-v2
[*] --> lead
lead --> proposal
proposal --> contract_sent : ⚠ GUARDED — needs a generated contract
contract_sent --> signed : ⚠ GUARDED — needs a signed PDF on file
signed --> active
active --> paused
paused --> active : resume
active --> complete
complete --> archived : a one-off engagement ends here
complete --> handoff_initiated : becoming ongoing support
handoff_initiated --> acknowledged
acknowledged --> support_active
support_active --> archived
archived --> [*]
⚠️ Both guards fail closed. The flags they read default to false, so an engagement with
no contract cannot reach contract_sent, and one the CLIENT has not signed cannot
reach signed — no matter what you know to be true offline. The refusal names the reason:
“Cannot move to ‘signed’ without a signed contract on file.”
⚙️ “Signed” here means the CLIENT signed — our counter-signature is not required to pass
this guard. A contract is signed once the client returns it and countersigned once we
add our signature; both satisfy the gate, and countersigned satisfies it because it
contains the client signature, not despite it. ⚙️ Every screen that counts signed contracts
reads the same set, so a fully executed agreement counts as signed everywhere — a counter-signature
adds to a contract, it never takes it out of the count.
⚙️ paused is the only state you can come back from. Everything else runs forward, and
archived is the end. The handoff tail (handoff_initiated → acknowledged → support_active)
is for work that becomes an ongoing support arrangement; a one-off engagement goes
complete → archived.
⚠️ archived means ABANDONED, and an abandoned engagement never deploys. It is the one
state that sits after signed in the lifecycle and is nonetheless refused, so “past the
gate” is not the test — deploy eligibility is an explicit SET (canDeployFrom), not a
threshold — archived sorts last in the lifecycle, so an ordering test would read an
abandoned engagement as further along than every live one. An archived engagement also cannot be reopened —
it has no outgoing transitions — so the refusal tells you to deploy from the engagement
that replaced it, rather than to advance a lifecycle that cannot move.
⚙️ Who may move an engagement depends on the move. The selling steps — lead, proposal, contract
sent, signed — need the modify_scope capability; creating an engagement and the delivery steps —
active, paused, complete and the handoff tail — need build_apps. Both belong to the admin and build
roles. Archiving an engagement that has no app yet is the same build_apps housekeeping, but
archiving or deleting one whose app is live takes that app offline, so it is kept to the admin role.
Archiving or deleting also closes the client’s portal: their signed-in sessions stop working at once,
and their onboarding link, any unused sign-in link and any unopened app link are revoked.
A seat is only offered the moves it may make, and a billing seat moves none — it reads every engagement.
The contracts behind the selling steps follow the same rule: generating, sending and recording a
signed copy need modify_scope too.
Signed to live — the screens, in order
The stages below have the detail. This is the route through them: which screen, the one control you press, and what changes when you do. It is the page to follow on your second engagement without re-reading the prose.
⚙️ This describes a SEQUENCE, which ages faster than structure. The states, the guards and the routes it names are anchored to the code that owns them, so a renamed route or a deleted guard turns this page red. A step reordered in the UI will not. Believe the screens over this page, and report the difference.
⚙️ The diagram is the route; the table under it is the detail. Nodes are deliberately terse — a step whose label needs five lines is a table row, not a box.
flowchart TD
S1["<b>1</b> · Clients<br/><i>New client</i>"]
S2["<b>2</b> · Delivery<br/><i>scope items</i>"]
S3["<b>3</b> · Contracts<br/><i>+ New contract</i>"]
S4["<b>4</b> · Contracts<br/><i>upload signed PDF</i>"]
GATE{{"🚧 reaches <b>signed</b><br/>nothing deploys before this"}}
S5["<b>5</b> · Build<br/><i>schema → pages → permissions</i>"]
S6["<b>6</b> · Deploy<br/><i>Deploy</i>"]
S8["<b>8</b> · Time · Invoices<br/><i>log time, raise invoice</i>"]
S7["<b>7</b> · Portal Users<br/><i>Add client user</i> ⚠️ real email"]
S1 --> S2 --> S3 --> S4 --> GATE --> S5 --> S6 --> S8
S2 -.->|"any time after step 1"| S7
| # | Screen | The control | What changes |
|---|---|---|---|
| 1 | Firm ▸ Clients | New client | client, engagement and portal invite in one wizard |
| 2 | Engagement ▸ Delivery | add scope items | they feed the contract, progress reports and change orders |
| 3 | Engagement ▸ Contracts | + New contract | ⚠️ generation is refused while a required value is unset |
| 4 | Engagement ▸ Contracts | upload the signed PDF | 🚧 unlocks signed — the deploy gate |
⚙️ A signed copy can only be uploaded while the contract is still awaiting signature
(generated or sent). Once it is signed or counter-signed the upload refuses, because replacing
the PDF of record on an executed agreement would walk it backwards and strand the
counter-signature against a document that no longer exists.
| 5 | Build ▸ Schema · Pages · Permissions | authoring | ⚠️ a role with no read grant sees an empty app — and the deploy refuses until you grant it or acknowledge that nobody will hold that role |
| 6 | Build ▸ Deploy — Configure | Deploy | their staff can use it |
| 7 | Engagement ▸ Portal Users | Add client user | ⚠️ a real email goes to a real person |
| 8 | Engagement ▸ Time, then Invoices | log time, raise invoice | a draft is not yet a claim on the client |
★ Step 4 is the one that surprises people. Everything from step 5 is authoring you can do whenever you like — but the deploy in step 6 is blocked until the client’s signed contract is and no amount of knowing the deal is agreed will move it.
⚙️ Steps 5 and 7 are independent. You can invite the portal user long before the app is built; the portal shows them progress, contracts and invoices without a deployed app.
Stage 0 — The firm exists
Before any client work, your firm needs to be set up once. Firm scope:
| Do this | Where |
|---|---|
| Set your firm profile | Firm ▸ Firm Profile (/operator) |
| Add your logo, colours, invoice identity | Firm ▸ Branding (/operator-branding) |
| Set standard billing rates | Firm ▸ Rates (/rates) |
| Configure how you get paid | Firm ▸ Payment Settings (/payment-config) |
| Invite your team, give them roles | Firm ▸ Access & Security ▸ Operators & Roles (/workspace/operators) |
| Optionally set a monthly cost budget | Firm ▸ Billing & Costs (/billing) |
Branding matters more than it looks: it flows into invoices, the client portal, and the delivered app’s login screen. Set it once, properly.
Stage 1 — Create the client and the engagement
- Firm ▸ Clients (
/clients) → New client. This creates the client company. - Inside the client, create an engagement — one discrete piece of work. A client can have many engagements; each gets its own app, its own data, its own invoices, and its own portal access.
An engagement is the unit of everything. When in doubt about where something belongs, it belongs to the engagement.
Stage 2 — Discovery and scope (OPERATE mode)
Engagement ▸ Operate is the commercial half of the relationship.
| Do this | Where |
|---|---|
| Record what you are delivering | Delivery (/engagements/:id/delivery) — the scope items |
| Track delivery progress | Delivery (/engagements/:id/delivery) |
| Put the agreement in writing | Contracts (/engagements/:id/contracts) |
| Add your team to the engagement | Team (/engagements/:id/team) |
Scope items are the contract’s spine. They flow into progress reports, into change orders when scope moves, and into invoicing. Getting them right early makes every later stage honest; skipping them makes the commercial surfaces empty.
⚙️ Editing scope and milestones needs the modify_scope capability — the admin and build
roles. A billing seat, or a seat whose role is narrowed on this engagement, sees the scope and the
milestones read-only, and the server refuses the write whichever screen it comes from.
Stage 3 — Build the app (BUILD mode)
This is the craft. Full detail in 02 — Build the app and 03 — Behavior. Opening an engagement’s app for the first time sets the app up, which needs a seat that builds apps (the admin and build roles); any other seat is told so. The order that works:
- Schema (
/engagements/:id/build/schema) — what things exist, and their fields. - Pages (
/engagements/:id/build/pages) — the screens, bound to that schema. - Appearance (
/engagements/:id/build/appearance) — the client’s look. - Permissions (
/engagements/:id/build/permissions) — the app’s roles (+ New role) and who may see and do what. ⚠️ Not Firm ▸ Roles: that is your own team’s operator roles. - Behavior (
/engagements/:id/build/behavior) — rules, workflows, approvals. - Connections, Import a Spreadsheet and Scheduled Imports — real data in.
- Anomaly Watchers, Surfacing Rules, Escalation Chains — the app noticing things on its own.
Do them roughly in that order. Schema first is not a style preference: pages bind to entities, rules target entities, and permissions are granted per entity, so building screens before the data shape settles means redoing them.
Stage 4 — Deploy (BUILD ▸ Deploy — Configure, then RUN)
Configuration is authored as a draft, then published, then deployed. Those are three different things and conflating them is the most common confusion:
- Draft — your working copy. Only you see it.
- Published — the config is frozen as a version. Still not live.
- Deployed — a published version is running in an environment.
Set the target up at Build ▸ Deploy — Configure
(/engagements/:id/build/deploy), then deploy and watch it from
Run ▸ Deployments (/engagements/:id/run/deployments).
Full detail, including environments and rollback, in 05 — Deploy and run.
Data survives config deploys. Redeploying configuration does not wipe the app’s records. See the data-safety section of 05 for the one operation that is destructive and how it is guarded.
Stage 5 — Give the client access (OPERATE + portal)
| Do this | Where |
|---|---|
| Invite the client’s stakeholders to the portal | Engagement ▸ Portal Users (/engagements/:id/portal-users) |
| Onboard them | Engagement ▸ Operate, and the portal’s own onboarding |
Portal users are client-side people, not operators from your firm. The two directories are deliberately separate; a picker that offers client users will never offer your operators, and vice versa. Detail in 07 — Client collaboration.
Stage 6 — Run it (RUN mode)
Once deployed, Run is where you operate the app on the client’s behalf:
| Watch | Where |
|---|---|
| The app’s real records | App Data (/engagements/:id/run/app-data) |
| What the app flagged for a human | Attention (/engagements/:id/run/attention) |
| Is it up and healthy | App Health (/engagements/:id/run/deployments/health) |
| What ran, and what it did | Workflow Runs (/engagements/:id/run/workflow-runs) |
| What it noticed | Anomaly Events (/engagements/:id/run/anomaly-events) |
| Client-raised problems | Support (/engagements/:id/run/support) |
| Who changed what | App Audit (/engagements/:id/run/audit) |
Stage 7 — Get paid (OPERATE)
| Do this | Where |
|---|---|
| Log time | Engagement ▸ Time (/engagements/:id/time) |
| Raise an invoice | Engagement ▸ Invoices (/engagements/:id/invoices) |
| Handle a disputed item | Engagement ▸ Disputes (/engagements/:id/disputes) |
| Bill scope that grew | Engagement ▸ Change Orders (/engagements/:id/change-orders) |
Detail in 06 — Commercials.
Stage 8 — Report and hand off
| Do this | Where |
|---|---|
| Send the client a progress report | Engagement ▸ Progress Reports (/engagements/:id/progress-reports) |
| Package the engagement for handover | Engagement ▸ Handoff Packets (/handoff?engagement=:id) |
Handoff produces the artefact the client keeps: what was built, how it works, and what they now own.
The shape of a first engagement
If you are walking this for the first time, this is the shortest honest path that touches every stage:
- Firm ▸ Clients → new client → new engagement.
- Operate ▸ Delivery → add two or three scope items.
- Build ▸ Schema → one entity with a handful of fields.
- Build ▸ Pages → one page listing that entity, one for creating a record.
- Build ▸ Appearance → set the client’s colours.
- Build ▸ Permissions → + New role for one non-admin role, then grant it read on your entity.
- Build ▸ Behavior → one rule that notifies that role when a record is created.
- Build ▸ Deploy — Configure → set the target. Deploy.
- Run ▸ App Data → create a record. Run ▸ Attention / the bell → see the notification arrive.
- Operate ▸ Time → log an hour; Operate ▸ Invoices → raise a draft invoice.
- Engagement ▸ Portal Users → invite yourself as a client user; open the portal.
- Operate ▸ Progress Reports → generate a progress report.
That is a complete engagement in miniature, and it exercises every subsystem the rest of this guide documents.