docs(backlog): per-port branded login (section K) + next-env regen

Section K documents the recommended path for multi-tenant branded auth
screens: a single Next.js app behind `*.crm.example.com` wildcard DNS
that derives the active portSlug from the Host header (instead of the
current "first active port wins" fallback in resolveAuthShellBranding).
Includes the open work: wildcard cert, parent-domain cookie scope,
middleware host-resolver, switcher UI, and bootstrap seed.

next-env.d.ts is auto-regenerated by Next typegen with double-quote
formatting; included so the diff stays clean for the next dev session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-21 19:18:22 +02:00
parent 363ef0b882
commit a263a202d9

View File

@@ -351,6 +351,45 @@ Acceptance: spot-check the timeline tab on a recently-edited interest, client, y
---
## K. Per-port branded login (multi-tenant UX)
The login / forgot-password / set-password screens currently show the
"first active port" branding via `resolveAuthShellBranding()`, because
those surfaces have no portId in the URL. With two unrelated ports
(Port Nimara + Port Amador, no umbrella company) this means whichever
port was created first wins the login screen for everyone.
**Recommended path: shared instance, Host-header branding.** Run a
wildcard subdomain (`*.crm.example.com`) into the same Next.js app and
have middleware derive the active portSlug from the `Host` header.
`resolveAuthShellBranding()` then takes an optional host argument and
resolves by slug instead of "first port". Switcher becomes a
`window.location.assign('https://other-port.crm.example.com/dashboard')`;
session cookies are scoped to the parent domain so super-admins don't
re-auth when hopping.
Open work:
- Wildcard DNS + TLS cert (Cloudflare DNS-01 with `*.crm.example.com`).
- Cookie domain change: `pn-crm.session_token` needs `Domain=.example.com`
set in better-auth config.
- Middleware: read host, resolve portSlug, attach to request headers so
the auth-shell branding resolver can use it.
- Update `resolveAuthShellBranding()` to prefer host-derived port over
"first port" fallback.
- Port-switcher UI: dropdown in topbar that lists ports the user has
access to and navigates cross-subdomain.
- Bootstrap seed: populate `branding_logo_url` / `_email_background_url`
/ `_app_name` for the default port so fresh deploys aren't blank.
Alternative considered: **N instances, one per port.** Cleaner data /
deploy isolation but no UX gain over the shared-instance path. Defer
unless an operator demands independent migrations or data residency.
Size: medium (12 days incl. cert + cookie work + seed + switcher).
---
## I. Dashboard widget wishlist
User-driven enhancements to the customizable main dashboard