TL;DR
Shared-database multi-tenancy = one database, every row tagged with tenant_id, a global scope that filters automatically.
Three moving parts: a TenantContext singleton, a BelongsToTenant trait, and composite unique constraints.
The real safety net isn't discipline — it's a CI test that fails when a tenant_id table forgets the trait (or vice versa).
I shipped the foundation layer for shared-database multi-tenancy this week. Not the routing, not the resolver — just the part that makes "one row belongs to one organisation" true and hard to get wrong. Here's the shape of it.






