Tenant isolation (why rows have tenantId / organizationId)
Every customer sees only their rows because queries filter by tenant or organization.
Difficulty 3/5
Plain English
Agentify uses tenantId + getTenantUser. Jmcon uses organizationId + getActor. If a query forgets the filter, that's a data leak — the code review pattern is always 'resolve actor, then withIndex'.
Analogy
Apartment building: same hallway, locked doors per unit.
Jessica's wedding portal
getActor(ctx) returns role + organizationId; client logins only see one eventId.
Agentify CRM
Pattern: getTenantUser(ctx, tenantId) at top of mutation; .withIndex('by_tenant_*', q => q.eq('tenantId', tenantId)).
Go deeper
One business = one tenant/org id on each row.
Common mistakes
- Trusting client-sent tenantId without server check.
- Copy-paste query from admin tool into user-facing code.
AI-agent trap
Broad queries without tenant filter — treat as Sev-1 until proven safe.
Summary
Never use .filter on tenantId in production hot paths — use indexes.
Confidence: