Skip to main content

Onboarding a Tenant

This is the end-to-end flow for bringing a new tenant online. It starts with a platform owner and ends with a freshly-minted tenant admin who can manage the tenant from the portal on their own. All of it happens inside the Flightdeck — no shell access, no database edits.

This guide assumes built-in email/password authentication (the default). The OIDC and SAML modes are slightly different and covered at the end.

Quick map

owner creates the tenant → owner invites the tenant admin → admin clicks email link → /register → logs in → lands at /portal → invites the rest of their team.

Prerequisites

  • A platform owner account signed in to the Flightdeck. If this is your first time, run through First-run setup to create the initial owner.
  • The six built-in roles and their capabilities are documented in Setup & Login → RBAC roles. This guide uses owner (platform) and admin (tenant).
  • For production, email delivery needs to be configured — see Email delivery below.

Step 1 — Create the tenant

In the sidebar, open Identity → Tenants and click New Tenant. Fill in the basics (name, region, priority tier) and submit.

Create-tenant formCreate-tenant form
Figure 1. Create-tenant form

When the save succeeds, a toast appears at the top-right with a call-to-action link:

✅ Tenant 'Acme Corp' created. Invite admin →

The toast stays up for seven seconds. Click Invite admin → while it's still visible and you'll be dropped on the invite form with the right context already filled in. If you miss it, the same deep link is available from the tenant's edit page (next step).

A TENANT_CREATED event lands in the audit log at this point; see it under Audit → Events.

Step 2 — Review the Team section (optional)

Open any existing tenant's edit page (Tenants → Edit on the row). A new Team section in the sidebar lists users assigned to this tenant plus two deep-link buttons:

  • Invite admin — pre-selects the tenant role admin
  • Invite with other role… — opens the invite form with just the tenant ID pre-filled so you can pick developer or viewer manually
Tenant edit form — the Team section is in the left sidebarTenant edit form — the Team section is in the left sidebar
Figure 2. Tenant edit form — the Team section is in the left sidebar

Each row shows the user's email (linked to their edit page), name, roles, and status (INVITED / ACTIVE / SUSPENDED). An INVITED user hasn't set their password yet — they're waiting to click the email link.

Step 3 — Send the invitation

Whichever path you took, you land on /users/new with the tenant ID and role already populated.

Invite user form with role checkboxesInvite user form with role checkboxes
Figure 3. Invite user form with role checkboxes

Fill in:

  • Email — where the invitation will be sent.
  • Name — optional display name.
  • Roles — leave admin checked. You can assign multiple tenant roles but you cannot mix platform and tenant roles on one user.

Click Send Invitation. The server:

  1. Creates a User record with status=INVITED and a 7-day verification token.
  2. Renders the invitation email from a template and hands it to the configured transport (log or SMTP — see below).

Step 4 — Tenant admin accepts the invitation

The invitee receives an email with a Set your password link that points at /register?token=<uuid>. The token is single-use and expires in 7 days. When they open it:

  1. They're asked for a password (minimum length is enforced — see built-in auth config).
  2. On submit, the User flips from INVITED to ACTIVE, the token is cleared, and they're redirected to /login?registered=true.
  3. They log in with their email and the password they just set.

Because their role is admin (a tenant role), the login flow drops them at /portal, not /.

Step 5 — Hand off to the tenant admin

At /portal the new admin sees the tenant-scoped dashboard — usage, cost, audit, API keys, provider credentials, and a Team page. From Team → Invite, they can invite their developers and viewers without involving the platform owner.

The tenant portal landing the new admin sees right after accepting the invitation and signing inThe tenant portal landing the new admin sees right after accepting the invitation and signing in
Figure 4. What the customer sees at /portal after the invitation flow completes — KPI tiles, quick actions, and a Team link in the sidebar. No platform-owner concepts (routes, policies-as-platform, billing console) are visible; the page is scoped to the admin's own tenant.

