Most B2B applications have a concept of a tenant which is separate from the concept of a user. LetsGo has first-class support for modeling tenants and users and their relationships, along with related concepts like subscription plans and invitations.
A tenant is a unit of organization specific to the customer of the app. The concept may have different names depending on the domain of the app, for example, a team__, a _project, an organization, or a workspace.
A user of the app has a unique identity from the authentication perspective. In practical terms, in the context of accessing the app's functionality through the browser, a user is a physical human being.
A tenant may have multiple users. This represents a situation where multiple users have access to the same project, workspace, or team, and is a frequent pattern in B2B apps.
A user in turn may have access to multiple tenants. For example, Fubar and Fubaz are companies that are customers of your app. They are different tenants in your system. Now, John is a contractor who works for both Fubar and Fubaz. John is a user in our app who can access either tenant Fubar or tenant Fubaz. The way this manifests itself in the UI presented to the user in the web component is via the tenant selector dropdown:
LetsGo also helps you manage subscription plans. In the LetsGo model, a tenant is at all times associated with a specific plan which describes the parameters of the service the app offers to that tenant. A plan may be a freemium plan or a paid plan associated with a Stripe subscription.
LetsGo supports an invitation mechanism using which one user with access to a specific tenant can invite another user. By accepting the invitation, the other user also gains access to the tenant.
sequenceDiagram
participant U1 as User 1
participant U2 as User 2
participant S as API server
participant D as Database
U1-->>S: POST /v1/tenant/ten-123/invitation<br>Authorization: Bearer {accessToken}
S-->>D: PUT ten-123/inv-345
S-->>U1: HTTP 200<br>inv-345
U1-->>U2: invitation link with ten-123/inv-345
U2-->>S: POST /v1/tenant/ten-123/invitation/inv-345/accept<br><br>Authorization: Bearer {accessToken}
S-->>D: DELETE ten-123/inv-345<br>PUT ten-123/usr-U2<br>PUT usr-U2/ten-123
S-->>U2: HTTP 200
U2-->>S: GET /v1/me<br>Authorization: Bearer {accessToken}
S-->>D: LIST /usr-U2/*
S-->>U2: HTTP 200<br>{ ..., tenants: [ "ten-123" ] }
NOTE For clarity of the illustration, the diagram above omits the browser component that intermediates between the users and the API server.
In the first step, user U1 with access to tenant ten-123 calls the API to create an invitation. The server generates a random initation Id and stores it in the database associated with tenant ten-123. The invitations are stored with a TTL so that they automatically expire if not used within 24h. The server returns the generated invitation Id inv-456 to user U1.
User U1 forms an invitation link that directs the browser to the web component and sends it over to user U2 using proprietary channels (e-mail, Slack).
User U2 navigates to the invitation link in the browser and is asked to log in. Then, he sends a request to the API server to accept the invitation. The API server validates the invitation still exists in the database and then creates the association between user U2 and tenant ten-123 in the database.
In the last step, the new user U2 calls the /v1/me
endpoint on the API server, which looks up the database to determine the list of tenants to which user U2 has access and returns that list in the response.
Read more about the relationship between tenants and subscription plans in Manage the pricing model.
LetsGo maintains a number of database categories to support the tenancy model. You can read more about in System database categories.
LetsGo also implements a number of HTTP APIs in the API component in support of the tenancy model. You can read more about in Develop the API.
Develop the API
System database categories
Authentication, authorization, and trust