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:
@@ -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 (1–2 days incl. cert + cookie work + seed + switcher).
|
||||
|
||||
---
|
||||
|
||||
## I. Dashboard widget wishlist
|
||||
|
||||
User-driven enhancements to the customizable main dashboard
|
||||
|
||||
Reference in New Issue
Block a user