Table of Contents

User account synchronization technical architecture

General context

In a multi-cluster / multi-tenant architecture, a single tenant may have applications deployed across multiple application clusters (e.g., for scalability, regional separation, or high availability).

A user account often needs to be synchronized across all these clusters to ensure:

  • consistent user access,
  • uniform roles, permissions, and preferences,
  • propagation of updates to user profiles or access rights.

Synchronization Flow

User Creation, Update or Deletion

A user is added, modified or deleted via:

  • an admin interface (e.g., UserAccountUI),
  • a backend service (e.g., UserAccount),
  • indirect action (like assigning a cluster to a tenant or setting a user as administrator).

Event Publication via Pub/Sub

The originating service publishes an event to a shared topic, e.g., UserAccountSaved, using a message broker such as Dapr (backed by Redis or RabbitMQ):

{
  "payload": {
    "emittingClusterId": "tenants",
    "emittingClusterMultitenancyEnabled": false,
    "isTenantClientAdministrator": false,
    "messageTypeIsAboutUserRemoval": false,
    "receivingClusterIds": ["Northwind-0.0.1"],
    "roles": null,
    "tenantIdentifier": "IRIUM",
    "userAuthenticationIsSynchronized": true,
    "userEmail": "[email protected]",
    "userFirstName": "John",
    "userId": null,
    "userLastName": "Doe",
    "userLogin": "[email protected]",
    "userPhoneNumber": null,
    "userType": 0
  }
}

Message Transmission via the Broker

The event is received by all relevant clusters:

  • Dapr forwards the message to all subscribers of the UserAccountSaved topic,
  • Each cluster has a subscription server method UpsertUserAccounts.

Local Upsert in Each Cluster

Within each cluster:

  • The message is processed,
  • The user account is created, updated or deleted in the cluster’s local database (and distributed cache),
  • Local validation or provisioning logic may apply.

An account created automatically at the first login only holds default values, such as names derived from the email and the Client type. Its message is flagged with IsAutoCreated, so that a cluster which already knows the account keeps its names, phone number and type instead of overwriting them.

Why Synchronize?

Reason Explanation
✅ Availability Each cluster can operate independently with valid user data.
✅ Performance Reduces cross-cluster lookups for authentication or permissions.
✅ Business Consistency Ensures consistent access, roles, and user experiences.
✅ Security Enables global revocation or access changes across all clusters.

Risks to Manage

Risk Typical Solution
✖ Propagation delay Retries + Dead Letter Queues
✖ Message loss Logging + periodic reconciliation
✖ Data conflict Timestamp-based or source-priority conflict resolution
✖ Divergent account states Versioning or global user ID management

Flow Diagrams

UserPermissions module

flowchart TD
    subgraph Publishers
        P1["UserAccount<br/>(Saved)"]
        P2["UserAccountUserRole<br/>(Saved)"]
        P3["UserAccountMultiClusterView<br/>(Saved)"]
    end

    subgraph Broker
        RabbitMQ["Dapr/RabbitMQ"]
    end

    subgraph Topic
        TopicUserAccountSaved["Topic: UserAccountSaved"]
    end

    subgraph Subscribers
        S1["Cluster A<br/>UpsertUserAccounts<br/>(Controller)"]
        S2["Cluster B<br/>UpsertUserAccounts<br/>(Controller)"]
        S3["Cluster C<br/>UpsertUserAccounts<br/>(Controller)"]
    end

    P1 -->|Publish Event| RabbitMQ
    P2 -->|Publish Event| RabbitMQ
    P3 -->|Publish Event| RabbitMQ

    RabbitMQ --> TopicUserAccountSaved
    TopicUserAccountSaved -->|Distribute Event| S1
    TopicUserAccountSaved -->|Distribute Event| S2
    TopicUserAccountSaved -->|Distribute Event| S3

Components represented:

Publishers:
  • Saved event of the UserAccount entity.
  • Saved event of the UserAccountUserRole entity.
  • Saved event of the UserAccountMultiClusterView entity view.
