Collaboration
Sharing, review comments, presence and audit for diagram documents
Collaboration adds the multi-user story to a diagram: who may do what, what reviewers said, and who is working on the document right now.
Table of Contents
Roles and Sharing
| Role | Can do |
|---|---|
| Viewer | Open the document |
| Commenter | View, add comments |
| Editor | View, comment, edit |
| Admin | Everything, including granting and revoking access |
var collaboration = new CollaborationService();
collaboration.RegisterUser(new CollaborationUser { Id = "alice", DisplayName = "Alice" });
collaboration.RegisterUser(new CollaborationUser { Id = "bob", DisplayName = "Bob" });
collaboration.Share("diagram", ownerId: "alice", ("bob", CollaborationRole.Commenter));
collaboration.Grant("diagram", requesterId: "alice", userId: "bob", role: CollaborationRole.Editor);
collaboration.SetPublic("diagram", requesterId: "alice", isPublic: true); // read-only link
Comments and Pins
Comments can be anchored to a component, which makes them review notes rather than chat. Anchored comments are drawn
as numbered pins on the component's corner through CommentPinLayer, and resolved comments disappear from the
canvas.
var comment = collaboration.AddComment("diagram", "bob", "This step needs a guard", "DecisionNode");
collaboration.ResolveComment("diagram", comment.Id, "alice");
// pins follow component geometry automatically
pinLayer.Rebuild(manager.GetComponents(), collaboration.GetComments("diagram"));
pinLayer.Draw(canvas);
Presence
Presence records who is active on a document and what they are doing. Entries expire automatically, so a crashed client does not appear online forever:
collaboration.SetPresence("diagram", "bob", "editing");
foreach (var entry in collaboration.GetPresence("diagram", TimeSpan.FromMinutes(2)))
Console.WriteLine($"{entry.UserId} {entry.Activity} ({entry.LastSeen:HH:mm:ss})");
Audit Trail
Every share, grant, revoke, comment and resolve is recorded with the user and timestamp, which gives reviewers a history of the document's access and review decisions.
Persistence
Collaboration state is saved next to the diagram with CollaborationSerializer. Presence is intentionally
excluded (it is ephemeral); everything else — users, shares, comments, audit — round-trips.
CollaborationSerializer.Save(collaboration, "diagram.collaboration.json");
var restored = CollaborationSerializer.Load("diagram.collaboration.json");
Collaboration Types
Review data is stored as plain records so it can be persisted and audited: users and shares, presence, comment pins and the audit trail.
UserRecord
JSON-friendly user record (color stored as 0xAARRGGBB).
| Member | Kind | Description |
|---|---|---|
string Id | Property | Gets or sets the id. |
string DisplayName | Property | Gets or sets the display name. |
string Email | Property | Gets or sets the email. |
uint Color | Property | Gets or sets the color. |
CollaborationSnapshot
Serializable collaboration state (users, shares, comments, audit). Presence is intentionally excluded — it is ephemeral.
| Member | Kind | Description |
|---|---|---|
int Version | Property | Gets or sets the version. |
List<UserRecord> Users | Property | Gets or sets the users. |
List<DocumentShare> Shares | Property | Gets or sets the shares. |
List<DiagramComment> Comments | Property | Gets or sets the comments. |
List<AuditEntry> Audit | Property | Gets or sets the audit. |
PresenceEntry
Live presence for a user on a document.
| Member | Kind | Description |
|---|---|---|
string DocumentId | Property | Gets or sets the document id. |
string UserId | Property | Gets or sets the user id. |
DateTime LastSeen | Property | Gets or sets the last seen. |
string Activity | Property | Gets or sets the activity. |
DocumentShare
Sharing state of a diagram document.
| Member | Kind | Description |
|---|---|---|
string DocumentId | Property | Gets or sets the document id. |
string OwnerId | Property | Gets or sets the owner id. |
Dictionary<string, CollaborationRole> Members | Property | Member roles (userId → role). The owner is always Admin. |
bool IsPublic | Property | When true, any registered user can view the document. |
override string ToString() | Method |
AuditEntry
An audit-trail entry for a collaboration action.
| Member | Kind | Description |
|---|---|---|
string Id | Property | Gets or sets the id. |
string DocumentId | Property | Gets or sets the document id. |
string UserId | Property | Gets or sets the user id. |
string Action | Property | Gets or sets the action. |
string Details | Property | Gets or sets the details. |
DateTime Timestamp | Property | Gets or sets the timestamp. |
override string ToString() | Method |
CommentPin
A comment pin anchored to a component in the diagram.
| Member | Kind | Description |
|---|---|---|
string ComponentId | Property | Component this pin is anchored to. |
int Index | Property | 1-based display number. |
SKPoint Position | Property | Center of the pin in world coordinates. |
SKRect ComponentBounds | Property | Bounds of the anchored component. |
List<string> CommentIds | Property | Unresolved comment ids anchored to this component. |
int CommentCount | Property | Gets or sets the comment count. |
bool Contains(SKPoint point, float radius = CommentPinLayer.PinRadius) | Method | |
override string ToString() | Method |