---
id: "0163"
title: "Matrix admin panel propio: users, rooms, devices, sessions (sustituye synapse-admin)"
status: pending
priority: medium
created: 2026-05-24
related_flows: ["0010", "0011"]
related_issues: ["0162", "0147"]
dependencies: ["0162"]
tags: [matrix, admin, panel, react, mantine, mas, synapse, infra]
---

## Objetivo

Panel admin propio que reemplaza `https://admin-0cc4d3.organic-machine.com/#/users` (synapse-admin actual). Funciones equivalentes: gestionar usuarios (crear, deactivate, reset password, list devices, list rooms), gestionar rooms (list, members, kick, force-leave, delete), ver sesiones activas + revoke, ver media (storage usage por user). Auth via MAS OIDC con scope admin. Stack: React+Vite+Mantine+`@fn_library` (consistente con flows 0010/0011 + resto del registry).

## Por que reemplazar synapse-admin

- **Auth legacy**: synapse-admin usa admin token + password admin directo. Tras issue 0162 (MAS obligatorio) esto chirria. Mejor consume MAS OIDC + Synapse Admin API.
- **UI ajena**: stack distinto al resto del registry. Sin theming propio, sin `@fn_library`, sin coherencia visual con cliente PC (flow 0010).
- **Sin agentes**: no podemos integrar paneles especiales para `agents_and_robots`, devices del mesh (flow 0009), policies de widgets.
- **No extensible**: anadir "ver telemetria de calls LiveKit" o "audit log MAS" requiere fork pesado.

## Tareas

1. **Scaffold app**:
   - `projects/element_agents/apps/matrix_admin_panel/`.
   - Stack: React+Vite+TS+Mantine+`@fn_library`+`@tabler/icons-react`.
   - Backend: Go con `mautrix-go` admin client + MAS OIDC client + `livekit-server-sdk-go` (para sesiones de call).
   - Empaquetado: backend Go sirve frontend estatico embebido (`embed.FS`).
   - Deploy: container Docker en `element_matrix_chat` stack o como service standalone via `deploy_server`.

2. **Auth flow MAS**:
   - Cliente registrado en MAS (issue 0162 paso 2) con scope `urn:synapse:admin:*`.
   - Login Web: OIDC redirect a MAS.
   - Token guardado en httpOnly cookie + CSRF token.

3. **Modulos UI**:
   - **Users**:
     - Tabla virtualizada con `data-table` (cuando exista TS equivalente) o `mantine-react-table`.
     - Columnas: localpart, displayname, avatar, admin, deactivated, last_seen, device_count.
     - Acciones por row: view detail, deactivate/reactivate, reset password (force MAS link), list devices.
     - Filtros: deactivated, admin, search.
   - **User detail**:
     - Sub-tabs: Profile, Devices (list + revoke individual), Rooms (membership list), Media (uploads + size), Sessions (MAS active sessions + revoke), Audit log (MAS).
   - **Rooms**:
     - Tabla: room_id, name, alias, members_count, encrypted, public, federated, state_events.
     - Acciones: view detail, force-leave usuarios, delete room (purge), shutdown notif.
   - **Room detail**:
     - Members + roles, state events viewer (read-only JSON), media in room, widgets activos (interop con flow 0010 widget API).
   - **Sessions** (MAS):
     - Lista sesiones activas global.
     - Filtro por user, IP, device, last_used.
     - Revoke individual o bulk.
   - **Federation**:
     - Estado federation (Synapse `federation_handler`).
     - Allowlist/blocklist servers.
   - **Stats**:
     - Resumen: users count, rooms count, mensajes/dia (ultima semana), media storage, calls activas (via LiveKit `RoomService.ListRooms`).
     - Graficas con `@mantine/charts` o `recharts`.

4. **Capability groups en panel**:
   - Reusa `AgentPanel` (flow 0010 issue 0153) para mostrar info de agentes registrados.
   - Reusa `DevicePanel` (cuando flow 0009 vivo) para devices del mesh.
   - Slot "Widgets policy": ver/aprobar capabilities concedidas globalmente, audit log.

5. **API endpoints backend Go**:
   - `GET /api/users` -> proxy a Synapse `/_synapse/admin/v2/users` con auth MAS.
   - `POST /api/users/<id>/deactivate`.
   - `GET /api/rooms`, `POST /api/rooms/<id>/delete`.
   - `GET /api/mas/sessions`, `POST /api/mas/sessions/<id>/revoke` (MAS admin API).
   - `GET /api/livekit/rooms` (active calls).
   - `GET /api/stats/summary`.

6. **Permisos**:
   - Solo users con flag `admin: true` (Synapse) o scope MAS admin claim.
   - Backend valida claim/flag en cada request.
   - UI muestra "Access denied" si user logueado no es admin.

7. **Deploy**:
   - Anadir container al `docker-compose.yml` de `element_matrix_chat`.
   - O bien standalone via `deploy_server` (registry function existente).
   - URL: `admin-af2f3d.organic-machine.com` o reusar `admin-0cc4d3.organic-machine.com` cuando se retire synapse-admin.

8. **Migracion synapse-admin -> panel propio**:
   - Coexistencia 2 semanas: ambos vivos, MAS audita uso de cada uno.
   - Cuando uso de synapse-admin = 0 durante 7 dias seguidos: detener container.
   - Documentar en `docs/admin_panel_migration.md`.

