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
|
## I. Dashboard widget wishlist
|
||||||
|
|
||||||
User-driven enhancements to the customizable main dashboard
|
User-driven enhancements to the customizable main dashboard
|
||||||
|
|||||||
Reference in New Issue
Block a user