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
UserAccountSavedtopic, - 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:
Savedevent of theUserAccountentity.Savedevent of theUserAccountUserRoleentity.Savedevent of theUserAccountMultiClusterViewentity view.
Broker:
- Dapr using RabbitMQ as pub/sub middleware.
Topic:
UserAccountSaved, logical event distribution channel.
Subscribers:
UpsertUserAccountssubscription 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:
Savedevent of theUserTenantentity.Savedevent of theDataPersistenceListViewentity view.AddAdministratorToTenantClustersserver 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
- The Administrator creates or updates a
UserAccountvia theUserAccountUI. - The Emitting Cluster saves the entity in its database.
- Upon a successful save, an event
UserAccountSavedis published to the Message Bus. - Subscribed Business Clusters receive this event.
- Each Business Cluster processes the event by calling
UpsertUserAccountsserver method. - The corresponding
UserAccountis created or updated in the Business Cluster Database. - 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
UserAccountSavedwithout changing the producer code.