← Back to Next.js SaaS foundation team

Skill · Version 1.0.0

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

See how it helps

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.

Details…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_at window (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.
  • Multi-Workspace Membership:
    • A single user_id can hold memberships in multiple workspaces simultaneously with a distinct role in each (owner in Workspace A, viewer in Workspace B). Never store workspace_id or role as a single scalar column on the users table!

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 workspaceId in 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 last owner from 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