# Journey result: Tenant onboard

- **Source**: `WALKTHROUGH/journeys/tenant-onboard.md`
- **Walked**: 2026-05-29 by Claude (Opus 4.8) against commit `eff6655269`
- **Verdict**: **pass (in-scope surfaces) / out-of-scope (tenant CRUD UI)** —
  the operator surfaces render and gate correctly; tenant-creation UI is
  allocated to the separate `apps/oshun/tenant-admin` app, but a 2026-07-17
  source search found no shipped caller for the BFF onboarding endpoint.
- **Walker**: `/tmp/claude-oshun-lt-2-walkthrough/walk.mjs tenant-onboard`

## Summary

`/operator` and `/operator/admin` auth-gate correctly (anon →
`/welcome?redirect= /operator`); when seeded they render. `/system` renders the
Lilith specimen sheet. `/v1/tenants` + `POST /v1/tenants/onboard` BFF endpoints
were added in goal-2/3. The tenant member/SCIM/SSO admin UI is in
`apps/oshun/tenant-admin`, which is explicitly out of this WALKTHROUGH's scope
(per README + CLAUDE.md); that does not establish an implemented organization-
creation caller. No persistent failures in this shell.

## Steps

- **Step 1 — operator + system routes**: pass (auth-gate correct; render when
  seeded; no broken links / page errors in this shell).

## 2026-06-26 addendum

- `/operator/tenant` Invite / + Add member are now covered by
  `apps/oshun/web/e2e/tenant-member-actions.spec.ts` against the live BFF.
- The signed-in invitee handoff is now covered at `/tenant/invite`: Playwright
  creates a real pending invite, signs in as the invitee, accepts the token from
  the browser page, and reads the active member + accepted invitation back
  through the tenant-console BFF cockpit.
- Still out of scope for this result: outbound branded email, root
  `?invite=<token>` link middleware, tenant SSO/MFA, full onboarding completion,
  first action, and tenant audit-chain reconciliation.

## 2026-07-17 durability and subject-privacy addendum

- Source commits `747edeab5215be2349c16430a8b2e87b62974cb0` and
  `92bb24d911954b874ea75f0b1e897847332dd14c` make Invite, Add, Accept, revoke,
  expiry, capacity, bulk-auth membership, and erasure candidate/save/publish
  operations over one strict schema-v2 snapshot. Deployable startup now requires
  and hydrates its Postgres sink before traffic.
- A real PostgreSQL integration proved v1 migration, accepted-subject recovery,
  mismatched-current-email export/erasure, seat release, resurrection fencing,
  and restart. The two isolated exact-source BFF-backed Chromium specs passed
  12/12 against a fresh migrated database.
- The internal accepted-subject link is never returned publicly. New invite and
  member success audits keep operational record ids and categorical state while
  omitting raw target email/user id; this privacy-safe utility copy follows the
  frontend review without changing hierarchy, layout, or motion.
- The boundary remains partial: mutation serialization is per process with no
  distributed compare-and-swap, invite-email/account equality is not enforced,
  terminal invitation records have no general time-based purge, old audit PII is
  not retroactively rewritten, acceptance has no dedicated audit event, and SCIM
  remains a separate projection.

## 2026-07-17 organization-onboarding authority addendum

- Source commit `fb0d40ead8b36badad3f04284096fda68b1a3403` makes
  `POST /v1/tenants/onboard` acknowledgement-bound. New organizations commit one
  strict active snapshot containing exact contract, hierarchy, residency,
  billing, allocation, isolation, and lifecycle fields. Failed persistence
  returns `503` without publishing a tenant, and deployable startup requires and
  restores the store before traffic.
- Public detail omits creator identity. Profile export includes the exact
  operator-created tenant view; account erasure pseudonymizes its creator and
  persists a restart-safe fence while retaining the shared organization and
  adjacent creators.
- Connected route/export/store tests passed 140/140, real PostgreSQL restart and
  privacy proof passed 1/1, the BFF type ratchet remained at zero, and the final
  33.0 MiB artifact booted against Redis plus a fresh database with all 15
  migrations and exited cleanly.
- This is API/store evidence, not tenant CRUD UI evidence. Repository-wide
  source search found no shipped UI caller for the onboarding endpoint, so no
  new Playwright flow is claimed. The existing roster UI contract did not
  change.
- Remaining boundaries: per-process whole-snapshot serialization, no request
  idempotency key, no dedicated onboarding audit event, no external isolation
  provisioning effect, no update/archive/offboarding flow, and `seatTotal`
  remains distinct from the separate live membership authority.

## Adjacent separate-app scope

- A tenant creation wizard and the admin invite, SAML/OIDC setup, and SCIM
  member-seed surfaces are allocated to `apps/oshun/tenant-admin`; this result
  does not claim that an organization-onboarding caller exists there. The
  operator-facing tenant _roster/SSO/ audit_ views inside this shell are covered
  by the `tenant-bulk-member-invite-scim`, `tenant-sso-config-*`, and
  `tenant-audit-log-investigation` journeys (batch 8).
