The invite system enables people to join circles and send invites to the app.
This supports invites by email, but includes a modular system that can have additional functionality added to it.

Invites exist as a collection in our backend. They match an identifier to the thing it’s inviting to, in our case a circle, as well as the status of the invite.

The identifier as of now is an email address. This works because our users collection enforces unique email addresses, so there is a one-to-one match between emails and users.

The identifier can be expanded to other fields, like a phone number, memberID or a random code we generate that could be included in a hyperlink.


Emails

The system can handle when a user does or doesn’t exist. When the circle admin goes to invite someone, they enter their email:

The confirmation message will adapt depending on whether there is already an account related to this email.

User ExistsNo User Found

The invite works exactly the same either way - aside from storing the existing user’s memberID in the invite if found.

An email is then sent to the email inviting them to join Tansy:

Because the invite email address is stored on our backend, nothing special is needed in this invite link. It is just a plain link to the app.


isInvited

When the user creates an account using the same email, the invite will be found and displayed to them in their account.

In order to show invite UI, the following frontend computed variable is calculated:

IsInvited

const isInvited = computed(() => {
	if (!props.circle.expand.invites_via_circle || !pb.authStore.record?.email) {
		return false;
	}
	return props.circle.expand.invites_via_circle.some((invite: any) =>
		invite.email === pb.authStore.record?.email && invite.accepted == false
	);
});

This checks if there are any invites related to the specific circle containing a matching email to the user’s auth account.

Even though their account is brand new, they will see the circle they have been invited to in their dashboard:

Circle permissions still enforce that they cannot see any information about the other circle members until they join.

They can accept/decline the invite to join/leave the circle.

A custom backend function is implemented in pb_hooks to verify that the current user is allowed to join the circle, and adds them.

This can be found at pocketbase/pb_hooks/records.pb.js and is located at the api route POST /api/v1/circles/join requiring the circleID as a body parameter and an authenticated account.


Status

The invite status is managed by 2 booleans in the collection: accepted and declined.

These states determine the backend permissions of the circle, for example an invite with declined status will not be able to view the related circle - so it will not load into their app dashboard anymore.

Invite status can be view in the circle details view by members of the circle, and can be revoked by the circle admin.