Skip to content

Branding ​

A licensed install can show its own look in place of Reportforge's: its product name, logo, favicon and colours, and its own sign-in page, in the studio and the viewer alike. It is set under Admin → Branding (/admin/branding).

The licence ​

Branding needs a licence with the branding feature (licence.md). Without it, the install keeps the Reportforge look, and the page says what a licence would unlock.

A lapse freezes branding, as it freezes content. A licence that granted branding keeps the branding showing after it lapses, or after a licence without branding replaces it, but it can't be changed until a licence grants branding again. An install that has never had such a licence can't set branding at all.

What it changes ​

Where it shows
Product namePage titles, the sidebar and the designer's top strip, the sign-in pages, the setup wizard, the viewer. The authenticator-app issuer and passkey name of a new enrolment, since apps keep the name they were given. The MCP server's title.
LogoBeside the product name in the sidebar, the designer's top strip and on the sign-in pages, in place of the studio's mark.
FaviconThe studio and the viewer (/branding/favicon, which answers Reportforge's until one is uploaded).
ColoursThe studio's brand palette, in light and dark mode: the accent (buttons, selection, links, focus) and the greys it tints. It is the studio's palette until someone picks another in their appearance menu; the viewer follows the brand too.
Sign-in pageA heading, a short text and an optional support link, in place of the studio's own copy, and a background image behind them. The viewer's sign-in page reads the same.

The product name doesn't change what reportd calls itself to machines: the MCP server's name, the assistant's prompts, the licence markers, the webhook user agent and cryptographic domain strings keep Reportforge or the code name.

Colours ​

You choose two: a primary colour and an accent. The studio's interface is monochrome with one accent, the brand's (buttons, selection, drop targets, links); the primary tints the greys and, where it reads, is the inverse surface (toasts, tooltips). The brand palette, every interface colour in light and in dark mode, is derived from them by one function, in reportd (internal/branding/ui_palette.go, DeriveUI) and in the studio (packages/style, deriveUiPalette), tested against the same vectors. reportd sends it with the branding, so the studio and the viewer draw with exactly what it checked.

Text must stay readable. In both modes, every pair the interface draws text in is checked against WCAG AA's 4.5:1, and every mark that isn't text (focus rings, the accent on a panel) against 3:1. The derivation steps a colour towards black or white until it reads, so any primary and accent you pick give a palette that passes: a mid grey primary, or a very light one, is darkened where it is text and kept where it only tints. The page shows the checks as you type, and reportd refuses a save that fails one all the same (422 contrast, with each check and its mode).

Uploads ​

FileTypesSize
LogoSVG or PNG512 KB
FaviconSVG, PNG or ICO128 KB
Sign-in backgroundPNG, JPEG or WebP2 MB

reportd reads a file's type from its content, never its name: a web page renamed logo.png is refused (415). Each file is served from /branding/<name> with Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline', X-Content-Type-Options: nosniff and an ETag, and the pages show the files only as images, so a script in an SVG never runs.

The sign-in text is plain text, with no HTML or Markdown, and is shown as text. The support link must be https: or mailto:.

Where it is kept ​

Branding is data, not config. On one node it is in dataDir/branding/: branding.json and the uploaded files. On the shared state it is in the schema's branding table, so every node serves the same. Backups, reportd state import and state export carry it (backup.md, state.md).

The embedded viewer ​

The viewer app draws in the studio's theme: light, dark or the system's, in the brand's palette when the install is branded. That palette is the one reportd derives from the primary and accent colours and sends with the branding, as the studio's is, and is the default until a person picks another palette in the studio. The report itself stays white in a dark theme, as it prints.

A page that embeds the viewer colours its controls with the studio's theme tokens (--rf-*, from @report-forge/ui-tokens) set on the element that holds it or above, as the designer's Interactive preview does. Unset, they are the Zinc palette's light colours. --rfv-paper-accent colours focus rings and checked filters on the report, a colour that reads on white (the viewer app sets the palette's light accent).

The API ​

RouteWhoWhat
GET /v1/brandingAnyone, signed in or notThe name, colours, derived palette ({light, dark}, every --rf-* colour token by name, when the colours aren't the defaults), sign-in copy and file URLs, and custom. No editor and no licence detail. The defaults without the feature.
PUT /v1/brandingsettings.manage and the feature{productName, colours: {primary, accent}, signIn: {heading, text, supportURL}}. An empty name or colour takes its default.
DELETE /v1/brandingsettings.manage and the featureBack to the defaults, files and all.
PUT, DELETE /v1/branding/files/{logo,favicon,background}settings.manage and the featureUpload a file (the body is the file) or remove one.
GET /branding/{name}AnyoneA file the branding shows, the default favicon, or 404.

Changes are audited as branding.change with the fields they changed, and branding.reset. settings.manage is the administrator's only, and an agent key never has it.