Multi-Tenant Architecture
Enterprise-grade multi-tenancy with complete data isolation and workspace management.
Overview
PenguinMails is built on a multi-tenant architecture powered by NileDB, providing complete tenant isolation, scalable workspace management, and secure data partitioning - all built into the platform from day one.
What is Multi-Tenancy?
Multi-tenancy means multiple customers (tenants) share the same application infrastructure while maintaining complete data isolation and security.
Benefits:
-
π’ Complete Isolation - Tenant data is fully separated
-
π Scalability - Add unlimited tenants without infrastructure changes
-
π° Cost Efficiency - Shared infrastructure reduces costs
-
π Security - Database-level tenant isolation
-
β‘ Performance - Per-tenant query optimization
Level 1: Core Concepts
Tenant Hierarchy
Platform (PenguinMails)
βββ Tenant (Company/Organization)
β βββ Users (Team Members)
β βββ Workspaces (Projects/Clients)
β βββ Subscription (Billing)
β βββ Settings (Company-wide)
β βββ Workspace 1
β β βββ Campaigns
β β βββ Domains
β β βββ Templates
β β βββ Contacts
β βββ Workspace 2
β βββ ...
Tenant
Tenant = Company/Organization.
-
Highest level of data isolation
-
Maps to one paying customer
-
Has one subscription
-
Can have multiple users and workspaces
-
Complete separation from other tenants
Example tenants:
- Acme Marketing Agency (Tenant ID:
tenant_abc123) - Startup Inc (Tenant ID:
tenant_xyz789)
Users
Users = Team Members within a Tenant.
-
Belong to exactly one tenant
-
Have roles (Owner, Admin, Member)
-
Can access multiple workspaces within their tenant
-
Cannot see data from other tenants
User roles:
-
Tenant Owner - Full control, billing access
-
Admin - Manage users, workspaces, settings
-
Member - Access assigned workspaces only
Workspaces
Workspaces = Projects, Clients, or Teams.
-
Organize work within a tenant
-
Optional sub-isolation for campaigns, contacts, domains
-
Multiple users can collaborate in one workspace
-
Example: βClient A Campaignβ, βProduct Launch 2025β
Level 2: Tenant Isolation
Database-Level Isolation
NileDB provides native multi-tenancy:
-- Every table has tenant_id
CREATE TABLE campaigns (
id UUID PRIMARY KEY,
tenant_id UUID REFERENCES tenants(id), -- Automatic isolation
workspace_id UUID REFERENCES workspaces(id),
name VARCHAR(255),
created_at TIMESTAMP
);
-- NileDB automatically filters by tenant
SELECT * FROM campaigns WHERE name = 'Welcome Series';
-- Becomes: SELECT * FROM campaigns WHERE tenant_id = {current_tenant} AND name = 'Welcome Series';
Automatic tenant context:
-
All queries automatically scoped to current tenant
-
Impossible to accidentally query another tenantβs data
-
Row-level security enforced at database level
-
No application-level filtering needed
Authentication & Tenant Context
How tenant context is established:
-
User logs in with email/password
-
NileDB authenticates and identifies tenant
-
Session includes tenant_id in JWT token
-
All API requests automatically scoped to that tenant
-
Database queries filtered by tenant_id
Session Token:
{
"user_id": "user_abc123",
"tenant_id": "tenant_xyz789", // Current tenant
"email": "user@acme.com",
"role": "admin",
"workspaces": ["ws_1", "ws_2"]
}
Data Isolation Guarantees
Whatβs Isolated:
-
β Campaigns - Tenant A cannot see Tenant Bβs campaigns
-
β Contacts - Complete contact list separation
-
β Templates - Email templates not shared
-
β Analytics - Performance data isolated
-
β Workspaces - Workspace data tenant-scoped
-
β Domains - Domain configurations isolated
-
β Users - User accounts tenant-specific
Whatβs Shared (Platform-Level):
-
βοΈ Application Code - Same codebase for all tenants
-
βοΈ Infrastructure - Shared servers (with isolation)
-
βοΈ Global Suppression - Platform-wide spam/abuse blocks
Level 3: Technical Implementation
Tenant Provisioning
Creating a new tenant:
// POST /api/v1/tenants
{
"company_name": "Acme Marketing",
"owner_email": "owner@acme.com",
"owner_name": "John Doe",
"plan": "professional"
}
// Backend Process:
// 1. Create tenant record in NileDB
// 2. Create owner user account
// 3. Initialize default workspace
// 4. Set up Stripe customer
// 5. Send welcome email
// 6. Return tenant_id and access token
Response:
{
"tenant_id": "tenant_abc123",
"owner_user_id": "user_xyz789",
"default_workspace_id": "ws_default",
"access_token": "eyJhbGc...",
"onboarding_url": "/onboarding"
}
Tenant Database Schema
-- Tenants Table (managed by NileDB)
CREATE TABLE tenants (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
settings JSONB DEFAULT '{}'
);
-- Users Table (tenant-scoped)
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID REFERENCES tenants(id),
email VARCHAR(255) NOT NULL,
name VARCHAR(255),
role VARCHAR(50), -- owner, admin, member
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(tenant_id, email) -- Email unique per tenant
);
-- Workspaces Table (tenant-scoped)
CREATE TABLE workspaces (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID REFERENCES tenants(id),
name VARCHAR(255) NOT NULL,
slug VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(tenant_id, slug)
);
-- Workspace Members (access control)
CREATE TABLE workspace_members (
workspace_id UUID REFERENCES workspaces(id),
user_id UUID REFERENCES users(id),
role VARCHAR(50), -- admin, member, viewer
PRIMARY KEY(workspace_id, user_id)
);
Tenant-Scoped Queries
Application code example:
// Get campaigns for current tenant
async function getCampaigns(tenantId) {
// NileDB automatically adds tenant_id filter
const campaigns = await db.campaigns.findMany({
where: {
// tenant_id automatically added by NileDB
status: 'active'
}
});
return campaigns;
}
// Create campaign (tenant context from session)
async function createCampaign(req, campaignData) {
const tenantId = req.user.tenant_id; // From JWT
const campaign = await db.campaigns.create({
data: {
tenant_id: tenantId, // Explicit tenant assignment
workspace_id: campaignData.workspace_id,
name: campaignData.name,
// ...
}
});
return campaign;
}
Workspace Management
Creating Workspaces
Workspaces organize work within a tenant:
// POST /api/v1/workspaces
{
"name": "Client A - Holiday Campaign",
"slug": "client-a-holiday",
"description": "Q4 2025 marketing push"
}
Response:
{
"workspace_id": "ws_abc123",
"name": "Client A - Holiday Campaign",
"slug": "client-a-holiday",
"members": [
{
"user_id": "user_xyz",
"role": "admin" // Creator is auto-admin
}
]
}
Workspace Access Control
Assign users to workspaces:
// POST /api/v1/workspaces/{workspace_id}/members
{
"user_id": "user_def456",
"role": "member" // admin, member, viewer
}
// User now has access to workspace
// Can view/edit campaigns, contacts, templates in that workspace
Workspace Roles:
-
Admin - Full control over workspace
-
Member - Create/edit campaigns, manage contacts
-
Viewer - Read-only access
Multi-Tenant Security
Security Features
-
Row-Level Security (RLS)
-
Database enforces tenant isolation
-
Impossible to bypass tenant filters
-
Automatic on all queries
-
-
API Middleware
-
Validates tenant_id from JWT
-
Ensures user belongs to tenant
-
Rejects cross-tenant requests
-
-
Tenant Switching Prevention
-
Users cannot switch tenants
-
Must log out and log in to different account
-
No shared user accounts across tenants
-
-
Audit Logging
-
All tenant actions logged
-
Cross-tenant access attempts flagged
-
Compliance and security monitoring
-
Security Validation
Request flow:
User Request
β
Extract JWT token
β
Verify signature
β
Extract tenant_id from token
β
Validate user belongs to tenant
β
Set tenant context for database
β
Execute query (auto-filtered)
β
Return results (tenant-scoped only)
Tenant Settings
Per-Tenant Configuration
Customizable settings:
{
"tenant_id": "tenant_abc123",
"settings": {
"company_name": "Acme Marketing",
"company_address": "123 Main St, SF, CA",
"timezone": "America/Los_Angeles",
"date_format": "MM/DD/YYYY",
"email_sender_name": "Acme Team",
"default_reply_to": "hello@acme.com",
"branding": {
"logo_url": "https://...",
"primary_color": "#007bff",
"custom_domain": "mail.acme.com"
},
"limits": {
"max_workspaces": 10,
"max_users": 5,
"email_sends_per_month": 50000
}
}
}
Tenant-Specific Features
Feature flags per tenant:
-
Beta Features - Early access for specific tenants
-
Custom Branding - Enterprise tenant white-labeling
-
API Rate Limits - Per-tenant throttling
-
Data Retention - Custom retention policies
Scalability
Horizontal Scaling
Multi-tenancy enables:
-
Add unlimited tenants without code changes
-
Database sharding (future) - partition tenants across DBs
-
Per-tenant performance optimization
-
Isolated tenant upgrades/migrations
Current Architecture:
-
All tenants share one NileDB instance
-
Automatic query optimization per tenant
-
Connection pooling shared across tenants
Future Scaling (if needed):
-
Shard large tenants to dedicated databases
-
Geo-distributed tenants (US/EU data centers)
-
Tenant-specific resource allocation
Related Documentation
Architecture
-
Free Mailbox Creation - Infrastructure provisioning
-
Infrastructure Overview - All infrastructure features
Implementation
-
NileDB Documentation - Database multi-tenancy details
-
Authentication - Tenant-aware auth
-
API Architecture - Multi-tenant API design
Management
-
User Management - Team member management
-
Workspace Management - Workspace organization
Tasks
- Epic 3: Tenant Management - Internal task reference for implementation tasks
Best Practices
For Tenants (Customers)
-
Use Workspaces - Organize by client, project, or team
-
Assign Roles Carefully - Give minimum necessary permissions
-
Regular Audits - Review workspace access quarterly
-
Naming Conventions - Use consistent workspace naming
For Developers
-
Always Use Tenant Context - Never query without tenant_id
-
Validate Tenant Access - Check tenant membership on every request
-
Test Isolation - Verify tenant data separation in tests
-
Audit Logs - Log all tenant-scoped operations
-
Never Hard-Code tenant_id - Always from session/token
Last Updated: November 24, 2025 Technology: NileDB Multi-Tenant PostgreSQL Isolation Level: Database Row-Level Security (RLS)
Multi-tenancy is the foundation of PenguinMailsβ security and scalability. Complete tenant isolation ensures enterprise-grade data protection.