Broker:
  • Dapr using RabbitMQ as pub/sub middleware.
Topic:
  • UserAccountSaved, logical event distribution channel.
Subscribers:
  • UpsertUserAccounts subscription server method (an application-side controller method).

Tenants module

Flow diagram

flowchart TD
    subgraph Publisher
        P1["UserTenant<br/>(Saved)"]
        P2["DataPersistenceListView<br/>(Saved)"]
        P3["AddAdministratorToTenantClusters<br/>(ServerMethod)"]
    end

    subgraph Broker
        RabbitMQ["Dapr/RabbitMQ"]
    end

    subgraph Topic
        TopicUserAccountSaved["Topic: UserAccountSaved"]
    end

    subgraph Subscribers
        S1["Cluster A<br/>UpsertUserAccounts<br/>(Controller)"]
        S2["Cluster B<br/>UpsertUserAccounts<br/>(Controller)"]
        S3["Cluster C<br/>UpsertUserAccounts<br/>(Controller)"]
    end

    P1 -->|Publish Event| RabbitMQ
    P2 -->|Publish Event| RabbitMQ
    P3 -->|Publish Event| RabbitMQ

    RabbitMQ --> TopicUserAccountSaved
    TopicUserAccountSaved -->|Distribute Event| S1
    TopicUserAccountSaved -->|Distribute Event| S2
    TopicUserAccountSaved -->|Distribute Event| S3
Components represented:
Publishers:
  • Saved event of the UserTenant entity.
  • Saved event of the DataPersistenceListView entity view.
  • AddAdministratorToTenantClusters server method.
Broker:
  • Dapr using RabbitMQ as pub/sub middleware.
Topic:
  • UserAccountSaved, logical event distribution channel.
Subscribers:
  • UpsertUserAccounts, subscription server method (an application-side controller method).

UML Sequence Diagram — User Accounts Synchronization

Description

This diagram illustrates the event-driven process of synchronizing user accounts between Business Clusters through a message bus.

Participants

  • Actor: Administrator
  • Main System: Emitting Cluster (Publisher)
  • Subscribed Systems: Business Clusters (Subscribers)
  • Middleware: Message Bus (Dapr/RabbitMQ)

Sequence Diagram

sequenceDiagram
    actor Admin
    participant UserAccountUI
    participant PubCluster as Emitting Cluster
    participant PubDB as Emitting Cluster DB
    participant Bus as Message Bus
    participant BizCluster as Business Cluster
    participant BizDB as Business Cluster DB

    %% User initiates creation or update
    Admin ->> UserAccountUI: Create or update UserAccount
    UserAccountUI ->> PubCluster: Send POST /UserAccountView
    PubCluster ->> PubDB: Save UserAccount entity
    PubDB -->> PubCluster: Confirm entity saved
    PubCluster ->> Bus: Publish event "UserAccountSaved"

    %% Event propagation to business clusters
    Note over Bus: Event distributed to all subscribed clusters

    Bus ->> BizCluster: Deliver "UserAccountSaved" message
    BizCluster ->> BizCluster: Execute UpsertUserAccounts server method
    BizCluster ->> BizDB: Create or update UserAccount
    BizDB -->> BizCluster: Acknowledgment (OK)

Flow Summary

  1. The Administrator creates or updates a UserAccount via the UserAccountUI.
  2. The Emitting Cluster saves the entity in its database.
  3. Upon a successful save, an event UserAccountSaved is published to the Message Bus.
  4. Subscribed Business Clusters receive this event.
  5. Each Business Cluster processes the event by calling UpsertUserAccounts server method.
  6. The corresponding UserAccount is created or updated in the Business Cluster Database.
  7. Synchronization across clusters is completed successfully.

Key Takeaways

  • Event-driven synchronization ensures loose coupling between clusters.
  • Business clusters remain autonomous while maintaining data consistency.
  • The system is scalable — new clusters can subscribe to UserAccountSaved without changing the producer code.