Verdan Onboarding Fix Plan
A new GC admin should reach a live jobsite in one sitting of about ten minutes and never be asked the same thing twice. Today five separate setup surfaces fire on the same person, read different "done" signals, and leave dead ends. The fix is autosaved drafting, one server-derived readiness checkpoint, one follow-up list.
Findings behind this plan are filed as VER-8526 with 13 sub-issues, each cited to file and line on main.
Who onboards, and what "done" means to them
Three people arrive in the first week. Only one of them should ever see a setup wizard.
| Person | How they arrive | Wants in the first session | Must never happen |
|---|---|---|---|
| Sarah GC owner or safety director (admin) | Activation email after HQ provisioning, or Stripe checkout when self-serve is on | A jobsite that is live: project, super assigned, QR poster printed | Being asked for her company name, first project or team invite twice |
| Mike Superintendent | Invite email from Sarah during setup | Log in on his phone, see his project, approve the first foreman | Landing in Sarah's wizard, or on a page telling him to create a project |
| A sub's foreman | Project invite, or the QR poster on day one | Sign in his crew | Any setup screen at all |
The first worker sign-in on the QR poster. Everything before it is setup cost; everything after it is the product. The jobsite story canon puts this at pre-day-1: the GC sets the project up, the super approves the foreman, the crew self-signs on the QR. Onboarding is done when that chain can start, not when a checklist reads 9 of 9.
That gives one definition of done for the whole tenant: company profile filled, one project created with a super on it, and the QR poster generated. Subs, insurance requirements, templates and orientation are follow-up work the product should nudge, never gate.
What Sarah hits today
Sarah's first session, as main ships it, asks her to set up the company four times and never tells her when she is finished.
flowchart TD A[Activation email] --> B["/activate then /login"] B --> C["/projects: Getting Started card
4 steps, 'Your account is set up'"] C --> D["Top-bar pill unlocks
'0 of 4'"] C --> E["Guard redirects to
9-step wizard"] E --> F["Wizard inside dashboard shell
pill still visible"] F --> G["Playbook step links out
to /admin/users"] G --> E F --> H["Complete: redirect to
8-step project setup checklist"] H --> I["/admin/getting-started
6-step guide"]
The card and the wizard fire on the same landing. Leaving the wizard by its own links can bounce her back in. Finishing it drops her into a second checklist, with a third guide page one click away.
Screen by screen
- Payment or activation. Self-serve checkout ends on a page whose only link is the homepage. HQ-provisioned tenants get an activation link that ends at login. Either way Sarah finds her own way in. VER-8543
- First landing on /projects. A Getting Started card says "Your account is set up" and lists four tasks. Seeing it unlocks a "0 of 4" pill in the top bar. In the same second the auth guard reads the tenant's onboarding row, sees "in progress", and redirects her to the wizard. VER-8535 VER-8534
- The wizard. Nine steps: account, company profile, playbook, first project, team, billing, compliance, mobile, review. It renders inside the dashboard shell, so the sidebar and the pill surround it. The billing step asks a self-serve tenant to pay again. The playbook step's "Do it now" links go to admin pages; following one can send her back to step one on the next page load. VER-8536 VER-8537
- After Review and Launch. She is redirected into an 8-step project setup checklist for the project she just created. Two of its required steps, subcontractors and compliance requirements, repeat what the wizard asked. VER-8537
- Back on the dashboard. The card still says "Create your first project" because it never renders ticks. The pill counts from a different endpoint whose invite check looks at the users table, so people she invited do not count until they accept. The guide page's Mark as Complete forgets on reload. VER-8538 VER-8539 VER-5473
- Her super, Mike. His invite email links to
/invite/{id}, a page that does not exist. If he signs out mid-wizard he is sent to /signup, not /login. VER-8540 VER-8541
None of these is a hard bug on its own. Together they are why the experience reads as broken.
The target flow: draft, then finalize
Product ruling, 2026-09-23: jobsite creation splits into drafting and finalization. Drafting saves itself and asks for nothing. Finalization is an operational-readiness checkpoint that verifies the jobsite can actually run before it goes live and before billing starts.
flowchart LR P["Activation or checkout
lands in the workspace"] --> C["Company profile
autosaved, no gate"] C --> D["Jobsite draft
autosaved, leave and return"] D --> R["Readiness check
blockers vs optional"] R -- "blocker missing" --> D R -- "all blockers clear" --> A["Activate
jobsite live, billing starts"] A --> S["First sign-in on the QR"]
One loop, not a wizard. The draft is a real project row in draft status from the first keystroke. The readiness check is computed on the server from what exists, and the same list drives the activate button and the follow-up card.
Drafting
- Everything autosaves. Company profile and jobsite fields persist on change, with a saved indicator, and no field is required to leave the page.
- No billing at draft time. Today creating a project is gated by the billing check, so a new GC cannot save a draft without a paid subscription (VER-8568). The gate moves to activation.
- No super required yet. The "who runs this site" field is present and optional during drafting. It becomes a blocker at finalization.
- Return anywhere. Reopening the workspace lands on the draft's setup page with the readiness list showing what is left, without a redirect loop and without a stored step number.
Finalization: the readiness checklist
The server computes this from real rows. Nothing here is a hand-ticked checkbox (VER-8569).
| Requirement | Derived from | Kind | Fix shown when missing |
|---|---|---|---|
| Company details complete | tenant name, address, timezone present | Blocker | "Finish your company profile" with a link to the fields |
| Site details complete | project name, address, geofence, start date | Blocker | "Add the site address" with the field focused |
| Superintendent assigned with access | a project lead row with role super whose invite is accepted, or the admin naming themself | Blocker | "Invite a superintendent" or "Resend Mike's invite, not accepted yet" |
| Foreman approval and crew sign-in flow working | sign-in gate configuration resolves for the project without an error; at least one approval path exists (super assigned or admin fallback) | Blocker | Names the setting that breaks it |
| QR poster working | a qr_codes row for the project that resolves to the sign-in route | Blocker | "Generate the poster" button inline |
| Required safety and orientation settings | the compliance-requirements and orientation settings the tenant marks required, using the new tenant defaults | Blocker | Lists the missing setting by name |
| Billing or pilot status correct | active subscription with a payment method, or prepaid checkout, or pilot billing profile | Blocker | "Add a payment method" or nothing for pilots and prepaid tenants |
| Subcontractors invited | at least one sub besides the GC self-sub | Optional | Nudge on the project page after activation |
| Templates, notifications | tenant settings | Optional | Follow-up card items |
Activate refuses while any blocker is open and returns the same list the page shows, so the button and the checklist can never disagree. Prepaid customers and pilots pass the billing row without a second charge; the check reads status, it never creates one.
Walkthrough of the target flow
Sarah builds the jobsite over two days
- Mon 0:00Opens the activation email, sets a passwordLands in her workspace on the company profile. Name and email are prefilled from the lead or HQ record; she adds the address. Every field saves as she types. No wizard, no step counter.Sees: "Saved" after each field, and a "Start your first jobsite" action.
- Mon 2:00Starts a jobsite draftTypes the project name and drops the map pin. The readiness list on the right shows seven blockers, all plainly named. She does not know the super's email yet and leaves the field blank.Sees: a draft that exists, and exactly what stands between it and live. Nothing has been charged.
- Mon 2:30Closes the laptopNothing is lost. There is no "unsaved changes" dialog because there is nothing unsaved.Sees: nothing. That is the point.
- Tue 7:10Comes back on her phoneThe workspace opens on the draft with "4 of 7 launch requirements met". She enters Mike's email under "Who runs this site?", which sends his invite. The super row flips to "invited, not yet accepted", still a blocker.Sees: the same list, the same wording, on a different device.
- Tue 9:40Mike acceptsHis acceptance clears the super blocker without Sarah doing anything. She taps "Generate poster", which clears the QR blocker. Six of seven.Sees: blockers clearing as the world changes, not as she clicks checkboxes.
- Tue 9:45Billing rowHer tenant is an HQ-provisioned pilot, so the billing row reads "Pilot, nothing to do". A self-serve tenant that paid at checkout reads the same way. A tenant without either sees "Add a payment method" and cannot activate.Sees: no surprise charge, and no second charge.
- Tue 9:46ActivateAll seven clear. The button is live. She activates; the project status becomes active, billing begins for this jobsite, and the poster download is offered again with "Tape this at the gate".Sees: a jobsite that can operate, and the physical thing she needs on site.
- Wed 6:40First worker scans the posterThe sign-in lands. The follow-up card (subs, templates, notifications) stays as nudges on the project page; nothing gates anything anymore.Sees: the product.
Mike's first login
- TueOpens his invite on his phoneThe link goes to the real activation route, not
/invite/{id}. He sets a password and lands on the super dashboard for the draft jobsite. He can see it is not live yet and what Sarah still needs to do, but nothing asks him to do it. The redirect rule never considers him.Sees: his site, its status, and "approve foreman" once it is live and the first sub arrives.
Where a blocker refuses
- any timeSarah taps Activate with the super invite still pendingThe server answers with the blocker list; the page highlights the super row: "Mike has not accepted yet. Resend invite, or name yourself as superintendent for now." The draft is untouched and still saving.Sees: what to fix and one way to fix it, never a generic error.
Rules the build keeps
Creating and editing a draft project never touches billing. The billing check moves from project creation to the readiness list and the activate endpoint. Prepaid and pilot tenants satisfy it by status; nothing in the flow creates a charge.
One endpoint returns blockers and optional items computed from rows that exist for another reason: lead rows, QR rows, settings, billing status. The page, the activate button, the follow-up card and the tenant-level redirect all read it. Hand-ticked checklist rows go away.
Redirect an admin only while the company profile is missing or no project exists, and only to the draft, never to a wizard step. Never redirect any other role. The two stored signals (tenant_onboarding_state, tenants.onboarding_completed) stop being read by anything.
Requirement ids and labels live in one shared list. The card, the setup page and the API return the same ids, so a requirement met in one place is met everywhere. The wizard, the top-bar pill and the guide page retire.
Build plan
Five phases. Phase 0 and 1 are dispatched. Phases 2 and 3 now have their ruling and can be dispatched next; phase 4 rides with them.
Phase 0 · Stop the bleeding
in progressPhase 1 · One onboarding signal
in progressPhase 2 · Drafts and the readiness endpoint
ready to dispatchGET /api/projects/:id/readiness returning blockers and optional items derived from data; make activate refuse with that list; add pilot billing profile at HQ provisioning; autosave on the setup page fields.Phase 3 · Setup page becomes the checkpoint; wizard retires
after phase 2Phase 4 · Canon, SPECs, tests
with phase 3tools/onboarding-wizard-steps/SPEC.md (retires) and tools/get-started-topbar-pill/SPEC.md (retires); the project setup SPEC gains the readiness contract. Un-quarantine the two expired onboarding contracts.Decisions
- Answered 2026-09-23: super assignment is required at finalization, not drafting. Drafts never bill. Prepaid and pilots pass billing by status.Recorded on VER-8526 and in the readiness table above.
- Open: does the follow-up card retire at the first sign-in, or stay until subs are invited?Recommendation: retire at first sign-in. Subs get nudged from the project page where the empty sub list already is.
- Open: can the wizard, guide page and top-bar pill be deleted outright in phase 3?Recommendation: yes. Their SPECs are amended in phase 4; nothing else links to them.
- Open: what counts as "required safety and orientation settings" for a blocker?Recommendation: the settings the tenant marked required in compliance requirements plus at least one orientation item when orientation is required; start from the new tenant defaults so a fresh GC is not blocked by an empty catalog.
Phases 2 and 3 can dispatch on the answered ruling; the three open items only shape their details.