Tenants, seats and access in an App: depth
How a Customer's Tenant, each person's seat and each Persona's Access level decide what an App renders and what the Offer charges, in the design.
In the design, every person who signs in to an App works inside one Customer's Tenant, holds one seat, and acts through one Access Level. The Tenant bounds which records exist, the Access level bounds what renders, and the Offer counts the seat.
One Tenant per Customer
A Tenant is the part of a Startup's data that belongs to one Customer. Tenancy gives each one its own path, keys and Limits, and no query crosses Tenants.
In the design, an App adds nothing to that partition. Each list, picker and count reads from the signed-in person's Tenant, by the rule tenant-scope.
On leaseclock.com, Harbor Property Group is one Customer with the Tenant harbor. Its manager sees Harbor's 12 leases and never another company's, at api.sb/leaseclock.com/harbor and in the App alike. A person who belongs to two Tenants switches between them with a TenantSwitcher in the App's header.
Sign-in and the seat
A person reaches a Tenant by invitation, then signs in with a passkey, an email link or their company's single sign-on, as Auth and Let customers sign in describe. In the design, the invitation names one Persona, and the Persona names the Access level.
Each person who accepts holds one seat. The Offer's seats key decides how seats count against what the Customer pays.
---
price: { amount: 12, currency: USD }
interval: month
seats: members
---seats | An accepted invitation | The members screen shows |
|---|---|---|
members | adds a seat, prorated into the current period on Stripe | seats used, which equals seats paid |
manual | past the bought quantity, asks someone holding admin to buy a seat | seats used against seats paid |
Harbor's manager invites an assistant on team. The Stripe quantity on Harbor's Subscription moves from 1 to 2, and the members screen (members) reads 2 of 2. Plans inside your App covers what a seat unlocks; Charge per seat is the ask.
What each Access level renders
The registry presets four Access levels. In the design, each one bounds the screens a Persona gets for the same Noun.
| Access level | Grants | Lease screens | Members screen |
|---|---|---|---|
owner | every Verb on every Noun, one-way Verbs included | list, record page, both forms, Renew, Terminate | invite, remove, change Access levels |
admin | read every Noun, every two-way change, access included | list, record page, both forms, Renew, Terminate | invite, remove, change Access levels |
member | read every Noun, two-way changes except to the Nouns that decide access | list, record page, both forms, Renew, Terminate | read only |
viewer | read every Noun, change nothing | list and record page | read only |
A Permission narrows a preset further. Granting the assistant Lease.renew alone, with no Lease.terminate, leaves the Terminate button off every screen the assistant sees. App per Persona: derivation rules lists each rule that reads these grants.
Where the check runs
In the design, the Verb checks the caller's Permissions on every call, from any Interface. A screen only leaves out what that check refuses, so a missing button never stands in for a refusal. Permissions sets out the check.
Two facts keep this a design.
- The Admin runs a Verb's rules in the browser, so
api-enforces-permissionswaits. - The registry defines an Access Level as a preset a Worker holds. Harbor's assistant is a person at a Customer, not a Worker of leaseclock.com, so no seat holder has an Access level to read.
App per Persona: derivation rules
The design rules that turn each Persona and its Access level into lists, forms, approval cards, a usage panel and an ask control for a Customer's people.
Flows: depth
How a Flow takes one Persona from first sign-in to an Offer's activation Event, with at most five onboarding questions, shown on leaseclock.com.