Files
brain-of-reese/.agent/user_stories/configurable-brand.md
T
ducoterra 4971e2859d
Build and Push Containers / build-and-push-app (push) Successful in 12s
Build and Push Containers / build-and-push-db (push) Successful in 10s
chore(agent): track .agent/ planning tree in git
Remove the blanket .agent/ gitignore so the phase roadmap, user
stories, reports, and PLAN.md are versioned with the code. Only
runtime artifacts (.agent/phase-sessions/, .agent/pipeline.log)
remain ignored. Update AGENTS.md git protocol rule to match.
2026-09-01 10:18:22 -04:00

2.8 KiB

Story: Configurable app name

Phase: 39_configurable_brand · E2E: tests/e2e/test_configurable_brand.py

Narrative

As the owner, the app is "Brain of Reese" because that's what I named it — but the name is hard-coded across every template and JS string. I want to be able to rename the app with one env var (BOR_APP_NAME) so every page title, the header brand, the status labels, and the aria text carry the new name without touching code.

  • Given the app is running with BOR_APP_NAME="Brain of Testy"
  • When I open any page (chat, sources, tuning, login, document viewer)
  • Then the title, the header brand, the status labels ("Brain of Testy is thinking"), the empty-state greeting, and the document-viewer titles all say "Brain of Testy" — and with the variable unset the app is byte-identical to today ("Brain of Reese").

Acceptance criteria

  1. GET /api/config (public, stateless) → {app_name, version} from settings — exactly those two keys (no secrets, no other settings); unit + integration tested.
  2. frontend/assets/brand.js (classic script, loaded first on all five pages): sets window.BOR_BRAND synchronously (default "Brain of Reese"), fetches /api/config (cache: "no-store"), and applies the name — document.title (global replace of the literal), every .brand-text (bold split: a name starting "Brain of " bolds the remainder, else plain; the name is HTML-escaped), every text node and the aria-label / placeholder / meta-content attributes containing the literal; a fetch failure falls back to the default (console.warn, the page never breaks).
  3. The JS hard-codes move off the literal: app.js (status labels, the typing label, the elapsed-hint aria) + document.js (page titles) read window.BOR_BRAND (default "Brain of Reese" if unset).
  4. Containerfile: an esbuild line for brand.js next to the others.
  5. The story E2E boots its own app instance with BOR_APP_NAME overridden (distinct port; the shared conftest server keeps the default name so the existing title assertions stay green) and asserts title/brand/greeting/aria/label.
  6. .env.example + README document BOR_APP_NAME (what it affects, the default, the bold-split rule).
  7. Unit + integration green, app/ coverage >90%, story E2E green in isolation, ruff + pyright clean, one --no-gpg-sign commit.

Playwright Mapping Rule

tests/e2e/test_configurable_brand.py — one story, one file, run in isolation: the overridden-name instance shows the new brand in the title, the header .brand-text (with the bold split), the empty-state greeting, the messages aria-label, and the chat status label; the default-name shared server still renders "Brain of Reese" (the no-op regression).