Scope limits the admin to their own tenant: they can only invite users whose role is admin, developer, or viewer, and every invitation they send is scoped to their tenant automatically.

From this point the platform owner is out of the loop unless they need to change role assignments, suspend the tenant, or manage platform-level resources.

Email delivery

The invitation email is built from a templated HTML body and delivered by one of three transports, configured with dvara.flightdeck.email.transport (env: DVARA_FLIGHTDECK_EMAIL_TRANSPORT):

  • log (default, for local and CI) — the entire email including the /register?token=… link is printed to the Flightdeck logs at INFO. Grep the log by the recipient address to find the token.
  • smtp (production) — uses the standard SMTP properties (spring.mail.host, spring.mail.port, spring.mail.username, spring.mail.password) via Spring's JavaMailSender. Set dvara.flightdeck.security.builtin.base-url to the public Flightdeck URL — otherwise the link the user receives will point at http://localhost:8090/register?token=…, which is exactly the kind of detail you discover only after a real user tries to click it.
  • resend (production) — POSTs to the Resend transactional API. Set dvara.flightdeck.email.resend-api-key (re_…) and verify your sender domain in Resend, or use the sandbox sender onboarding@resend.dev for testing. Same base-url requirement as smtp for the link's host.

Token lifetime is seven days. Expired tokens render as invitation link is invalid or has expired on /register; there's no self-service resend yet, so the invite needs to be re-sent from /users/new.

Audit events

Onboarding shows up in the immutable audit trail as:

Event typeEmitted whenPayload highlights
TENANT_CREATEDA platform owner creates the tenant in step 1tenant_id, name, status, metadata, actor
TENANT_METADATA_UPDATEDAny subsequent edits to the tenanttenant_id, actor, changes (diff per key)
TENANT_DELETEDThe tenant is deletedtenant_id, name, status, actor
USER_INVITEDStep 3 succeeds — user persisted with status=INVITED and the invitation email delivereduser_id, email, tenant_id (null for platform-role invites), roles, status (INVITED), actor

Token acceptance at /register (step 4) does not currently emit its own audit event. If you need richer audit coverage of user lifecycle, the Automation API at /v1/admin/users additionally emits USER_CREATED, USER_ROLE_ASSIGNED, USER_ROLE_REVOKED, and USER_DELETED events from Terraform or CI/CD flows.

OIDC and SAML deployments

If the Flightdeck is configured for OIDC (Enabling OIDC) or SAML, identity is owned by your IdP, not by DVARA, and this flow is slightly different:

  • OIDC — users are not sent an invitation email. They exist in DVARA either by being created ahead of time via the Users page (invite-first mode) or by being auto-provisioned on first login from the JWT claims. /register is not used.
  • SAML — same shape as OIDC. With dvara.flightdeck.security.saml.auto-provision=true, the user is created on first successful assertion using defaultRoles and defaultTenantId. For CI/CD automation against /v1/admin/**, issue a personal access token (dvara_pat_…) from /settings/tokens after a browser login.

In both modes, the Team section on the tenant edit page and the portal team page still work for role assignments; only the email + password flow is skipped.

Troubleshooting

The CTA toast disappeared before I could click it. It stays up for seven seconds. If you missed it, open the tenant's edit page — the Team section has the same deep-link buttons.

The invitee clicked the link and got invitation link is invalid or has expired. Either the 7-day TTL has passed or the invite has already been consumed. Re-send from /users/new.

The invite email never arrived. Check the email transport. In log mode, the email is in the Flightdeck logs — grep for the recipient address. In smtp mode, verify dvara.flightdeck.security.builtin.email.from and the SMTP connection properties, and confirm the SMTP host is reachable from the Flightdeck pod.

The admin logged in but landed on / instead of /portal. That means they ended up with a platform role (owner, policy-admin, billing-admin) instead of a tenant role. Edit the user and check the role assignments — mixing platform and tenant roles on one user is rejected at create time, but a role mistakenly set to owner will land the user on the platform dashboard.