> ## Documentation Index
> Fetch the complete documentation index at: https://internal.softcrum.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Support Impersonation

> After this ships, an operator can see exactly what a stuck customer sees — and that customer can see that it happened, when, and why.

## Context

Support cannot debug what it cannot see. Screenshots and screen shares are slow and often
impossible, so every serious B2B platform ends up with some form of impersonation. The question is
never whether, it is whether it is accountable.

Done casually — a superuser flag, no record — it is an undetectable read of every customer's data
by anyone with an internal account. That is a breach waiting for a disgruntled employee, and under
Ley 21.719 it is exactly the kind of access an audit asks about.

The design turns it from a liability into a trust signal by making it **impossible without a reason
and a time box, and visible to the tenant in their own audit trail**. The tenant is the party with
the incentive to notice an unexplained session, so they are the one who gets to see it.

This is deliberately the last feature in the module: it should not exist before the audit trail
that constrains it does.

## Scope *(normative)*

* `identity.impersonations`, append-only, with operator, target, reason and time box.
* A session that is explicitly an impersonation, never indistinguishable from a real one.
* A persistent visual banner in the console for the whole duration.
* Automatic expiry and manual end.
* Full visibility in the tenant's own audit trail.
* A restricted action set: read-only by default.

## Non-scope *(normative)*

* Tenant-to-tenant impersonation. Never, under any configuration.
* Impersonating a specific individual user's identity. The operator acts **as an operator scoped to
  the organization**, not as that person — attributing an operator's actions to a customer's
  employee is falsifying an audit trail.
* Silent or invisible access. There is no configuration that hides it.

## Behaviour *(normative)*

1. Starting an impersonation requires the `identity.impersonation.start` permission — Ops only —
   **plus re-authentication, plus a free-text reason of at least 20 characters**. The length floor
   exists because "debugging" is not a reason.
2. Every impersonation is **time-boxed**, default 60 minutes, hard maximum 4 hours. It expires
   automatically; there is no extend, only a new one with a new reason.
3. The session is marked as an impersonation and every action taken under it is attributed to the
   **operator**, never to a user of the tenant. The audit actor is the operator, with the
   impersonation id attached.
4. **Read-only by default.** Write actions require a separate `identity.impersonation.write`
   permission and are individually audit-logged with heightened visibility. Most support problems
   are diagnosed by looking.
5. Certain data is **never visible under impersonation**: full national IDs, API key secrets, MFA
   secrets and recovery codes. An operator seeing a customer's screen does not need their
   customers' identity documents.
6. The console shows a **persistent, unmissable banner** for the entire session, naming the
   organization and the remaining time.
7. The tenant sees every impersonation in **their own audit trail**, with operator, reason, duration
   and actions taken. It is not filtered out, ever.
8. Starting one notifies the organization's owners by email. A tenant learning about access only if
   they go looking is not transparency.
9. `identity.impersonations` is **append-only**. A record cannot be edited or deleted by anyone,
   including Ops.
10. An impersonation can never reach another organization, and never the member realm.

## Data *(normative)*

| Table                     | Key invariants                                                                                                                                                                                                          |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `identity.impersonations` | append-only; `operator_user_id`, `organization_id`; `reason` NOT NULL, min length enforced; `started_at`, `expires_at`, `ended_at`; `is_write_enabled`; `actions_count`; never updated except `ended_at`, never deleted |

## API *(normative)*

| Endpoint                                    | Class      | Permission                                    | Budget       |
| ------------------------------------------- | ---------- | --------------------------------------------- | ------------ |
| `POST /v1/identity/impersonations`          | Management | `identity.impersonation.start`, re-auth       | p95 \<1 s    |
| `POST /v1/identity/impersonations/{id}/end` | Management | operator or tenant owner                      | p95 \<300 ms |
| `GET /v1/identity/impersonations`           | Management | `identity.impersonation.read` or tenant owner | p95 \<1 s    |

A **tenant owner can end an impersonation of their own organization**. If they are uncomfortable
with what they see happening, they get to stop it.

## Events *(normative)*

`identity.impersonation.started` and `identity.impersonation.ended`. The `started` event drives an
immediate notification to the organization's owners through `messaging`.

## Acceptance criteria *(normative)*

1. Starting without a reason, with a reason under 20 characters, or without re-authentication is
   rejected in each case.
2. An impersonation expires automatically at its time box; requests afterwards are rejected.
3. Beyond the 4-hour maximum, creation is rejected.
4. Every action under impersonation is audited with the operator as actor and the impersonation id
   attached — never with a tenant user as actor.
5. A write attempt without `identity.impersonation.write` is rejected.
6. Full national IDs, key secrets and MFA secrets are unreadable under impersonation, whatever roles
   the operator holds.
7. The tenant's own audit trail shows the impersonation with reason and duration.
8. Organization owners receive a notification within seconds of the start.
9. A tenant owner can end an impersonation of their organization.
10. **Negative:** no configuration, flag or endpoint hides an impersonation from the tenant, and no
    impersonation record can be edited or deleted.

## Execution

Single slice, synchronous command. F1b, and last in the module by design. The banner is a
`frontend/console` concern driven by the session flag; notifications go through `messaging`.

## Open questions

| # | Question                                                                                      | Decides | By              |
| - | --------------------------------------------------------------------------------------------- | ------- | --------------- |
| 1 | Can a tenant disable impersonation entirely for their organization, accepting slower support? | Daniel  | before approval |
| 2 | Default time box — 60 minutes, or 30 with easy renewal?                                       | Daniel  | before approval |

## Changelog

| Version | Date       | Change        | Why | Author                 |
| ------- | ---------- | ------------- | --- | ---------------------- |
| 0.1.0   | 2026-08-17 | Initial draft | —   | daniel + claude-opus-5 |

## Delivery record

*Not implemented yet.*
