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.

Roles and Sharing

RoleCan do
ViewerOpen the document
CommenterView, add comments
EditorView, comment, edit
AdminEverything, 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");
Safe under concurrent use. The service guards its state with a lock and hands out snapshots, so callers cannot mutate internal state (for example to grant themselves a role) and concurrent comments, presence updates and queries cannot corrupt it. This is covered by 8-thread stress tests.

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).

MemberKindDescription
string IdPropertyGets or sets the id.
string DisplayNamePropertyGets or sets the display name.
string EmailPropertyGets or sets the email.
uint ColorPropertyGets or sets the color.

CollaborationSnapshot

Serializable collaboration state (users, shares, comments, audit). Presence is intentionally excluded — it is ephemeral.

MemberKindDescription
int VersionPropertyGets or sets the version.
List<UserRecord> UsersPropertyGets or sets the users.
List<DocumentShare> SharesPropertyGets or sets the shares.
List<DiagramComment> CommentsPropertyGets or sets the comments.
List<AuditEntry> AuditPropertyGets or sets the audit.

PresenceEntry

Live presence for a user on a document.

MemberKindDescription
string DocumentIdPropertyGets or sets the document id.
string UserIdPropertyGets or sets the user id.
DateTime LastSeenPropertyGets or sets the last seen.
string ActivityPropertyGets or sets the activity.

DocumentShare

Sharing state of a diagram document.

MemberKindDescription
string DocumentIdPropertyGets or sets the document id.
string OwnerIdPropertyGets or sets the owner id.
Dictionary<string, CollaborationRole> MembersPropertyMember roles (userId → role). The owner is always Admin.
bool IsPublicPropertyWhen true, any registered user can view the document.
override string ToString()Method

AuditEntry

An audit-trail entry for a collaboration action.

MemberKindDescription
string IdPropertyGets or sets the id.
string DocumentIdPropertyGets or sets the document id.
string UserIdPropertyGets or sets the user id.
string ActionPropertyGets or sets the action.
string DetailsPropertyGets or sets the details.
DateTime TimestampPropertyGets or sets the timestamp.
override string ToString()Method

CommentPin

A comment pin anchored to a component in the diagram.

MemberKindDescription
string ComponentIdPropertyComponent this pin is anchored to.
int IndexProperty1-based display number.
SKPoint PositionPropertyCenter of the pin in world coordinates.
SKRect ComponentBoundsPropertyBounds of the anchored component.
List<string> CommentIdsPropertyUnresolved comment ids anchored to this component.
int CommentCountPropertyGets or sets the comment count.
bool Contains(SKPoint point, float radius = CommentPinLayer.PinRadius)Method
override string ToString()Method