Skip to content

Multi-Tenancy Strategy

Status: Draft · Date: 2026-05-22 · Owner: Phat Nguyen (PM/PO) Companion engineering decision: ADR-0001 Multi-tenancy isolation tiers.

This page captures what we want from multi-tenancy and why. The how lives in the ADR.

Problem

BANA serves many businesses (Organizers) from one platform. Today every tenant shares one set of services and one database (nx_seller), separated only by a merchantId / organizerId column filter at the application layer. As tenant count and contract diversity grow, one model no longer fits everyone:

  • Mass-market SMBs need the cheapest possible per-tenant cost.
  • Larger / enterprise customers may demand data isolation, dedicated capacity, or even on-prem deployment.
  • We must be able to move a tenant between models as their needs change — including the hard direction, consolidating a dedicated tenant back onto the shared platform.

Goal

Make isolation level a per-Organizer attribute decided at runtime, not a one-time platform-wide choice. Default everyone to the cheapest tier; promote individual Orgs to stronger isolation on demand; keep the door open to move back.

Tenant boundary

The isolation unit is the Organizer (Org) — one Org plus all its child Merchants (branches) move together as a unit. organizerId is the partition key.

The three tiers (product view)

TierWhat the customer getsCostSold to
POOL (default)Shared services + shared DB; logically separatedLowestSMB, mass-market
BRIDGEShared services + own database per OrgMediumCustomers needing data isolation
SILODedicated services + DB per Org (own namespace/stack)HighestEnterprise, on-prem, special contracts

Industry mapping (AWS SaaS Lens): Pool / Bridge / Silo. BANA is already running Pool today.

Requirements

#RequirementTier
R1A new Org onboards instantly into POOL with no provisioningPOOL
R2An Org can be promoted POOL → BRIDGE → SILO without changing client URLs or app business codeall
R3An Org can be demoted SILO → POOL (consolidation) with data merged safelyall
R4Tenant data carries globally-unique IDs so merges never collideplatform
R5A noisy/heavy Org in higher tiers does not affect othersBRIDGE, SILO
R6One schema migration path that works across all tiersplatform
R7Long-term DB hygiene: cleanup, split, merge are documented, repeatable runbooksplatform

Success criteria

  • [ ] Isolation tier is a field on the Org, defaulting to POOL.
  • [ ] Moving an Org between tiers is a documented runbook, not a bespoke project each time.
  • [ ] No merchantId/organizerId ID collision is possible when merging a SILO back into POOL.
  • [ ] Adding a new Org to POOL requires zero infrastructure work.

Open questions (to resolve before Accepted)

QStatusImpact
Primary target market — SMB vs enterprise?Leaning hybrid, still exploringDetermines how much SILO investment is justified now
Compliance / data-residency / on-prem mandates?UndeterminedIf yes → SILO + portable Helm chart become mandatory, not optional
Is BRIDGE a permanent tier or only a stepping stone to SILO?OpenAffects whether we build BRIDGE tooling fully
Adopt Postgres Row-Level Security, or keep app-level filtering?OpenSecurity posture of POOL tier

Out of scope

  • Shift / cash-session redesign (tracked separately, under team discussion).
  • Per-tenant feature flags / customization beyond isolation.

Glossary

TermMeaning
Org / OrganizerTop-level tenant; contains N Merchants
MerchantA business unit / branch under an Org
Tenant RegistryLookup table: orgId → { isolationTier, datasourceRef }
Connection ResolverLayer that picks the right DB connection per tenant at request time
Snowflake IDGlobally-unique 64-bit ID; enabler for safe tenant merges

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.