Skip to content

Matrix Integration Entity Relationships

This diagram describes the planned data model for the Drupal–Matrix integration. It combines the schemas already implemented in the Matrix API Entity and Matrix API Identity modules with the room-management entities planned for Matrix API Application Server.

Drupal remains the source of truth for content, identity, group membership, and business rules. Matrix is the communication layer. Matrix events are not copied into Drupal in full; Drupal stores only the identifiers needed to map rooms, messages, threads, and users back to Drupal entities.

erDiagram
  DRUPAL_GROUP {
    int id PK "Group entity ID"
    string label "Group name"
  }

  DRUPAL_NODE {
    int nid PK "Content entity ID"
    string bundle "Content type"
  }

  DRUPAL_COMMENT {
    int cid PK "Comment entity ID"
    int entity_id FK "Commented entity ID"
    int pid FK "Parent comment ID, if threaded"
    int uid FK "Drupal author"
  }

  DRUPAL_USER {
    int uid PK "Drupal user ID"
  }

  MATRIX_IDENTITY_MAP {
    int uid PK, FK "Drupal user ID"
    string matrix_id UK "Matrix user ID"
    string source "idp or declared"
    int linked_at "Unix timestamp"
  }

  MATRIX_USER {
    string matrix_id PK "External Matrix user ID"
  }

  MATRIX_SPACE {
    int id PK "Drupal content entity ID"
    string room_id UK "Matrix space room ID"
    string room_alias UK "Canonical alias"
    string parent_space_id FK "Optional parent space"
    string drupal_entity_type "Attached entity type"
    int drupal_entity_id "Attached entity ID"
  }

  MATRIX_ROOM_TYPE {
    string id PK "Config entity machine name"
    string label "Human-readable label"
    string alias_suffix "Group alias suffix"
    json default_power_levels "Power-level template"
    boolean inbound_sync "Matrix to Drupal enabled"
    boolean outbound_sync "Drupal to Matrix enabled"
    json privileged_accounts "Matrix IDs and levels"
    json widgets "Widget definitions"
  }

  MATRIX_ROOM {
    int id PK "Drupal content entity ID"
    string room_id UK "Matrix room ID"
    string room_alias UK "Canonical alias"
    string room_type FK "Room type config entity"
    int room_version "Matrix room version"
    string adoption_state "Lifecycle state"
    string predecessor_room_id FK "Replaced room ID"
    string drupal_entity_type "Attached entity type"
    int drupal_entity_id "Attached entity ID"
  }

  MATRIX_EVENT {
    string event_id PK "External Matrix event ID"
    string room_id FK "Matrix room ID"
    string sender FK "Matrix user ID"
    string thread_root_event_id FK "Optional thread root"
    string reply_to_event_id FK "Optional direct reply parent"
  }

  MATRIX_EVENT_MAP {
    string entity_type PK "Drupal entity type"
    int entity_id PK "Drupal entity ID"
    string event_id "Indexed Matrix event ID"
    string room_id "Matrix room ID"
    int created "Unix timestamp"
  }

  PROCESSED_TRANSACTION {
    string transaction_id PK "Synapse transaction ID"
    int expires_at "Deduplication expiry"
  }

  DRUPAL_GROUP ||--o{ DRUPAL_NODE : contains
  DRUPAL_NODE ||--o{ DRUPAL_COMMENT : receives
  DRUPAL_COMMENT o|--o{ DRUPAL_COMMENT : parent_of

  DRUPAL_USER ||--o| MATRIX_IDENTITY_MAP : has
  MATRIX_USER ||--o| MATRIX_IDENTITY_MAP : identifies
  MATRIX_USER ||--o{ MATRIX_EVENT : sends

  DRUPAL_GROUP ||--o| MATRIX_SPACE : represented_by
  MATRIX_SPACE o|--o{ MATRIX_SPACE : contains_subspace
  MATRIX_SPACE ||--o{ MATRIX_ROOM : contains
  MATRIX_ROOM_TYPE ||--o{ MATRIX_ROOM : configures
  MATRIX_ROOM o|--o| MATRIX_ROOM : replaces

  MATRIX_ROOM ||--o{ MATRIX_EVENT : contains
  MATRIX_EVENT o|--o{ MATRIX_EVENT : thread_root_for
  MATRIX_EVENT o|--o{ MATRIX_EVENT : reply_parent_for
  MATRIX_EVENT ||--o| MATRIX_EVENT_MAP : indexed_as

  DRUPAL_NODE ||--o| MATRIX_EVENT_MAP : maps_when_node
  DRUPAL_COMMENT ||--o| MATRIX_EVENT_MAP : maps_when_comment
Entity or recordDrupal storageOwning moduleStatus
MATRIX_EVENT_MAPmatrix_event_map database tableMatrix API EntityImplemented
MATRIX_IDENTITY_MAPmatrix_identity_map database tableMatrix API IdentityImplemented
Declared Matrix IDConfigurable field on the Drupal user entityMatrix API IdentityImplemented
Application-service settingsDrupal configuration; secrets reference Key entitiesMatrix API Application ServerImplemented
PROCESSED_TRANSACTIONExpiring Drupal key-value collectionMatrix API Application ServerImplemented
MATRIX_ROOMDrupal content entityMatrix API Application ServerPlanned
MATRIX_SPACEDrupal content entityMatrix API Application ServerPlanned
MATRIX_ROOM_TYPEDrupal config entityMatrix API Application ServerPlanned
MATRIX_EVENT and MATRIX_USERMatrix homeserver, not DrupalMatrixExternal

matrix_event_map is a polymorphic join from a Drupal entity to its canonical Matrix event:

  • A node maps to the Matrix message that starts its thread.
  • A comment maps to the Matrix event representing its thread reply.
  • The composite primary key, (entity_type, entity_id), permits one canonical Matrix event per Drupal entity.
  • event_id supports inbound lookup and loop prevention.
  • room_id records the room in which the event was sent.

The links from MATRIX_EVENT_MAP to DRUPAL_NODE and DRUPAL_COMMENT are logical, not database foreign keys. Exactly one applies according to entity_type. This follows Drupal’s polymorphic entity-reference pattern.

A Matrix thread can carry both relationships needed to reproduce Drupal comment threading:

  • thread_root_event_id resolves through matrix_event_map to the Drupal node.
  • reply_to_event_id resolves through matrix_event_map to the parent Drupal comment. If it does not resolve, Drupal creates a top-level comment.

matrix_identity_map is one-to-one in both directions:

  • uid is the primary key, so one Drupal account has at most one active Matrix identity.
  • matrix_id is unique, so one Matrix identity cannot represent multiple Drupal accounts.
  • source records whether the mapping came from authoritative IDP provisioning or a user-declared profile field.

Rooms and spaces are planned as Drupal content entities because they have an operational lifecycle and need administrative listings. They are not deployment configuration.

drupal_entity_type plus drupal_entity_id forms another polymorphic logical reference. It allows a Matrix room or space to represent a Group, node, taxonomy term, or another supported Drupal entity without coupling the generic application-service module to a specific Group implementation.

A room type is deployment configuration. It defines synchronization policy, power levels, privileged bot accounts, alias conventions, and widgets for every room using that type.

Constraints to finalize during implementation

Section titled “Constraints to finalize during implementation”

The following constraints are part of the intended model but are not all present in the current prototype schema:

  1. matrix_event_map.event_id should be unique, not merely indexed. A Matrix event must not map to more than one Drupal entity.
  2. matrix_event_map.room_id should be indexed for room-scoped operations.
  3. matrix_room.room_id and matrix_space.room_id must be globally unique across both entity types because Matrix spaces are also Matrix rooms.
  4. A room or space attachment must validate that the (drupal_entity_type, drupal_entity_id) pair identifies an existing entity.
  5. Room replacement must preserve predecessor history without allowing cycles.
  6. Deleting Drupal content should redact or retain its Matrix event according to policy before removing the event mapping.
  • Matrix API provides the Matrix client, inbound-event plugin system, ECA events/actions, and Matrix event value objects.
  • Matrix API Entity owns Drupal entity ↔ Matrix event mapping and bidirectional content synchronization.
  • Matrix API Identity owns Drupal user ↔ Matrix user mapping and power-level policy integration.
  • Matrix API Application Server receives Synapse transactions and owns room and space lifecycle management.
  • Matrix Recipes provides installation recipes and example ECA models; it does not own persistent integration data.