From c02bd51ec26552b1f36e81e96a9d7cb1c9bc6661 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 22:31:20 +0000 Subject: [PATCH] docs(deployment): branding variables follow the runtime's defaults and readers OS_PRODUCT_NAME defaults to ObjectOS and names the console only (tab title, header mark, sign-in pages, loading screen, PWA manifest); mail and auth are OS_APP_NAME's. OS_PRODUCT_SHORT_NAME falls back to the served product name. Adds OS_PRODUCT_STAGE, OS_LOGO_URL, OS_FAVICON_URL, OS_BRAND_COLOR, OS_PWA_DESCRIPTION and OS_PWA_THEME_COLOR as RuntimeConfigPlugin resolves them, read once at construction. States the Setup -> Branding precedence under single and the withheld namespace under group / isolated. Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp Co-authored-by: Claude --- .../docs/deployment/environment-variables.mdx | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/content/docs/deployment/environment-variables.mdx b/content/docs/deployment/environment-variables.mdx index 17b00ddebf9..aa78ace567f 100644 --- a/content/docs/deployment/environment-variables.mdx +++ b/content/docs/deployment/environment-variables.mdx @@ -129,13 +129,28 @@ Auth settings precedence: --- -## Branding (single-tenant) +## Branding + +The console's product name, logo, favicon and colours are served by `RuntimeConfigPlugin` (`@objectstack/cloud-connection`) as the `branding` block of `GET /api/v1/runtime/config`, which the console reads on every page load. A host that constructs its own `RuntimeConfigPlugin` with an option of the same name (`productName`, `logoUrl`, …) outranks the variable. The first eight variables below are read **once, when that plugin is constructed at boot**: changing one takes a restart. A value saved in **Setup → Branding** is read per request instead (see the precedence below). Mail and auth are named separately, by `OS_APP_NAME`. | Variable | Type | Default | Description | |:---|:---|:---|:---| -| `OS_PRODUCT_NAME` | string | `ObjectStack` | Product name shown in the UI chrome and emails. | -| `OS_PRODUCT_SHORT_NAME` | string | `OS` | Short name used in compact UI surfaces (favicons, mobile titles). | -| `OS_APP_NAME` | string | — | The deployment's product name under `objectstack serve`: `{{appName}}` in every email template (auth emails included), the issuer an authenticator app lists a TOTP enrollment under, and the MCP OAuth resource name. Wins over `config.email.appName`, `config.email.defaultTemplateContext.appName` and `config.appName`; with none of them set the name is `ObjectStack`. An explicitly set `branding.workspace_name` setting outranks it in auth. | +| `OS_PRODUCT_NAME` | string | `ObjectOS` | The console's product name (`branding.productName`): the browser-tab title (alone, or after the open app's label), the header's product mark, the sign-in pages, the loading screen and the installed-app (PWA) manifest's `name`. It does **not** name emails, the authenticator app entry or the MCP sign-in — `OS_APP_NAME` does — so an unconfigured deployment reads `ObjectOS` in the console and `ObjectStack` in its mail. Empty reads as unset. | +| `OS_PRODUCT_SHORT_NAME` | string | the product name served | The PWA manifest's `short_name` (`branding.productShortName`). Unset, it is the product name actually served, which under `single` may be a saved Branding name. | +| `OS_PRODUCT_STAGE` | enum | — (no `stage` key) | `preview` \| `beta` \| `ga`, matched exactly. Drives the console's top-bar chip (`branding.stage`): "Preview" for `preview`, "Beta" for `beta`, none for `ga`. Unset sends no `stage` key and the console keeps its own `preview` default, so the chip shows. Any other value (`GA`, `general-availability`) is refused with one `warn` at boot and treated as unset. | +| `OS_LOGO_URL` | url | — | The product logo, absolute or relative (`branding.logoUrl`): the sign-in pages, the loading screen and the header's product mark. Unset, the console draws its built-in mark. | +| `OS_FAVICON_URL` | url | — | The favicon, absolute or relative (`branding.faviconUrl`): the browser-tab icon and the PWA manifest's icon. While an app with its own `branding.favicon` is open, that icon replaces it. No Branding setting overrides this variable, on any posture. | +| `OS_BRAND_COLOR` | string | — | The brand colour as hex, e.g. `#4F46E5` (`branding.brandColor`). The console uses it as the installed-app theme colour, through `OS_PWA_THEME_COLOR`'s default; each app's own `AppBranding` colours are separate. | +| `OS_PWA_DESCRIPTION` | string | ` — runtime console` | The PWA manifest's `description` (`branding.pwaDescription`). Unset, it is built from the product name actually served. | +| `OS_PWA_THEME_COLOR` | string | the brand colour served, else `#4f46e5` | The PWA manifest's `theme_color` (`branding.pwaThemeColor`), as hex. Unset, it is the brand colour actually served, else `#4f46e5`. | +| `OS_APP_NAME` | string | — | The deployment's product name under `objectstack serve` for mail and auth: `{{appName}}` in every email template (auth emails included), the issuer an authenticator app lists a TOTP enrollment under, and the MCP OAuth resource name. Wins over `config.email.appName`, `config.email.defaultTemplateContext.appName` and `config.appName`; with none of them set the name is `ObjectStack`. Under `single`, an explicitly set `branding.workspace_name` setting outranks it in auth (the authenticator issuer takes a change only when the auth instance is rebuilt, such as at a restart); under `group` / `isolated` nothing does. It never names the console — that is `OS_PRODUCT_NAME`. | + +Branding precedence, by tenancy posture (`OS_TENANCY_POSTURE`): + +- **`single`** — three fields read the `branding` settings namespace on every request, so a save in **Setup → Branding** shows on the next page load with no restart: `workspace_name` → `productName`, `logo_url` → `logoUrl`, `accent_color` → `brandColor`. Each takes the first source that is set: the setting (a value saved in Setup, or the settings layer's own `OS_BRANDING_WORKSPACE_NAME` / `OS_BRANDING_LOGO_URL` / `OS_BRANDING_ACCENT_COLOR`, which outranks a saved value and locks the field), then the host's `RuntimeConfigPlugin` option, then `OS_PRODUCT_NAME` / `OS_LOGO_URL` / `OS_BRAND_COLOR`, then the built-in default. The Branding page's own default for `workspace_name` (`ObjectStack`) is never served to the console. A set `workspace_name` also names sign-in emails, the authenticator app entry and the MCP sign-in, ahead of `OS_APP_NAME`. +- **`group` / `isolated`** — the `branding` namespace is not offered: it is absent from `GET /api/settings`, `GET` and `PUT /api/settings/branding` answer `404 UNKNOWN_NAMESPACE`, and Setup lists no Branding entry. The `OS_BRANDING_*` variables are not read. The console's branding is the host option, then the variables in this table, then the default, and the auth product name is the `OS_APP_NAME` chain alone. A walled deployment that set `OS_BRANDING_WORKSPACE_NAME` moves the value to `OS_APP_NAME`. + +On every posture `productShortName`, `pwaDescription` and `pwaThemeColor` follow the name and colour actually served unless set themselves, and `OS_PRODUCT_STAGE` and `OS_FAVICON_URL` have no setting above them. ---