Skip to main content
This runbook is for Vorel platform operators (the platform_operator role). End customers and tenant admins do not have access to this feature. Tenant admins do see audit-log entries when an operator impersonates their tenant.
The view-as-tenant feature lets a Vorel platform operator render the tenant-side dashboard (/inbox, /cases, /leads, /analytics, …) as that tenant, without needing a user account on the tenant. It is the support primitive for “what is the tenant’s admin actually seeing right now?”, load-bearing for incident response, data-sync debugging, and live verification of new features against real production data.

When to use it

Customer-support escalation

A tenant admin reports their inbox is empty when their voice agent took 12 calls today. You need to see the inbox exactly as they see it (same RLS scope, same UI overlays, same filters) to confirm whether the calls are missing from the tenant view or whether the tenant’s view has a stale filter applied.

Data-sync debugging

A tenant’s CRM-write is failing intermittently. You need to confirm whether the lead row exists on the Vorel side from the tenant’s perspective (it could be RLS-scoped out, or filtered by status). View-as-tenant lets you see what their admin would see.

Live verification of a new feature

You shipped a new dashboard view behind a feature flag for one tenant. Before announcing it, you want to log in as that tenant and confirm the surface renders correctly with their real data.

Onboarding handoff verification

A new tenant just finished kickoff. You want to confirm their dashboard renders correctly with their persona, their offerings, their CRM connection, before sending the “you’re live” email.

When NOT to use it

  • Routine admin work. Use the operator console at /admin/tenants/<id> for cross-tenant operator tasks: managing credentials, viewing audit logs, running cost rollups. View-as-tenant is for seeing the tenant-side UI, not for performing operator work.
  • Bulk operations across tenants. If you’re doing something that touches multiple tenants, use the operator-side cross-tenant surfaces. Repeatedly starting and stopping view-as-tenant sessions for ten tenants is a code-smell; there is probably an operator-side bulk surface for what you’re trying to do.
  • As a workaround for missing operator-side functionality. If you find yourself impersonating a tenant to do something the operator console should support, file an issue. The operator console is the surface that’s supposed to evolve to cover those gaps.

How to use it

1

Navigate to the tenant page

From the admin console at /admin/tenants, click the tenant you need to impersonate. You land at /admin/tenants/<id>.
2

Click 'View as tenant'

On the tenant page there is a card titled View tenant-side as this tenant. Enter a short reason (3–200 characters) in the Reason field, for example debug data sync, verify cases dashboard, look at their inbox. The reason is required and lands in the audit trail.
3

Submit the form

Click View as tenant →. Vorel writes an impersonation_started row to audit_log with your platform-operator id, the tenant id, and the reason. The system sets an 8-hour session cookie scoped to your browser session and redirects you to /inbox.
4

Use the tenant-side dashboard as that tenant

Every tenant-scoped query now resolves to the impersonated tenant. The dashboard renders as their admin sees it: same RLS scope, same offerings, same conversation history. A banner appears at the top of every tenant-side page reminding you that you are impersonating, displaying the tenant name and a Stop impersonation button.
5

Stop impersonation when done

Click the Stop impersonation button in the banner. Vorel writes an impersonation_ended row to audit_log and clears the session cookie. You return to your operator identity. Alternatively, clearing browser cookies ends the session; closing the browser does not (cookies persist) unless your browser is in private mode.

Session semantics

  • Cookie-scoped. The impersonation lives in an 8-hour session cookie. There is no server-side persistent state recording “operator X is currently impersonating tenant Y”; the cookie is the only carrier. Two browsers running side-by-side can each have independent impersonation contexts.
  • 8-hour expiry. The cookie expires 8 hours after the session starts. After expiry, the dashboard reverts to your operator identity automatically; no impersonation_ended audit row fires for the silent expiry (the row only fires on explicit stop). Auditors who need to know when a session ended can infer it from the next impersonation_started row or from access patterns.
  • Single-tenant at a time. You can impersonate one tenant at a time. Starting a new impersonation while another is active replaces the active one (an impersonation_ended row fires for the old, an impersonation_started row fires for the new).
  • No write actions during impersonation are tagged as the tenant. Mutations you perform while impersonating still carry your operator identity in their audit rows, so a write that happens during an impersonated session is traceable back to the operator that performed it, not laundered through the tenant identity.

Audit-trail guarantees

Every start and explicit stop of an impersonation session writes an audit_log row:
  • impersonation_started: fields: operator’s user id, target tenant id, reason text, IP address, user agent, ISO timestamp.
  • impersonation_ended: fields: operator’s user id, target tenant id, ISO timestamp.
These rows are written into the tenant’s audit_log partition and are visible to the tenant’s admin at the tenant-side audit surface. The tenant admin can see that on 2026-05-19 at 14:32 UTC, Vorel operator Alice impersonated their tenant for the reason “debug data sync” and ended the session 17 minutes later. This is intentional: the tenant’s trust posture is that Vorel operators can impersonate, but every impersonation is visible to the tenant’s admin in the same surface they audit their own team’s activity. The audit_log table is append-only at the database level via a Postgres trigger; impersonation rows cannot be redacted or deleted by anyone (operator, tenant admin, or platform-level) except via the global retention regime. There is no admin path to hide an impersonation event from a tenant.

Security model

  • Role-gated. Only users with platformRole === 'platform_operator' can start an impersonation. The gate runs in the server action that handles the form submission, independent of any client-side check.
  • Defense in depth. The admin route group (/admin/*) is already operator-gated by middleware; the impersonation server action enforces the same role check independently. A bypass of the admin route would still fail at the action.
  • Reason required. The reason field is required (3–200 characters); the action rejects an empty or too-short reason. Reasons are not validated for content; write “debug data sync” not “lol”. The audit row is what tenant admins read.
  • No token persistence. There is no JWT, no API key, no server-side impersonation token table. The session cookie is signed with the same secret used for operator authentication. There is no way to “share” an impersonation session across browsers or recover one after the cookie is cleared.
  • No bypass of tenant-side guardrails. Impersonation overlays the tenant identity onto your operator session; it does not grant you privileges that the tenant admin does not have. If a tenant’s admin cannot see archived conversations, neither can you while impersonating them.

Operating notes

  • Two operators impersonating the same tenant is allowed. The audit log shows both. There is no “exclusive lock”; view-as-tenant is read-style support, not a destructive operation that needs serialization.
  • Long-running session timeouts. An 8-hour cookie is long for a support session and short for a debugging session that spans a workday. If you need to span multiple workdays, re-start the impersonation each morning. Two impersonation_started rows on consecutive days for the same tenant is normal.
  • Customer-facing notifications. Vorel does not email the tenant admin when an impersonation starts; the audit row is sufficient per the trust model. If a particularly sensitive tenant (PHI-adjacent, financial-services) wants per-event email alerts, that is a per-tenant configuration request via the operator console; the audit row remains the source of truth.