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

# Modelo de datos y ciclo de vida

> Las entidades de identidad, el modelo de habilitación usuario × plataforma, el ciclo de vida del provisioning y el kill switch.

La capa de identidad y habilitación es un pequeño conjunto de entidades de gobernanza propiedad del
IdP. Esta página las describe **conceptualmente**; el esquema de almacenamiento concreto
es un detalle de implementación interno.

<Note>
  El IdP solo autentica. **No** hay catálogo de permisos, ni roles por cliente
  ni tablas de autorización. La autorización de grano fino vive en cada
  cliente; las APIs de B Brands usan su RBAC interno existente.
</Note>

## 1. Modelo lógico

```mermaid theme={null}
erDiagram
    User ||--o{ PlatformAccess : "enabled for"
    OAuthClient ||--o{ PlatformAccess : "grants"
    OAuthClient ||--o{ AuthorizationLog : "consent"
    OAuthClient ||--o{ IssuanceLog : "issuance"
    OAuthClient ||--o{ ProvisioningEvent : "webhook queue"
    OAuthClient ||--o{ AdminAudit : "admin changes"
    User ||--o{ TokenBlacklist : "revoked tokens"

    OAuthClient {
        id id PK
        string client_handle UK
        string display_name
        enum platform_type
        enum trust_level
        enum status
        enum id_token_alg
        list redirect_uris
        int access_token_ttl_seconds
    }
    PlatformAccess {
        id id PK
        id user FK
        id oauth_client FK
        enum status
        datetime expires_at
        id granted_by FK
    }
```

Convenciones comunes en cada entidad: una clave primaria UUID, campos de seguimiento estándar
(timestamps de creación/actualización/eliminación y flags de soft-delete), integridad
referencial restringida, y controles de acceso a nivel de fila.

## 2. Entidades

| Entidad                       | Propósito                                                                |
| ----------------------------- | ------------------------------------------------------------------------ |
| Registro de clientes OAuth    | Catálogo de clientes OAuth / plataformas + metadatos de gobernanza       |
| Acceso usuario × plataforma   | Habilitación usuario × cliente (estado, **sin rol**). La entidad central |
| Registro de autorización      | Registro de decisiones de consentimiento / autorización                  |
| Registro de emisión de tokens | Registro de emisión de tokens (OAuth + exchange interno)                 |
| Blacklist de tokens           | Revocación inmediata por `jti`                                           |
| Cola de provisioning          | Eventos de provisioning por webhook hacia el cliente                     |
| Auditoría de administración   | Auditoría de cambios de administración                                   |

### Registro de clientes OAuth

Contiene un registro por cliente registrado, con un `client_handle` estable (p. ej.
`erp-dev`), un display name visible por humanos, `platform_type` (`agent`, `analytics`,
`crm`, `erp`, `internal_tool`, `partner`), `trust_level` (`first_party`,
`partner`, `public`), `status` (`active`, `suspended`, `revoked`), `id_token_alg`
(`ES256` por defecto, `RS256` — el `id_token_signed_response_alg` de OIDC: con
`RS256`, el IdP re-firma el `id_token` del cliente con su clave RSA para que las
librerías que solo validan RS256, como el módulo OCA `auth_oidc` de Odoo,
funcionen sin modificaciones), las redirect URIs registradas (coincidencia
exacta), un TTL de token de acceso por cliente, y el target del webhook de
provisioning más su secreto de firma. El secreto del webhook nunca se devuelve
después de su creación.

### Acceso usuario × plataforma

La entidad central de habilitación. **Sin rol, sin permisos.** Un usuario puede tener a lo
sumo una habilitación activa por cliente. El hook de token de acceso y el exchange
ambos verifican `status = 'active'` y que la habilitación no haya expirado. Registra
quién otorgó el acceso, la expiración opcional, y los datos de revocación (cuándo, por quién, motivo).

### Registros y auditoría

<AccordionGroup>
  <Accordion title="Registro de autorización">
    Decisiones de consentimiento (`approve`/`deny`), los scopes solicitados, un correlation id,
    metadatos de la solicitud (IP, user agent) y referencias al cliente y al usuario.
  </Accordion>

  <Accordion title="Registro de emisión de tokens">
    Tipo de grant (`authorization_code` / `refresh_token` / `token_exchange`), tipo de token
    (`oidc_identity` / `internal_exchange`), `jti`, expiración y un correlation
    id. Append-only, best-effort.
  </Accordion>

  <Accordion title="Blacklist de tokens">
    El `jti` del token revocado, el tipo de token, el motivo (p. ej. `oauth_revocation`), la expiración
    (para la limpieza) y quién lo revocó.
  </Accordion>

  <Accordion title="Cola de provisioning">
    Tipo de evento (`user_provisioned` / `user_deprovisioned` / `user_suspended` /
    `user_reactivated`), estado de entrega (`pending` / `in_flight` / `delivered` /
    `failed` / `dead_letter`), el payload, el conteo de intentos, el próximo tiempo de reintento y el
    último error.
  </Accordion>

  <Accordion title="Auditoría de administración">
    La acción (cliente creado/actualizado/suspendido/revocado, secreto rotado, acceso
    otorgado/suspendido/revocado/reactivado, …), el actor, el cliente/usuario objetivo,
    un correlation id y metadatos de la solicitud.
  </Accordion>
</AccordionGroup>

## 3. Resolución de identidad y revocación

Una única rutina de resolución es llamada por el hook de token de acceso. Valida que
el cliente esté activo y el usuario habilitado, y devuelve el payload de identidad
(o un motivo estructurado de "no habilitado" en lugar de lanzar, para que el hook pueda responder
un `access_denied` limpio). El payload también lleva la dimensión de cuenta de
negocio: la cuenta vinculada al usuario mediante el rol `primary_user` y el id
del sistema externo de esa cuenta (`null` si no está mapeada). Un payload
resuelto típico:

```json theme={null}
{
  "enabled": true,
  "reason": "ok",
  "client_handle": "erp-dev",
  "platform_type": "erp",
  "trust_level": "first_party",
  "access_status": "active",
  "account": "uuid-of-account",
  "account_external_id": "ODOO-84213"
}
```

Dos rutinas de revocación respaldan el kill switch:

* **Revocar una única habilitación** para un usuario en un cliente.
* **Kill switch**: revocar **todas** las habilitaciones activas/suspendidas de un usuario en
  cada cliente a la vez. Cada transición dispara un evento de provisioning.

## 4. Ciclo de vida del provisioning

Un cambio de estado en la entidad de acceso usuario × plataforma es la **única** fuente de
eventos de provisioning:

| Transición                               | Evento               |
| ---------------------------------------- | -------------------- |
| Nueva habilitación con `status = active` | `user_provisioned`   |
| `* → active` (reactivación)              | `user_reactivated`   |
| `* → suspended`                          | `user_suspended`     |
| `* → revoked`                            | `user_deprovisioned` |

```mermaid theme={null}
stateDiagram-v2
    [*] --> pending: event enqueued
    pending --> in_flight: worker picks up
    in_flight --> delivered: 2xx
    in_flight --> failed: 4xx (no retry)
    in_flight --> pending: 5xx / timeout (backoff)
    pending --> dead_letter: max attempts reached
    failed --> [*]
    delivered --> [*]
    dead_letter --> pending: manual retry
```

## 5. Mantenimiento

El esquema evoluciona a través de migraciones versionadas. Trabajos de limpieza periódicos se ejecutan según
un cronograma: entradas de blacklist expiradas (diario), eventos entregados con más de 30 días
(semanal), y registros de emisión/autorización con más de 12 meses archivados en almacenamiento
en frío (mensual).
