--- layout: learn permalink: /:collection/:path.html --- # Collaborate with groups {:.no_toc} A key feature of Radiks is support for private collaboration between multiple users. Supporting collaboration with client-side encryption and user-owned storage can be complicated but the patterns to implement it are generally the same among most applications. Radiks provides out-of-the box for collaboration, making it easy to build private, collaborative apps. You use the UserGroup class to build a collaborative group with Radiks. In this section, you learn about this class. * TOC {:toc} ## Understand the UserGroup workflow The key model behind a collaborative group is `UserGroup`. By default, it only has one attribute, `name`, which is encrypted. You can subclass `UserGroup` with different attributes as needed. The general workflow for creating a collaborative group that can share and edit encrypted models is as follows: 1. The admin of the group creates a new `UserGroup`. This group acts as the 'hub' and controls the logic around inviting and removing users. 2. The admin invites one or more other users to a group: * The admin specifies the username of the user they want to invite * Radiks looks up the user's public key * Radiks creates an 'invitation' that is encrypted with the user's public key, and contains information about the `UserGroup` 3. When the invited user 'activates' an invitation, they create a `GroupMembership`. They use this membership instance to reference information (such as private keys and signing keys) related to the group. As they participate in a group, the group's members can create and update models that are related to the group. These models **must** contain a `userGroupId` attribute used to reference the group. This allows Radiks to know which keys to use for encryption and signing. When needed, the group admin can remove a user from a group. To remove a user from the group, the admin creates a new private key for signing and encryption. Then, the admin updates the `GroupMembership` of all users _except_ the user they just removed. This is also known as rotating the key. After a key is rotated, all new and updated models must use the new key for signing. Radiks-server validates all group-related models to ensure that they're signed with the most up-to-date key. ## Work with a UserGroup This section details the methods on the UserGroup class you can use to create, add members to, and query a group. ### Create a UserGroup To create a `UserGroup`, your application must import the class from `radiks`: ```javascript import { UserGroup } from 'radiks'; // ... ``` Calling `create` on a new `UserGroup` will create the group and activate an invitation for the group's creator. ```javascript const group = new UserGroup({ name: 'My Group Name' }); await group.create(); ``` A group's creator is also the group's admin. ### Invite users to become members Use the `makeGroupMembership` method on a `UserGroup` instance to invite a user. The only argument passed to this method is the user's `username`. ```javascript import { UserGroup } from 'radiks'; const group = await UserGroup.findById(myGroupId); const usernameToInvite = 'hankstoever.id'; const invitation = await group.makeGroupMembership(usernameToInvite); console.log(invitation._id); // the ID used to later activate an invitation ``` ### Accept an invitation Use the `activate` method on a `GroupInvitation` instance to activate an invitation on behalf of a user: ```javascript import { GroupInvitation } from 'radiks'; const invitation = await GroupInvitation.findById(myInvitationID); await invitation.activate(); ``` ## View all activated UserGroups for the current user Call `UserGroup.myGroups` to fetch all groups that the current user is a member of: ```javascript import { UserGroup } from 'radiks'; const groups = await UserGroup.myGroups(); ``` ## Find a UserGroup Use the method `UserGroup.find(id)` when fetching a specific UserGroup. This method has extra boilerplate to handle decrypting the model, because the private keys may need to be fetched from different models. ```javascript const group = await UserGroup.find('my-id-here'); ```