Skip to content

fix(admin): Cloud-defined communication preferences, hidden privacy page, pr-<hex> host label, F37–F40 - #12

Merged
Domantas merged 10 commits into
mainfrom
fix/portal-structure-hostlabel
Oct 8, 2026
Merged

Domantas merged 10 commits into
mainfrom
fix/portal-structure-hostlabel

Conversation

@Domantas

@Domantas Domantas commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

What changed

  • Communication preferences render the structure Cloud defines (Project Settings → Communication Preferences): Marketing / Service messages tabs, groups with their tags, one switch per delivery channel a tag sends on (defaultDelivery), "Other options" for tags in no group, plus the global marketing switch. Writes blockedTags per delivery channel, as the gateway reads it (Campaign.cs).
  • Privacy & data page, nav item and Home card are hidden (PRIVACY_PAGE_ENABLED = false) — /me/compliance* do not exist. Home Security card no longer mentions two-factor.
  • Managed host: reads pr-<32 hex> (gateway ProjectId.HostLabel) and converts it to the pr_<base62> id with the gateway's own steps (tested against .NET output). The old pr_ host form broke because browsers lower-case hosts → "Portal unavailable".
  • F37 Profile / Preferences / Passkeys use the usr_ login id from the JWT cm_auth_id claim, not the numeric /auth userId ("2").
  • F38 no empty "or continue with" without WebAuthn; Terms / Privacy links point at /legal/* when Cloud published the document; reset form says "sent" only on success. Legal pages now use the boot-resolved project (custom domains).
  • F39 Dockerfile build args NEXT_PUBLIC_ADMIN_PROJECT_ID / NEXT_PUBLIC_ADMIN_CONFIG_MODE (checked: the id lands in the browser bundle).
  • F40 self-hosted structure route calls /v3/account/projects/{projectId}/admin-portal/structure via the SDK with the service-user key.
  • npm audit fix: source-map-js 1.2.1 (new high advisory GHSA-68fv-2mgg-jv7q, unrelated to this change) + in-range patch bumps.
  • Docs: README, docs/README, login-resolution, features, devops, backend.

Tests

  • npm test: 120 passed (new: host label vs .NET pairs, login id, communication structure, nav cards, sign-in screens, structure route against a local Hub).
  • lint, format:check, typecheck, next build: pass.
  • Playwright (local, fake API): 6 passed; branding-shell screenshot refreshed (no Privacy item/card).

Not in this PR (gateway)

  • Canonical admin URL still uses ProjectId.ViewId (DomainUrl.CreateTenantAdminUrlFromSuffix) — should be HostLabel.
  • Managed portal has no service key, so the communication structure needs to come through the internal structure endpoint.

Task file: docs/tasks/portal-structure-hostlabel.md (this branch).

🤖 Generated with Claude Code

Domantas and others added 10 commits October 7, 2026 17:01
… it into the pr_ id

Browsers lower-case the host, so the old pr_<base62> subdomain lost its id and
the portal showed "Portal unavailable". The label now matches the gateway's
ProjectId.HostLabel / TryParseFromHost and is converted to ProjectId.ViewId
with the same steps as Base62Converter (tested against .NET output).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, Preferences and Passkeys

The /auth response userId is ServiceStack's numeric UserAuthId ("2"), which
/membership/auth/{id} does not accept. Read the cm_auth_id claim the gateway
writes into the JWT; persisted sessions are re-derived by the selector. ref: F37

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ance endpoints exist; no two-factor on the Security card

/me/compliance, /me/compliance/export and /me/compliance/delete do not exist
(404). The page, its nav entry and its Home card hang off PRIVACY_PAGE_ENABLED
(false) until Cloud defines the privacy flows. 2FA is not built, so the Home
Security card now says "Password and passkeys."

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ture from Cloud instead of one marketing switch

Cloud defines channels → groups → tags (Project Settings → Communication
Preferences); the backend already reads it with the service key in
/api/bootstrap. The page now shows Marketing / Service messages tabs, each
group with its tags and one switch per delivery channel the tag sends on
(defaultDelivery), "Other options" for tags in no group, and keeps the
global marketing switch. blockedTags is written per delivery channel as the
gateway reads it (Campaign.cs).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ks filled, reset says "sent" only on success

- The passkey button renders nothing without WebAuthn, so it no longer counts
  towards the "or continue with" block.
- Terms / Privacy link to the portal's /legal/* pages when Cloud published the
  document; a link in the project config still wins.
- The reset request shows "on its way" only after the call succeeded and an
  error otherwise (it used to say sent in a finally block).
- publicApi takes the project resolved at boot, so legal pages work on custom
  domains too (resolveProjectId alone misses the async host lookup).
- Prettier on project.ts / loginId.ts from steps 3 and 4.
ref: F38

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cts/{projectId}/admin-portal/structure with the service-user key

The route called {hub}/v3/admin-portal/structure, which does not exist; the
gateway route is GetAdminPortalStructure at
/{version}/account/projects/{projectId}/admin-portal/structure. It now goes
through the SDK (hub.account.getAdminPortalStructure) with the service-user
API key from task P3, so the path, bearer and project headers match the
gateway. ref: F40

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… hidden privacy page, Next build args

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…NEXT_PUBLIC_ADMIN_CONFIG_MODE

Next inlines NEXT_PUBLIC_* at build time, so runtime env cannot pin the
project. Checked: docker build --build-arg NEXT_PUBLIC_ADMIN_PROJECT_ID=pr_dockerPinCheck
puts the id into .next/static/chunks/app/[[...slug]]/page-*.js. ref: F39

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…acy item or card, Security card says passkeys

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g-jv7q, high) and in-range patch bumps

The production audit step failed on a new advisory unrelated to this branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Domantas
Domantas merged commit 75330d2 into main Oct 8, 2026
2 checks passed
@Domantas
Domantas deleted the fix/portal-structure-hostlabel branch October 8, 2026 05:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant