Skip to content

Branding & site settings

Trackarr's visible identity — title, logo, subtitle, hero copy, login pages, footer, the homepage banner — is entirely runtime-driven. There are no env vars to set; the first admin edits everything live from /admin/branding and /admin/settings. New values land in the settings key-value table and are served back through /api/branding to every visitor.

How it works

       ┌─────────────────────────┐
       │  /admin/branding form   │
       │  /admin/settings form   │
       └────────────┬────────────┘
                    │ PUT /api/admin/settings
                    │ POST /api/admin/logo
                    │ POST /api/admin/favicon

       ┌─────────────────────────┐
       │  settings (key/value)   │
       │  uploads/ (logo, favicon)│
       └────────────┬────────────┘

        ┌───────────┴───────────┐
        │                       │
        ▼                       ▼
  ┌──────────┐           ┌──────────────┐
  │ Redis    │  pub/sub  │  GET /api/   │
  │ invalidate            │  branding    │
  │ channel  │           │  (cached)    │
  └────┬─────┘           └──────────────┘


  every Nitro replica clears its local 60 s cache so the new value lands within one request

The cache uses the same idiom as Upload Rules: in-process 60 s TTL + Redis pub/sub invalidation on every write.

What lives in settings

Each row is a free-form (key, value) pair (both text). The keys are enumerated in apps/api/utils/settings.ts (SETTINGS_KEYS).

Identity

KeyEffect
site_nameDisplay name. Renders in the header, title tag, footer, and notification subjects.
site_subtitleOptional tagline shown below the name.
site_name_colorOptional hex color override for the name in the header.
site_name_boldtrue/false. Wraps the name in <strong> when true.
site_logoEmoji or short text shown when no image logo is uploaded.
site_logo_imagePath to the uploaded logo (set by POST /api/admin/logo). Empty = fall back to site_logo.
site_faviconPath to the uploaded favicon (POST /api/admin/favicon).
page_title_suffixSuffix appended to every page title (e.g. · My Tracker).

Auth pages

KeyEffect
auth_titleOverride the headline on /auth/login and /auth/register.
auth_subtitleOverride the subheading on the auth pages.

Homepage

KeyEffect
hero_titleBig headline on /.
hero_subtitleSubheading.
status_badge_textThe pill text next to the hero (e.g. "Beta", "Invite-only").
feature_1_titleCard 1 title under the hero.
feature_1_descCard 1 description.
feature_2_*Card 2.
feature_3_*Card 3.
welcome_messageMarkdown shown in a dismissible welcome banner after first login.
KeyEffect
footer_textMarkdown rendered in the footer.

Site rules

KeyEffect
site_rulesMarkdown. Surfaces on the registration page and in the user's dropdown menu.

Announcement banner

A site-wide banner shown at the top of every page until an admin disables it.

KeyEffect
announcement_enabledtrue/false master toggle.
announcement_messageMarkdown body.
announcement_typeinfo / warning / success / error. Drives the colour rail.

Operational toggles

These aren't visual but live on the same page (/admin/settings):

KeyEffect
registration_opentrue/false. When false, /auth/register is gated behind an invite code.
invite_enabledMaster switch for the invite system.
default_invitesHow many invite slots a fresh account starts with.
min_ratioFloor enforced on user ratio. Used by the bonus economy + warnings.
starter_uploadBytes credited to users.uploaded + users.bonusUploaded at registration.
hnr_enabledMaster switch for Hit-and-Run enforcement.
hnr_required_seed_timeSeconds. Default 86400 (24 h).
hnr_grace_periodSeconds. Window before a not-yet-completed download is flagged.
require_2fa_scopeoff / staff / all. See Two-Factor Auth.
notifications_retention_read_daysTTL (days) for read notifications. Drives the notification-retention cron.
notifications_retention_unread_daysTTL (days) for unread notifications.

File uploads

The logo and favicon are real files, not URLs. They're stored under ${UPLOADS_DIR}/branding/ (defaults to ./data/uploads/branding/ inside the API container) and served via GET /uploads/branding/....

EndpointMethodNotes
POST /api/admin/logoPOSTMultipart upload, single field file. Server validates MIME + caps size.
POST /api/admin/faviconPOSTSame shape.

The endpoints overwrite the previous file (one logo + one favicon active at a time) and set the matching site_logo_image / site_favicon setting in the same transaction.

SSR-friendly delivery

/api/branding is the public read endpoint — no auth required. Nuxt SSR fetches it once on first paint, hydrates the result into the useBranding() composable, and the static-SPA build picks it up via /api/runtime-config. This means a single Trackarr image is fully portable across operators: someone redeploying for their own community only needs to edit /admin/branding to make the site theirs.

API surface

MethodPathAuthNotes
GET/api/brandingpublicAll visible identity fields in one call.
GET/api/homepage-contentpublicHero + feature cards (hero_*, feature_*_* settings).
GET/api/announcementpublic{ enabled, message, type }. Empty message if disabled.
GET/api/admin/settingsadminFull settings table (every key including hidden ones).
PUT/api/admin/settingsadminUpdate one or more settings atomically.
POST/api/admin/logoadminUpload logo (multipart).
POST/api/admin/faviconadminUpload favicon (multipart).

Caveats & gotchas

  • First-boot defaults: registration_open defaults to false (opt-in registration), staffBypass defaults to true. The first admin should sweep /admin/settings once after install.
  • Cache staleness on rollback: if you roll back a setting by editing settings directly in the DB (e.g. a recovery action), publish a manual invalidation: redis-cli PUBLISH settings:invalidate <key>. Without it, every Nitro replica keeps the stale value until the 60 s TTL expires.
  • Markdown surfaces: site_rules, footer_text, welcome_message, announcement_message are all rendered as Markdown. Sanitisation happens on the client; don't paste raw HTML you wouldn't trust.

Implementation reference

ConcernFile
Schemapackages/db/src/schema.ts (settings)
Key registry + cached gettersapps/api/utils/settings.ts
Public branding endpointapps/api/routes/api/branding.get.ts
Admin settings PUTapps/api/routes/api/admin/settings.put.ts
Logo / favicon uploadapps/api/routes/api/admin/logo.post.ts, favicon.post.ts
Web admin formapps/web/app/pages/admin/branding.vue, settings.vue
Public branding composableapps/web/app/composables/useBranding.ts

Released under the MIT License.