MergeMind
Docs

Tenancy & isolation

Multi-tenancy is the part of a SaaS backend that looks trivial in a demo and becomes a real security question in production: what actually stops one customer's data from leaking into another's response? The platform answers that at the data-access layer, not by convention.

Tenant context is never trusted from the caller

The tenant a request operates on is resolved from the gateway-signed X-Tenant-Id header — never from a request body field, a query parameter, or a path segment the client controls. A handler that read a tenant id out of the request itself would be a bug, not a feature.

the difference that matters
// WRONG — trusting a caller-supplied tenant id
@GetMapping("/orders")
List<Order> list(@RequestParam UUID tenantId) {
    return orderRepo.findByTenantId(tenantId); // caller picks the tenant!
}

// The tenant comes from the verified gateway header, never a parameter.
@GetMapping("/orders")
List<Order> list() {
    UUID tenantId = TenantContext.getTenantId(); // from X-Tenant-Id, signature-verified
    return orderRepo.findByTenantIdAndTenantId(tenantId); // enforced, every query
}

Enforced at the data layer

Every service scopes its reads and writes to the caller's tenant at the repository layer — so even a handler that forgets to filter explicitly still can't cross tenant boundaries. That's defence in depth: the header can't be spoofed, and even if a query were built wrong, the enforcement layer underneath it still holds.

Data lifecycle

Tenant offboarding includes a scheduled data-purge path for GDPR-style deletion requests — not a manual, easy-to-forget cleanup script.

Need full infrastructure isolation — a dedicated database, VPC, or on-prem deployment for a single tenant, not just logical isolation in a shared stack? That's part of the Dedicated Enterprise engagement — see Security & Trust.

Previous

Authentication

Next

Authorization