Tenancy & identity
Use the subscriber organization for billing and the verified principal for data ownership.
Every customer tenancy is a subscriber organization, including a solo user. Plans, subscriptions, billing, entitlements, and business-level limits attach to that organization.
Inside it, requests carry a verified principal:
- a member principal identifies a person;
- a service principal identifies an organization-owned machine credential.
Do not trust customer-supplied organization or user ids in headers or request bodies. Verify the Farther Shore runtime context in the backend SDK and derive ownership from the signed principal.
Shared-workspace data
Key shared rows by the verified subscriber/organization identifier. Every query must include that key, even when another id appears globally unique.
// ctx comes from fs.handler() after fs.middleware() verifies the request.
const projects = await db.project.findMany({
where: { orgId: ctx.principal.org.id },
});
This keeps billing, entitlements, and the backend's data boundary aligned.
Per-member data
For private rows inside the organization, include both boundaries:
import { requireMember } from "@farthershore/backend";
const member = requireMember(ctx);
const documents = await db.document.findMany({
where: {
orgId: ctx.principal.org.id,
ownerMemberId: member.memberId,
},
});
Require a member subject on routes that need memberId:
fs.route("/v1/me/documents", {
get: { requireMember: true },
});
Create user state on demand
Identity and webhook delivery can race with the first API request. Do not make a webhook the prerequisite for a user row. Use a database unique key on the verified identity and an atomic upsert/find-or-create path on first use.
See Storing per-user data for the transaction and retry pattern.
Collaboration
Sharing a row is a domain authorization rule in your backend. Store an explicit membership or ACL keyed by verified member ids and scope it to the subscriber. Managed RBAC answers whether a member may call an operation; it does not decide which individual document that operation may return.
Avoid boundary confusion
- Builder organizations own Farther Shore businesses; subscriber organizations buy and use one business. They are different domains.
- A plan grant is subscriber-wide; managed RBAC narrows member operations.
- A service credential is not a person and has no member id.
- Environment ids route preview data and configuration; they are not customer tenancy ids.
If production and previews share a database, isolate their rows or databases explicitly as well. Organization scoping alone is not an environment isolation strategy. Test with two organizations and two members: changing a body, URL, or query parameter to another owner's id must never widen the verified scope.