JUL6ART
🇬🇧 EN
Retour au blog
12 April 2026

Why we picked native multi-tenancy

One organization, one scope, zero leak. The most structuring decision of the platform.

Architecture multi-tenant

Shared multi-tenancy — every organization in the same database, isolated by application filters — is the most dangerous compromise a SaaS platform can make. One mis-scoped query, one forgotten join, one missing voter, and the leak is silent, lasting, and undetectable without a full audit.

That is why Jul6art applies multi-tenancy to every layer of the app:

  • Doctrine — every business entity carries an organization_id FK, indexed alongside deleted_at. A bare findAll() is never valid; repositories expose queryByOrganization(Organization) as the canonical entry point.
  • HTTP — the X-ORGANIZATION header is resolved at the very start of the chain by a subscriber that rejects any mismatch with the authenticated user's tenant.
  • API Platform — every StateProvider applies the tenant filter automatically. Processors check the scope before persisting on potentially cross-org FKs (mass-assignment guard).
  • VotersdenyAccessUnlessGranted(Voter::VIEW, $entity) on every show, edit, delete, with an entity-side re-check of organization_id.

Defense in depth keeps a single mistake from becoming a breach. A voter regression is caught by the Doctrine filter; a Doctrine filter regression is caught by the voter.