MemberPulse
IntegrationsBackendConvex

Tenant Scoping

Isolation strategy for multi-tenant MemberPulse on Convex

Even though MemberPulse is conceptually "single tenant per organization", this Convex implementation assumes a shared Convex deployment with strict isolation.

Rule: every tenant-owned record has clientId

All tables that store tenant data must include:

clientId: v.id("clients")

Examples: memberProfiles, events, courses, resources, supportTickets, orders, crmSyncRecords.

Authorization pattern

All queries/mutations must:

  1. derive the caller identity (auth)
  2. resolve which clientId they are allowed to access
  3. scope the query by clientId (and/or validate the target document belongs to clientId)

Index requirements

Convex performance depends on indexes. Tenant-scoped lists should have at least:

  • by_clientId
  • by_clientId_status
  • by_clientId_createdAt

depending on the screen.

Preventing cross-tenant references

Any time you write a reference (e.g., memberProfileId, eventId), validate:

  • referenced doc exists
  • referenced doc has the same clientId

This check belongs in server-side mutations.

Features

Tenant Scoping

Acceptance Criteria

Frontend
  • Developer-facing configuration and usage is documented and internally consistent.
Backend / API
  • Convex implementation matches the rules and contracts described on this page.
Permissions
  • Tenant scoping and access controls are enforced as described.
Business Rules
  • Domain rules/invariants are enforced as described.
Error Handling
  • Access violations and validation failures produce deterministic errors.

On this page