CHANGELOG v0.5.0 - nself-org/nchat GitHub Wiki
Release Date: January 30, 2026 Status: Major Release - Multi-Tenant Architecture
nself-chat v0.5.0 introduces a production-ready multi-tenant system, transforming the platform into a fully-featured SaaS application.
Key Capabilities:
- ✅ Subdomain Routing: Automatic tenant resolution from subdomains (
tenant.nchat.app) - ✅ Custom Domains: Optional custom domain support (
chat.acme.com) - ✅ Schema-Level Isolation: Each tenant gets isolated PostgreSQL schema
- ✅ Stripe Billing: Full subscription management (Free, Pro, Enterprise, Custom plans)
- ✅ Resource Limits: Per-plan usage enforcement (users, storage, API calls)
- ✅ Usage Tracking: Real-time monitoring and analytics per tenant
- ✅ Tenant Management: Complete CRUD operations via API
- ✅ Row-Level Security: PostgreSQL RLS policies for data protection
New Global Tables (in public schema):
-
tenants- Tenant organizations metadata -
tenant_usage- Usage statistics per tenant per month -
tenant_settings- Tenant-specific configuration -
tenant_invitations- Invite system for tenant onboarding -
tenant_audit_logs- Audit trail for administrative actions -
stripe_webhooks- Stripe webhook event log
Tenant Isolation:
- Each tenant gets dedicated schema:
tenant_{slug} - Complete isolation of all chat data (users, channels, messages, etc.)
- Automatic schema provisioning on tenant creation
Tenant Resolution:
// Before: Single-tenant
export function middleware(request: NextRequest) {
// Authentication only
}
// After: Multi-tenant + Authentication
export async function middleware(request: NextRequest) {
// 1. Resolve tenant from subdomain/domain
// 2. Set tenant context headers
// 3. Authenticate user
// 4. Enforce tenant-scoped access
}Core Service (src/lib/tenants/tenant-service.ts):
class TenantService {
createTenant(request: CreateTenantRequest): Promise<Tenant>
getTenantBySlug(slug: string): Promise<Tenant | null>
updateTenant(id: string, request: UpdateTenantRequest): Promise<Tenant>
deleteTenant(id: string): Promise<void>
checkLimits(tenant: Tenant): Promise<{ exceeded: boolean; limits: string[] }>
}Middleware (src/lib/tenants/tenant-middleware.ts):
- Subdomain parsing and validation
- Custom domain resolution
- Tenant caching for performance
- Automatic tenant context injection
Context & Hooks (src/contexts/tenant-context.tsx):
// React hooks for tenant operations
useTenant() // Get current tenant
useTenantFeature() // Check feature availability
useTenantLimits() // Check resource limits
useTenantBilling() // Get billing informationStripe Service (src/lib/billing/stripe-service.ts):
class StripeBillingService {
createCustomer(tenant: Tenant): Promise<string>
createSubscription(tenant, plan, interval): Promise<Subscription>
updateSubscription(tenant, newPlan, newInterval): Promise<Subscription>
cancelSubscription(tenant, immediately): Promise<Subscription>
createCheckoutSession(...): Promise<CheckoutSession>
createPortalSession(tenant, returnUrl): Promise<PortalSession>
processWebhookEvent(event): Promise<void>
}Webhook Processing:
- Automatic subscription lifecycle management
- Payment status tracking
- Trial expiration handling
- Usage-based billing support
Tenant Management:
-
POST /api/tenants/create- Create new tenant -
GET /api/tenants/[id]- Get tenant details -
PUT /api/tenants/[id]- Update tenant -
DELETE /api/tenants/[id]- Delete tenant (soft delete) -
GET /api/tenants/by-slug?slug=acme- Internal tenant resolution -
GET /api/tenants/by-domain?domain=chat.acme.com- Custom domain resolution
Billing:
-
POST /api/billing/checkout- Create Stripe checkout session -
POST /api/billing/portal- Access customer billing portal -
POST /api/billing/webhook- Stripe webhook endpoint
- 10 users
- 5 channels
- 1 GB storage
- 1,000 API calls/month
- Basic features only
- 100 users
- 50 channels
- 100 GB storage
- 50,000 API calls/month
- All features + analytics + integrations
- Unlimited users, channels, storage
- Unlimited API calls
- All features + SSO + audit logs + priority support
- Custom resource limits
- Custom feature set
- Dedicated support
- SLA guarantees
Tenant Isolation Policies:
-- Super admins can see all tenants
CREATE POLICY tenants_super_admin_all ON public.tenants
USING (is_super_admin(auth.uid()));
-- Tenant owners can see their own tenant
CREATE POLICY tenants_owner_select ON public.tenants
FOR SELECT USING (owner_id = auth.uid());- Schema-level isolation: No shared tables between tenants
- Middleware enforcement: Automatic tenant scoping on every request
- Encrypted storage: Tenant-specific encryption keys
- Audit logging: All administrative actions tracked
Per-tenant rate limits based on subscription plan:
- Free: 60 requests/minute, 1,000 requests/hour
- Pro: 120 requests/minute, 5,000 requests/hour
- Enterprise: 300 requests/minute, 15,000 requests/hour
- Custom: 600 requests/minute, 30,000 requests/hour
Required:
# Multi-tenancy
ENABLE_MULTI_TENANCY=true
NEXT_PUBLIC_BASE_DOMAIN=nchat.app
# Stripe
STRIPE_SECRET_KEY=sk_...
STRIPE_WEBHOOK_SECRET=whsec_...
# Database
DATABASE_URL=postgresql://...Optional:
# Custom domains
ENABLE_CUSTOM_DOMAINS=true
ALLOWED_CUSTOM_DOMAINS=chat.acme.com,team.example.com
# Single-tenant mode
DISABLE_MULTI_TENANCY=false
DEFAULT_TENANT_SLUG=demoDNS Configuration:
- Wildcard DNS record:
*.nchat.app → server IP - Wildcard SSL certificate for
*.nchat.app
Database:
- PostgreSQL ≥14 with schema support
- Recommended: Connection pooling (PgBouncer)
Caching:
- Redis ≥6.0 for tenant metadata caching
- Recommended: Separate Redis instance per environment
Metrics Collected:
- Active users per tenant
- Messages sent per tenant
- Storage used per tenant
- API calls per tenant per endpoint
- Call duration and participant counts
Database Functions:
-- Check if tenant has exceeded limits
SELECT public.check_tenant_limits('{tenant_id}');
-- Get current month usage
SELECT * FROM public.tenant_usage
WHERE tenant_id = '{id}' AND period = '2026-01';All tenant administrative actions logged:
- Tenant creation/deletion
- Subscription changes
- Feature flag updates
- Custom domain assignments
- User management actions
New Documentation:
-
/docs/Multi-Tenant-Deployment.md- Complete deployment guide (12,000+ words) -
/docs/Multi-Tenant-README.md- Quick start guide -
.env.multi-tenant.example- Environment configuration template
Migration Guides:
- Single-tenant to multi-tenant migration
- Self-hosted to SaaS conversion
- Development to production checklist
1. Database Migration:
cd .backend
nself db migrate up 030_multi_tenant_system.sql2. Create Default Tenant (for existing installations):
INSERT INTO public.tenants (
name, slug, status, owner_email, owner_name,
schema_name, billing_plan
) VALUES (
'Default Organization',
'default',
'active',
'[email protected]',
'Owner',
'nchat', -- Points to existing nchat schema
'enterprise'
);3. Update Environment:
# Add to .env.local
ENABLE_MULTI_TENANCY=true
DEFAULT_TENANT_SLUG=default4. Install Dependencies:
pnpm install # Adds Stripe SDK5. Test:
# Access via default subdomain
http://default.localhost:3000Renamed:
- None
Added (required for multi-tenant mode):
ENABLE_MULTI_TENANCYNEXT_PUBLIC_BASE_DOMAINSTRIPE_SECRET_KEYSTRIPE_WEBHOOK_SECRET
Deprecated:
- None
New Headers (automatically added by middleware):
-
X-Tenant-Id- Current tenant UUID -
X-Tenant-Slug- Current tenant slug -
X-Tenant-Schema- Current tenant schema name -
X-Tenant-Context- Complete tenant context JSON
New Required Tables:
- All
public.tenants*tables (see migration 030)
Schema Changes:
- No changes to existing
nchat.*tables - Existing data can be migrated to tenant schema
- Tenant Caching: Redis cache for tenant metadata (TTL: 1 hour)
- Schema Caching: PostgreSQL prepared statements per schema
- Connection Pooling: Per-tenant connection pools
- CDN Support: Static assets served via CDN with tenant context
Tenant Resolution:
- Cached: <1ms
- Uncached: 5-10ms
Schema Switching:
- PostgreSQL SET search_path: <1ms
Total Overhead:
- Multi-tenant vs single-tenant: +2-5ms per request
- Tenant Admin Portal: UI for managing tenant settings
- Super Admin Dashboard: Global tenant management interface
- Tenant Analytics: Advanced usage analytics and insights
- White-Label Customization: Per-tenant branding and theming
- API Access: Tenant-scoped REST and GraphQL APIs
- Webhook System: Tenant-configurable webhooks
- Multi-region Support: Geographic tenant distribution
- Tenant Groups: Hierarchical tenant organization
- Usage-based Billing: Metered billing for API calls and storage
- Tenant Import/Export: Backup and migration tools
Multi-tenant features are now part of the core platform. Contributions welcome:
- Bug Reports: https://github.com/yourusername/nself-chat/issues
- Feature Requests: Use "multi-tenant" label
- Pull Requests: See CONTRIBUTING.md
Same as nself-chat: MIT License
Special thanks to:
- Stripe for excellent billing infrastructure
- PostgreSQL for robust schema isolation
- nself CLI team for backend foundation
Full Documentation: See /docs/Multi-Tenant-Deployment.md
Questions? [email protected]