# CLAUDE.md — `web/src/components/sidebar/`

Sidebar + the workspace switcher. Two coupled controls (see
`text/roles-optimisation-plan.md § Navigation & impersonation model`):

## Top × bottom — the navigation/impersonation model

| | **Top — `GroupSwitcher`** (header) | **Bottom — `AuthButton`** (footer) |
|---|---|---|
| Question | *Where am I?* — which group | *Who am I?* — which user in this group |
| Action | switch group context (re-scopes auth — C8) | impersonate a member of the **current** group |
| Browse | parent→child drill: agencies → clients → teams, per-level search | the active group's members; act-as gated (allow-matrix, time-boxed, audited, no-nesting) |

**Coupling rule:** the bottom list IS the top's current group. `AuthButton`
fetches `/api/export/actors?group=<active slug>`; switching groups is a full
nav, so it re-mounts and re-scopes. Pick the room (top), pick whose eyes you
look through (bottom).

## GroupSwitcher (top) — hierarchy drill

One level at a time over `/api/groups/tree?depth=3` (membership-scoped: only
your subtree). Each row: **body click = switch** into that group (`navigate()`
POSTs `/api/groups/active` then redirects — C8 re-scope); **chevron = drill**
into its children. Breadcrumb back + per-level search → scales from 3 to 300
children. No act-as here — impersonation lives at the bottom.

`GroupSwitcherTree.tsx` (recursive, fixed to render each node once) remains for
fully-expanded tree views; the switcher itself uses the drill.

## Don't

- Don't put impersonation in the top switcher — it belongs in `AuthButton`, scoped to the current group.
- Don't load the whole forest — drill + search; `/api/groups/tree` is already membership-scoped.
- Design + `emitClick` rules apply (auto-loaded from `../CLAUDE.md`).
