B2B Import ERP is a shared-database, shared-schema multi-tenant platform. Every company (tenant) operates on the same PostgreSQL instance and the same table structure, but their data is kept in complete isolation at the database engine level via Row-Level Security (RLS). This approach gives tenants an independent operational experience without requiring separate databases or schemas, while still guaranteeing that no record from Company A is ever visible to users of Company B — not even if there is a bug in application code.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/ency07/B2B-import/llms.txt
Use this file to discover all available pages before exploring further.
How It Works
Every operational table in the system carries a mandatorytenant_id UUID NOT NULL column that references the tenants(id) primary key. RLS policies attached to each table intercept every query issued by an authenticated user and automatically append an implicit WHERE clause that restricts results to the rows owned by the user’s own tenant.
The mechanism relies on two PostgreSQL primitives exposed by Supabase:
auth.uid()— returns the UUID of the currently authenticated user as declared in the JWT.userstable lookup — maps thatauth_user_idto the application’stenant_idandis_platform_userflag.
Standard RLS Policy Pattern
Every tenant-scoped table follows this policy template:- Platform bypass — if
is_platform_useristrue, the predicate evaluates totrueunconditionally and all rows are returned (used only bySUPER_ADMIN). - Tenant isolation — otherwise, only rows whose
tenant_idmatches the authenticated user’s owntenant_idpass the filter.
WITH CHECK clause is applied on INSERT and UPDATE to prevent a user from writing data into a different tenant’s partition, even if they somehow construct a rogue payload.
SUPER_ADMIN Bypass
Platform-level administrators are represented in theusers table with two special column values:
| Column | Value | Meaning |
|---|---|---|
tenant_id | NULL | Not affiliated with any company |
is_platform_user | true | Bypasses all RLS tenant-isolation filters |
site_id | NULL | No site assignment |
area_id | NULL | No area assignment |
is_platform_user = true, the first branch of every RLS policy short-circuits to true, granting full cross-tenant read and write access. This allows SUPER_ADMIN users to perform operations such as provisioning new tenants, inspecting platform-wide audit logs, and applying global configuration — none of which is accessible to tenant-level users.
Tenant Resolution in Server Actions
URL-based tenant routing is the entry point for multi-tenancy on the application side. Each tenant accesses the ERP through a unique URL slug (e.g.,/acme/dashboard, /apex/dashboard). The tenantCode extracted from the URL is passed into every Server Action, which resolves it to the internal tenant_id UUID via getTenantId():
tenant_id filter is always consistent with the RLS policy enforced at the database layer:
Demo Tenants
The development and staging environments ship with two pre-provisioned demo tenants:| Slug | Company Name | Primary Color | Theme |
|---|---|---|---|
acme | AeroMax Industrial | 199 89% 48% (Sky Blue) | Dark |
ventitech | AeroMax Industrial | 199 89% 48% (Sky Blue) | Dark |
apex | Apex Logística B2B | 142 72% 29% (Forest Green) | Dark |
acme credential will never surface apex records, and vice versa — enforced simultaneously at the application layer and the PostgreSQL RLS layer.
TenantConfig Interface
The frontend representation of a tenant’s basic identity is typed as TenantConfig in src/utils/tenant.ts:
getTenantConfig(tenantCode?) resolves a slug to its TenantConfig at render time for auth pages (login, recovery, reset-password), ensuring branded styling is applied even before a user is fully authenticated.
Additional Safeguards
- Insertion triggers —
BEFORE INSERT OR UPDATEtriggers verify that thetenant_idbeing written matches the session user’s owntenant_id, blocking any attempt to cross-write data via a crafted payload. - Soft deletes only — rows are never physically deleted. A
deleted_attimestamp marks logical removal, preserving the audit trail. permissionstable is global — thepermissionscatalogue hasUSING (true)for all authenticated users (read-only) because permission codes are not tenant-specific. OnlySUPER_ADMINcan insert or modify permission definitions.