Tenant¶
The tenant app models the tenant organization and how requests are routed
to it. It is a shared app (lives in the public schema) and is the backbone of
Midsummer’s multi-tenancy.
What it does¶
Tenant— the org that owns one or more events (in practice one event today). Each tenant has its own PostgreSQL schema (schema_name).Domain— the subdomain(s) that map a host to a tenant (e.g.furrydelphia.midsummer.cloud).modedistinguishes event vs. tenant-management domains.CustomDomain— a customer-owned domain (e.g.furrycon.com) pointing at a specificEvent. Lifecycle:DNS_VERIFIED→ … →SSL_ISSUED. Midsummer issues Let’s Encrypt certificates and generates nginx configs from these records (services/custom_domain_nginx.py).Membership— the per-tenant role for aUser. CarriesisTenantSuperuserand developer flags. This is how a single shared identity gets different powers in different tenants.Public-schema landing pages — the
front/app serves the marketing/landing pages on the public schema.
How routing uses this¶
host ──► TenantMainMiddleware ──► Domain → Tenant
│ switch connection to tenant schema
│ set URLconf (tenant vs public)
▼
EventSetupMiddleware ──► request.current_event (subdomain or CustomDomain)
See Request resolution and Multi-tenancy for the full middleware walk.
Key models¶
Tenant (schema_name)
└─ Domain (is_primary, mode)
└─ CustomDomain (event, status: DNS_VERIFIED…SSL_ISSUED)
User ── Membership ──► Tenant (isTenantSuperuser, developer flags)
Warning
A latent bug: the staff roster uses a Membership.isTenantAdmin field that does
not exist (short-circuit-masked). Prefer the real Membership.isTenantSuperuser
field for any new tenant-admin gating.
Where to look¶
Models:
tenant/models.pyCustom-domain nginx generation:
tenant/services/custom_domain_nginx.pyMiddleware:
midsummer/middleware.py