Workspace membership lifecycle
Keeps workspace access correct throughout invitations, switching, ownership transfer and member removal, including simultaneous browser tabs.
memberships-workspace-lifecycle
Team members using this skill
When is it useful?
Use it when people belong to several workspaces or access changes while requests and sessions remain active.
What does it help you do?
- Models invitation acceptance, expiration and membership revocation.
- Uses explicit workspace targets to prevent cross-tab mistakes.
- Protects the last owner and clears state when switching workspaces.
Try asking this
Test two browser tabs in different workspaces while a member loses access. Revoke membership while both tabs remain open. Each request must use its explicit workspace, and the removed member must lose access without changing the other tab's target.
Detailed documentation
Read the skill’s original instructions, examples and checks in their authored language.
Show less
Memberships & Workspace Lifecycle
When to Use
Use when implementing or reviewing user–workspace memberships, invitation flows, active workspace switching, ownership transfer, member removal, or workspace suspension/deletion.
1. Membership & Invitation State Machine
Model workspace_memberships and workspace_invitations with explicit states and invariants:
- Invitation Security:
- Store only a cryptographic hash (
SHA-256) of the single-use invitation token in the database, never the raw token. - Enforce a strict
expires_atwindow (e.g., 7 days), revocation (revoked_at), and idempotent handling if an already-accepted invite link is clicked twice. - Identity / Email Binding: Verify that the authenticated user accepting the invite matches the invited target email/identity (or require explicit re-authentication) so a forwarded invite link cannot bind an unintended account.
- Store only a cryptographic hash (
- Multi-Workspace Membership:
- A single
user_idcan hold memberships in multiple workspaces simultaneously with a distinct role in each (ownerin Workspace A,viewerin Workspace B). Never storeworkspace_idorroleas a single scalar column on theuserstable!
- A single
2. Multi-Tab & Active Workspace Switching
- Storing "current workspace" purely in a mutable server session or shared cookie causes multi-tab cross-workspace overwrite: if Tab 1 is open on Workspace A and the user switches Tab 2 to Workspace B, a subsequent save in Tab 1 silently mutates Workspace B!
- Best Practice: Include the explicit target
workspaceIdin the route path (/w/:workspaceId/...), request header (X-Workspace-Id), or payload of every workspace-scoped request, and verify membership on every call. - On client-side workspace switch, abort in-flight queries and purge client-side query caches (
QueryClient.clear()/ Pinia / Redux store reset), realtime WebSocket subscriptions, and draft state from the previous workspace.
3. Ownership Invariants & Safe Owner Transfer
- Zero-Orphan Rule: Every active workspace must have at least one active
owner. Block the lastownerfrom leaving, being removed, or downgrading their own role unless ownership is transferred first or the workspace itself is being deleted. - Two-Step Ownership Transfer: Require an existing owner to initiate the transfer to an active workspace member and record an immutable audit event upon completion.
4. Membership Revocation & Immediate In-Flight Effect
When a member is suspended or removed from a workspace (or their role is downgraded):
- Immediately reject subsequent API requests for that
(user_id, workspace_id)pair—never rely on a long-lived JWT claim (workspaces: [...]) without checking current membership state or token revocation version. - Close active WebSocket/SSE streams for that workspace and define what happens to scheduled/delayed jobs, personal API tokens, and resources created by the removed member (transfer ownership of workspace artifacts to the workspace, not the departing user's personal account).
5. Workspace Suspension & Deletion Lifecycle
Separate workspace lifecycle states (active $\rightarrow$ suspended $\rightarrow$ pending_deletion $\rightarrow$ deleted):
- Suspended: Block mutations, pause recurring background jobs/webhooks, and restrict access to billing/recovery admins while preserving data intact.
- Pending Deletion / Deleted: Cancel external subscriptions/webhooks, purge files/caches/search indexes, and enforce a documented retention grace period before irreversible purge.
Included files 1
SKILL.md
