v0.6.0 — Optional multi-tenancy
Optional multi-tenancy
Adds opt-in multi-tenancy controlled by the MULTI_TENANCY env flag. Default is false, which preserves the original single-tenant behavior exactly.
When enabled
- Identity =
(Authorization key, X-Session-Id). Auth key sent as today (Authorization: Bearer/X-API-Key); the tenant additionally sends a static, client-controlledX-Session-Idheader. - Auto-provisioning, no admin. First time a
(key, session_id)pair is seen, a tenant is created and an opaque, stabletenant_idis derived. Raw key never stored (only SHA-256 hash). - Data scoping. Every owned table has a
tenant_idcolumn; all queries filter by the tenant resolved from context. Name/natural-key uniqueness is per-tenant (email, template name, mailbox, chat, external object ids). - Channel config stays global. WhatsApp / Threads / IMAP gateway + tokens are shared via env; only the data is scoped.
- Public routes (
/t,/o,/export,/u, wa webhook) resolve the owning tenant from the globally-unique random code/id on the matched row. - Background jobs record the owning tenant per task and re-inject it into context before tenant-scoped work.
Migration
0010_multi_tenancyadds thetenantstable, atenant_idcolumn on every owned table (default'default'), and per-tenant composite unique keys. Existing rows backfill to'default'. Auto-applied on startup; no manual steps.
Backward compatibility
Verified on a real MySQL upgrade (v9 → 0010): legacy single-tenant data backfilled and fully reachable, multi-tenant isolation verified, full integration suite green.
Config
| Variable | Default | Notes |
|---|---|---|
MULTI_TENANCY |
false |
true scopes all data per tenant; tenants auto-provisioned from (Authorization, X-Session-Id). |
PR #23.
www.threads.com_cookies.txt session file was briefly committed during merge and has been purged from history via a force-push rewrite. If you have a local clone from before this release, re-clone or hard-reset to the new master. Rotate any affected Threads/Instagram session.