9. **Tests**:
   - `e2e/test_admin_login.sh` — MAS OIDC + scope admin valido -> acceso.
   - `e2e/test_admin_login_denied.sh` — user no-admin recibe 403.
   - `e2e/test_user_deactivate.sh` — flow completo deactivate + verify can't login.
   - `e2e/test_room_purge.sh` — purge room + verify gone en Synapse.
   - `e2e/test_session_revoke.sh` — revoke sesion MAS + user perdiendo acceso en <30s.

## Funciones del registry a crear

- `synapse_admin_client_go_infra` — wrapper Synapse Admin API.
- `mas_admin_client_go_infra` — wrapper MAS admin API (`/api/admin/v1/...`).
- `livekit_admin_client_go_infra` — `RoomService.ListRooms`, kick participant, etc.
- `oidc_admin_middleware_go_infra` — middleware Go que valida scope admin en cookie/Bearer.
- `UsersTable_ts_ui` — componente Mantine con virtualization + filtros.
- `RoomDetail_ts_ui` — componente con tabs Members/State/Media/Widgets.
- `SessionsList_ts_ui` — lista sesiones + revoke action.
- `StatsSummary_ts_ui` — componente con `@mantine/charts`.
- `FederationStatusPanel_ts_ui` — componente federation diag.

## Acceptance

- [ ] App compila + arranca como container Docker.
- [ ] Login via MAS OIDC con scope admin funciona.
- [ ] User no-admin recibe 403 al intentar entrar.
- [ ] Tabla users con 50+ rows + filtros + actions.
- [ ] Deactivate user end-to-end (verify cannot login despues).
- [ ] Room detail muestra members + state events JSON.
- [ ] Sessions MAS listadas + revoke individual.
- [ ] Stats: counts + media usage + active calls visibles.
- [ ] Tema visual coherente con cliente PC (flow 0010).

## Definition of Done

### Mecanica
- `go build` + `pnpm build` verde.
- Container Docker `<150MB` (Alpine + binary + static).
- Health endpoint `/health` 200.
- E2E suite pasa.

### Cobertura

| Escenario | Evidencia | Resultado |
|---|---|---|
| Golden: admin login + ver users | `e2e/test_admin_full_flow.sh` | tabla con users reales, actions visibles |
| Edge: 5000 users en tabla | benchmark scroll | 60fps, <300MB RAM |
| Edge: user sin admin entra | request directo | 403 + audit log |
| Edge: room con 200 members | view detail | render < 1s, paginacion OK |
| Error: Synapse Admin API caida | mock 500 | UI muestra error claro, no crash |
| Error: MAS session revoke fails | mock 500 | retry + toast error |

### Vida util (>=7 dias)

| Metrica | Umbral | Donde | Ventana |
|---|---|---|---|
| Crashes container | `0` | docker logs | 7 dias |
| Uso real | `>= 2 sesiones/semana` (operador) | nginx access log | 7 dias |
| Latency p95 endpoint /api/users | `< 800ms` (Synapse Admin paginado) | metrics | 7 dias |
| Acciones destructivas auditadas | `100%` (cada delete/revoke con audit row) | local audit DB | continuo |

### Anti-criterios
- NO marcar done si admin panel acepta token sin claim/flag admin.
- NO marcar done si delete room no purga media en DB Synapse.
- NO marcar done si UI deja al operador sin confirmacion en acciones destructivas (deactivate, purge, revoke).
- NO marcar done si lookalike de synapse-admin sin features propias (mejor mantener synapse-admin entonces).

## Notas

**Ventajas reales sobre synapse-admin:**
1. Coherencia visual + Mantine + theme propio.
2. Integracion con `agents_and_robots` (panel agente embedded).
3. Integracion con widgets policy (audit + override capabilities).
4. Integracion con LiveKit calls (ver rooms activos, force-end).
5. Audit log local SQLite con todas las acciones admin (synapse-admin no lo tiene).
6. Extensible — anadir tabs para mesh devices (flow 0009), telemetria, etc.

**Onboarding:**
1. `cd projects/element_agents/apps/matrix_admin_panel`.
2. `make dev` (Go backend + Vite frontend hot reload).
3. Visitar `http://127.0.0.1:8090` -> login MAS dev.
4. Deploy prod: ver `deploy/README.md`.

**Decisiones:**
- Backend Go > Python/Node: alinea con `mautrix-go` + reusa funciones del registry. Binario pequeno, deploy facil.
- Embedded static (Go `embed.FS`): un binario, sin docker multi-stage compleja.
- Audit log local SQLite > Postgres: panel admin no necesita HA, suficiente con SQLite local + backup periodico.

**Gotchas:**
- Synapse Admin API requiere `Bearer <admin_token>` — el panel intercambia OIDC token + admin claim por admin_token (con MAS admin API o con cuenta admin shared).
- MAS admin API esta en `/api/admin/v1/` — version unstable, monitorizar breaking changes.
- Federation tab: si federation deshabilitada (caso actual, ver `homeserver.yaml`), tab muestra "disabled" en vez de error.

**Roadmap post-DoD:**
- Bulk actions (mass deactivate, mass invite).
- Export reports CSV.
- Slack/email alerts en eventos criticos (server cae, MAS down, federation block).
- Multi-tenancy si llegan mas homeservers.

## Capability growth log

- v0.1.0 (2026-05-24) — issue creada.
