# Changelog All notable changes to Chat Switchboard. ## [0.22.8] — 2026-03-04 ### Changed - **Naming cleanup: preset → persona.** Unified domain terminology across the entire codebase. Routes `/presets` → `/personas` (user, team, admin). JSON response keys, request fields, Go struct fields, handler names, JS functions, CSS classes, DOM IDs, template strings, display text — all consistently use "persona". File renamed: `presets.go` → `personas.go`. Dual JSON keys (`"personas"` + `"presets"`) collapsed to single `"personas"` key. Config key `user_presets` → `user_personas`. Banner color presets intentionally left as "presets" (different domain concept). - **Naming cleanup: APIConfigID → ProviderConfigID.** All Go structs and JSON fields now use `provider_config_id` consistently. - **Removed aliases.** `chat_id` field removed from completion handler. `/models` route alias removed (use `/models/enabled`). - **Shared app-state.js.** Extracted `App` state object, `fetchModels()`, and `resolveCapabilities()` from chat-only `app.js` into new `app-state.js` loaded by `base.html` for all surfaces. Settings and admin surfaces now have access to `App` state for model dropdowns, settings, and user context. - **Auth tokens loaded for all surfaces.** `API.loadTokens()` now runs in `base.html` inline script so settings, admin, editor, and notes surfaces can make authenticated API calls. - **Script loading consolidated in base.html.** `ui-core.js` moved from per-surface loads to `base.html`. `ui-primitives-additions.js` (never loaded by any surface) now loaded in `base.html`. All surfaces get the complete shared stack: app-state → api → events → ui-primitives → ui-primitives-additions → ui-core → pages. ### Added - **Settings surface functions.** `UI.loadGeneralSettings()` populates the general settings form (model dropdown, system prompt, temperature, max tokens, thinking toggle) with server data. `UI.saveAppearance()` persists theme, scale, and font size. `UI.loadTeamsSettings()` renders team membership on the settings teams tab. - **Design documentation.** `docs/DESIGN-SURFACES.md` (four-layer surface architecture, extension hooks, trust model), `docs/ICD-API.md` (domain-organized API contract, 240 routes), `docs/ICD-AUDIT.md` (cross-reference audit with resolution status). ## [0.22.7] — 2026-03-03 ### Added - **Theme system.** New `theme.css` provides complete light/dark theming via CSS custom properties with `[data-theme]` attribute switching. Variables cover backgrounds, surfaces, text, accents, borders, shadows, and component-specific tokens. System preference auto-detection via `prefers-color-scheme` media query. Old variables (`--bg-primary`, `--text-primary`) bridged via fallback chains (`var(--bg, var(--bg-primary, #0e0e10))`) — zero breakage of existing CSS. - **ChatPane component.** New `chat-pane.js` provides a mountable, self-contained chat pane factory replacing the hardcoded singleton pattern. `ChatPane.create(opts)` returns an instance with `renderMessages()`, `appendChunk()`, `finalizeStream()`, `appendTyping()`, `removeTyping()`, `scrollToBottom()`, `showWelcome()`, `clear()`, `getInputValue()`, `setInputValue()`, `focusInput()`, `destroy()`. Lookup via `ChatPane.get(id)`, `ChatPane.forChannel(channelId)`, `ChatPane.active()`. Each instance owns its own DOM elements and channel binding. - **Chat pane template component.** New `components/chat-pane.html` Go template partial: `{{template "chat-pane" dict "ID" "main"}}` renders a complete chat scaffold with messages container, input bar, model selector, send button, and toolbar mount points. Used by editor surface assist pane. - **Splash/login surface.** Login page rewritten from minimal form to split-panel splash layout: animated grid canvas on hero side, tabbed auth card (Login + Register) on right. Registration form includes avatar upload, display name, email. Powered by new `pages-splash.js` module with `Pages.initSplash()`, grid animation, and `POST /api/v1/auth/register` + `PUT /api/v1/users/me/avatar` integration. - **UI primitives additions.** New `ui-primitives-additions.js` extends the shared primitive library: `Toast` (show/success/error/warning/info with auto-dismiss stacking), `renderBadge()` (6 color variants), `renderIcon()` (20+ SVG icon set), `renderIconBtn()` (icon button factory with active state), `Theme` (init/set/get/resolved/renderToggle with localStorage persistence), `showConfirmDialog()` (enhanced with variant/callbacks), `mountAvatarUpload()` (file input with preview). - **Settings BYOK gate.** Settings surface nav now conditionally shows "My Providers", "Model Roles", and "Usage" tabs only when BYOK is enabled. Server-side gate via `{{if .Data.BYOKEnabled}}` reads `GlobalConfig` key `user_providers.enabled`. Includes BYOK status indicator in nav footer with UEK encryption notice. - **Settings User Personas gate.** Settings surface conditionally shows "My Personas" tab when user-created personas are enabled. Server-side gate via `{{if .Data.UserPersonasEnabled}}` reads `GlobalConfig` key `user_presets.enabled`. - **Settings Models tab.** New "Models" nav link in settings surface for user model visibility preferences. - **Editor assist pane.** Editor surface now includes a `chat-pane` template component for the right-side assist pane with split handle, wired up via `ChatPane.create()` on DOM ready. ### Changed - **`base.html` template.** Added `data-theme` attribute on `` element for theme system. Google Fonts preconnect + DM Sans / JetBrains Mono stylesheet. `theme.css` loaded before `styles.css`. New shared script tags for `ui-primitives-additions.js` and `chat-pane.js` (available on all surfaces). Added `window.__SETTINGS__` global from `PageData.SurfaceSettings`. - **`PageData` struct** (`pages.go`). New fields: `Theme` (string), `SurfaceSettings` (any, serialized to `__SETTINGS__`), `InstanceName`, `LogoURL`, `Tagline`, `RegistrationOpen`. `Render()` defaults `Theme` to `"dark"` when unset. - **`RenderLogin()`** (`pages.go`). Now calls `loadBranding()` and `isRegistrationOpen()` to populate splash/login template fields from `GlobalConfig` keys `branding.*` and `registration.enabled`. - **`SettingsPageData`** (`loaders.go`). Added `BYOKEnabled` and `UserPersonasEnabled` boolean fields. `settingsLoader()` reads from `GlobalConfig` keys `user_providers.enabled` and `user_presets.enabled`. - **`settings.html` template.** Reorganized nav: base tabs (General, Appearance, Models, My Presets) always visible; BYOK section (My Providers, Model Roles, Usage) gated; User Personas gated; then Knowledge, Memory, Notifications, Teams. Added `my-personas` to dynamic section loaders. - **`editor.html` template.** Added `chat-pane` component in right-side assist pane with split handle and `ChatPane.create()` initialization. ### New Files - `src/css/theme.css` — 305 lines: CSS custom properties, shared components, surface layouts - `src/js/chat-pane.js` — 162 lines: mountable chat pane factory - `src/js/ui-primitives-additions.js` — 199 lines: Toast, Badge, Icons, Theme, confirm, avatar - `src/js/pages-splash.js` — 154 lines: splash init, login, register, grid canvas - `server/pages/templates/components/chat-pane.html` — 23 lines: reusable template partial ## [0.22.6] — 2026-03-03 ### Fixed - **Split FE/BE deployment: page route proxying.** Frontend container now supports `BACKEND_URL` env var. When set, the entrypoint generates nginx `proxy_pass` blocks for page routes (`/`, `/login`, `/chat/:id`, `/admin/*`, `/editor/*`, `/notes/*`, `/settings/*`) so Go template rendering works in k8s split-image deployments. When unset, behavior is unchanged (SPA fallback). Both `BASE_PATH=""` and `BASE_PATH="/prefix"` variants supported. - **CI test timeout.** All `go test` commands now include `-timeout 8m` to prevent indefinite hangs from runner resource contention or race-detector compilation stalls. Previously used Go's 10-minute default with no goroutine dump on timeout. ### Removed - **`router.js` (322 lines).** Client-side hash router fully replaced by server-side page routes. All `Router.*` call sites in `chat.js` replaced with `history.replaceState()` for URL updates. All `typeof Router` guards in `app.js` removed. - **`surfaces.js` (368 lines).** Client-side surface registry replaced by Go template surface architecture. Extension API stubs (`surfaces.register`, `surfaces.activate`, etc.) now log deprecation warnings. `surfaces.getCurrent()` returns `window.__SURFACE__` from server-rendered page data. - **`index.html` SPA shell (1,296 lines → 16 lines).** Original monolithic SPA entry point replaced with a minimal redirect page. All real routes now served by Go templates; `index.html` only serves as nginx `try_files` fallback for unknown paths. - **`editor-mode.js` old Surfaces paths (~260 lines).** Removed `_register()`, `openDirect()`, `_unregister()`, `_activate()`, `_deactivate()`, `_embedChat()`, `_returnChat()`, and full `check()`/`checkStartup()` implementations. Only `mountServerRendered()` remains as the entry point. `check()` and `checkStartup()` kept as no-ops for backward compat with `projects-ui.js` callers. - **SPA-only entrypoint code path.** `docker-entrypoint-fe.sh` now requires `BACKEND_URL` (fails fast if unset). Removed dead `%%BASE_HREF%%`, `%%ENVIRONMENT%%`, `%%BRANDING_JSON%%` injection into index.html. Removed branding config file loading (branding now handled by Go templates). ### Changed - `docker-entrypoint-fe.sh`: Simplified from 227 → 184 lines. Requires `BACKEND_URL`. Removed SPA-only fallback path. - `nginx.conf` (unified container): Consolidated repeated `proxy_set_header` blocks. Uses `$backend` variable. Page routes proxy to Go backend for template rendering. - `base.html`: Added `__ENV__` and `__BRANDING__` globals for JS compatibility (previously injected by index.html sed). - `server/pages/pages.go`: Added `Environment` field to `PageData`, populated from config. - `extensions.js`: `ui.replace()`, `ui.restore()`, and `surfaces.*` API methods now log deprecation warnings instead of calling removed Surfaces system. - `app.js`: Removed `Surfaces.init()`, `EditorMode.checkStartup()`, and `Router.init()` calls. Simplified to direct `sessionStorage` chat restore. - `chat.js`: Replaced `Router.update()` calls with `history.replaceState()` for URL-bar sync on chat selection/creation. - `repl.js`: Removed `surfaces.js` import reference. ## [0.22.5] — 2026-03-03 ### Added - **Go template engine.** Server-side HTML rendering via `html/template` with `//go:embed` for compiled-in templates. Custom `FuncMap` with helpers (`roleFilterType`, `toJSON`, `hasPrefix`, `dict`). CSP nonce generation per request. Replaces monolithic `index.html` + client-side DOM construction with composable, server-rendered surfaces. - **Surface architecture.** Each page route renders a dedicated surface template that owns its full layout below the classification banner. Surfaces compose from reusable components (`model-select`, `team-select`, `file-upload`) without sharing CSS layout rules. Banner height handled via CSS custom properties (`--banner-top-h`, `--banner-bot-h`, `--surface-h`). - **Chat surface.** Server-rendered shell at `/` and `/chat/:chatID`. Go template renders banner + layout + script tags; existing JS builds DOM inside the container. Bridge pattern preserves all current chat functionality. - **Admin surface.** Full admin panel at `/admin/:section` with 5 category tabs (People, AI, Routing, System, Monitoring) and section sidebar. Server-rendered pages for providers, models, teams, users, and settings. Hybrid fallback for JS-loaded sections (groups, presets, knowledge, memory, health, capabilities, extensions, storage, usage, audit, stats). - **Editor surface.** Server-rendered layout shell at `/editor/:wsId` with proper CSS height ownership. `mountServerRendered()` method on `EditorMode` bypasses the Surfaces registry for Go template mode. Dedicated CSS owns full viewport below banners — no layout collision with other surfaces. **(Fixes bugs #4, #5: editor layout collapse)** - **Notes surface.** Server-rendered layout at `/notes/:noteId` with notes-main + notes-assist split. Boot script calls `openNotes()` in standalone mode. Responsive: assist pane hidden on mobile. - **Settings surface.** Full-page settings at `/settings/:section` replacing modal-based settings. Left nav with all sections (general, appearance, providers, models, presets, roles, knowledge, memory, notifications, usage). General and Appearance sections server-rendered with form controls; dynamic sections populated by existing JS. - **Login page.** Standalone Go template at `/login` with cookie-based auth. Sets `redirect_after_login` cookie for post-login navigation. - **`AuthOrRedirect` middleware.** Cookie-based JWT validation for page routes. Reads `sb_token` cookie, redirects to `/login` on missing/invalid token (instead of 401 JSON). `RequireAdminPage()` helper aborts with 403 for non-admin users. Skips auth entirely in unmanaged mode. - **Cookie-based auth sync.** `api.js` `saveTokens()` now sets `sb_token` cookie alongside localStorage on every token save/refresh. `clearTokens()` clears the cookie. Bridges API auth (Bearer header) with page auth (cookie). - **Reusable `model-select` component.** Go template partial renders `