Ir al contenido

Entity model

Los dispositivos por sí solos son una lista plana. El entity model es la forma en que CORE-M les da estructura y los comparte de forma segura: los activos agrupan y ubican dispositivos, las relations tipadas conectan todo en un grafo navegable, y los clientes obtienen acceso de subtenant estrechamente acotado mediante entity views y asignaciones de dashboard.

Todo lo de aquí está acotado al tenant y se almacena en el namespace de Aerospike devices.

Un activo es una entity de primera clase que representa una agrupación lógica o física — un sitio, edificio, línea de producción, máquina, vehículo o medidor. Los activos viven en devices/assets, con clave {tenant_id}:{asset_id}, y contienen name, type, label, tags, metadata, status y version.

  • Nombre único por tipo por tenant. Crear un segundo site llamado “Factory 1” en un tenant que ya tiene uno se rechaza con ALREADY_EXISTS (y no se publica ningún evento). El mismo nombre bajo un tipo distinto está permitido.
  • Consultable por tipo y tag. Puedes listar activos filtrados por tipo y tag (p. ej. type=site, region=eu), paginados con next_page_token.
  • Soft delete. Eliminar un activo establece status="deleted"; queda excluido de las listas normales pero se conserva para auditoría y es recuperable con include_deleted=true, que devuelve deleted_at y deleted_by.

Crear un activo publica entity.asset.created.T1.{asset_id} y escribe un audit event.

Las relations conectan entidades — dispositivos, activos, clientes, dashboards y entity views — en un grafo dirigido. Cada relation tiene un type y una dirección, almacenada en devices/relations con clave {tenant_id}:{from_type}:{from_id}:{relation_type}:{to_type}:{to_id}.

Tipo de relationUso típico
containsUn activo contiene subactivos o dispositivos
managesUna entity gestiona otra
assigned_toUn dashboard asignado a un cliente/usuario
located_atUn dispositivo ubicado en un activo
monitorsUn dispositivo monitorea un target
depends_onUna arista de dependencia entre entidades

Crear A1 --contains--> D1 escribe un registro de relation, construye índices de búsqueda inversa (para que puedas consultar “dispositivos contenidos por A1”) y publica entity.relation.created.T1.A1.D1.

Para los tipos de relation donde los ciclos están prohibidos (como una jerarquía contains), el sistema rechaza las aristas que cerrarían un bucle. Si A1 contains A2, un intento de crear A2 --contains--> A1 se rechaza con FAILED_PRECONDITION y la respuesta identifica la ruta del ciclo, para que puedas ver exactamente qué aristas entran en conflicto.

Las relations son navegables en ambas direcciones y a lo largo de la profundidad. Pedir los descendientes de A1 filtrados a entity_type=device — dado A1 contains A2 y A2 contains D1, D2 — devuelve D1 y D2, cada uno con su ruta de relation de vuelta a A1. Esa ruta es lo que los dashboards y los nodos de enriquecimiento usan para renderizar y razonar sobre la jerarquía.

flowchart TD
  A1["Asset: Factory 1<br/>(site)"] -->|contains| A2["Asset: Line A<br/>(line)"]
  A1 -->|contains| A3["Asset: Line B<br/>(line)"]
  A2 -->|contains| D1["Device: Boiler 1"]
  A2 -->|contains| D2["Device: Boiler 2"]
  A3 -->|contains| D3["Device: Press 1"]
  D1 -.located_at.-> A2

Un cliente es una entity acotada al tenant que recibe acceso restringido — piensa en un cliente final de tu tenant que solo debería ver su propio equipamiento, nunca todo el tenant. Los clientes viven en devices/customers con clave {tenant_id}:{customer_id}.

Los usuarios de cliente son usuarios de autenticación con autoridad customer_user y una o más membresías de cliente. Su acceso es fundamentalmente más estrecho que el de un member:

Invitar a un usuario de cliente crea un usuario de autenticación con authority="customer_user", lo asigna al cliente, y audita la invitación.

Un entity view es el mecanismo que otorga a un cliente acceso a una porción específica de los datos de una entity — y nada más. Los views viven en devices/entity_views con clave {tenant_id}:{view_id} y contienen entity_type, entity_id, customer_id, field_mask, telemetry_key_allowlist, start_time, end_time y version.

Tres controles definen la porción:

  • field_mask — qué campos de la entity son visibles. Un view que enmascara la configuración y la clave de API significa que un cliente que lee el dispositivo D1 a través de él no ve configuración, ni clave de API, ni credenciales, ni metadatos internos, ni claves de telemetry no relacionadas.
  • telemetry_key_allowlist — qué métricas son legibles. Un view que permite ["temperature", "humidity"] deja que el cliente consulte solo esas claves para el dispositivo.
  • start_time / end_time — la ventana de validez.

Los dashboards se pueden asignar a clientes (y usuarios) con permiso view o edit mediante una relation assigned_to.

  1. Asignar. Asignar el dashboard DB1 al cliente C1 con permission="view" crea DB1 --assigned_to--> C1. Los usuarios de cliente de C1 ahora ven DB1 en su lista pero no pueden editarlo.

  2. Revocar. Revocar elimina la relation. Las sesiones WebSocket activas de C1 reciben de inmediato un evento dashboard_access_revoked, y las lecturas posteriores de la API de dashboard devuelven PERMISSION_DENIED.

Así que la revocación es en tiempo real: un visor en curso no mantiene el dashboard abierto hasta que refresque — a su sesión en vivo se le indica que pierda el acceso de inmediato.

Los activos, clientes, relations y entity views admiten todos soft delete con historial de auditoría. Eliminar un cliente es el caso más amplio: establece status="deleted", deshabilita las asignaciones y entity views del cliente, retira el acceso del usuario de cliente en su siguiente petición, y escribe un audit event que enumera los entity_view_ids y dashboard_ids deshabilitados. Las entidades eliminadas se conservan para auditoría y se excluyen de las consultas de lista por defecto.

flowchart LR
  cust["Customer C1"] -->|has| cu["Customer user CU1"]
  ev["Entity view EV1<br/>field_mask + allowlist + expiry"] -->|customer_id| cust
  ev -->|entity_id| dev["Device D1"]
  db["Dashboard DB1"] -->|assigned_to| cust
  cu -.reads through.-> ev
  cu -.sees.-> db

Un usuario de cliente alcanza datos únicamente a lo largo de estas aristas: a través de un entity view que nombra a su cliente y un dispositivo, o a través de un dashboard asignado a su cliente. Cualquier cosa fuera de esa ruta se deniega.