From 66063b08eddabd82116a5a75efda4a1e521dee3c Mon Sep 17 00:00:00 2001 From: Jeffrey Smith Date: Fri, 27 Mar 2026 15:38:42 +0000 Subject: [PATCH 1/2] Feat v0.2.7 user settings audit (#11) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Audit all 6 user settings sections. Remove dead chat-era code, rename localStorage namespace, clean up stale backend policies. - Remove BYOK nav section (empty BYOK_ITEMS, byokEnabled state, "BYOK Enabled" badge) and personas gate filter from settings nav - Remove auth.permissions.changed listener (existed solely for dead BYOK + personas state) - Remove Message Font Size slider, msgFont state, and --msg-font CSS variable application from appearance section and base template - Rename localStorage key cs-appearance → sb-appearance with one-time migration preserving existing user preferences - Remove allow_user_byok and allow_user_personas from PolicyDefaults, profile bootstrap, permissions handler, PublicSettings, and test seeds - Remove orphaned .settings-nav-footer CSS class - Replace stale policy-gating test assertions with allow_registration Co-Authored-By: Claude Opus 4.6 (1M context) --- CHANGELOG.md | 26 +++++++++++++ ROADMAP.md | 4 +- server/database/testhelper.go | 4 -- server/handlers/admin.go | 1 - server/handlers/profile_bootstrap.go | 4 -- server/handlers/profile_permissions.go | 4 -- server/models/models.go | 6 +-- server/pages/templates/base.html | 5 +-- server/pages/templates/workflow.html | 2 +- src/css/surfaces.css | 3 -- src/js/__tests__/policy-gating.test.js | 11 ++---- src/js/sw/surfaces/settings/appearance.js | 29 +++++--------- src/js/sw/surfaces/settings/index.js | 46 +---------------------- 13 files changed, 48 insertions(+), 97 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce1980d..d0baeca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,32 @@ All notable changes to Switchboard Core are documented here. +## [Unreleased] — v0.2.7 + +### Changed + +- **localStorage namespace**: Renamed `cs-appearance` key to `sb-appearance` + across appearance settings, base template, and workflow template. One-time + migration preserves existing user preferences. +- **Policy-gating tests**: Replaced stale `allow_user_byok` / `allow_user_personas` + assertions with `allow_registration` check (the only policy still in admin UI). + +### Removed + +- **Dead BYOK nav section** in user settings: empty `BYOK_ITEMS` array, + `byokEnabled` state, "BYOK Enabled" footer badge, and the nav group + that rendered an empty section. +- **Dead personas gate**: `personasEnabled` state and `.filter()` on + NAV_ITEMS for a `gate` property no items have. `auth.permissions.changed` + listener removed (existed solely for BYOK + personas state). +- **Dead Message Font Size**: Slider, `msgFont` state, and `--msg-font` + CSS variable application from appearance section and base template. +- **Dead policy defaults**: `allow_user_byok` and `allow_user_personas` + removed from `PolicyDefaults`, profile bootstrap, permissions handler, + and `PublicSettings`. Test seed data cleaned. + +--- + ## [Unreleased] — v0.2.6 ### Changed diff --git a/ROADMAP.md b/ROADMAP.md index adbeb88..7c0d5c8 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -100,8 +100,8 @@ SDK stabilization, and the first rebuilt extension (tasks). | Step | Status | Description | |------|--------|-------------| -| User settings E2E | ⬚ | Verify all user settings sections: General (default surface), Appearance (theme, scale, font), Profile (display name, avatar, handle), Connections, Notifications. Remove dead features, fix broken states. | -| Visibility gating | ⬚ | Ensure settings sections only show features that are actually available. Hide empty sections. Respect `user_overridable` flag from extension manifests. | +| User settings E2E | ✅ | All 6 user settings sections verified (General, Appearance, Profile, Teams, Connections, Notifications). Dead code removed: BYOK nav section + state, personas gate filter, Message Font Size slider, `auth.permissions.changed` listener. localStorage key renamed `cs-appearance` → `sb-appearance` with one-time migration. | +| Visibility gating | ✅ | Dead BYOK/personas policy lookups removed from bootstrap and permissions handlers. `allow_user_byok` removed from `PublicSettings`. `PolicyDefaults` cleaned of `allow_user_byok` and `allow_user_personas`. Dead `msgFont` early-apply removed from base template. Stale policy-gating test assertions replaced. No empty nav sections remain. | ### v0.2.8 — Team Admin Settings Audit (Pass 1) diff --git a/server/database/testhelper.go b/server/database/testhelper.go index 1eb2a23..4126ce0 100644 --- a/server/database/testhelper.go +++ b/server/database/testhelper.go @@ -340,8 +340,6 @@ func TruncateAll(t *testing.T) { `) DB.Exec(` INSERT INTO platform_policies (key, value) VALUES - ('allow_user_byok', 'false'), - ('allow_user_personas', 'false'), ('allow_registration', 'true'), ('default_user_active', 'false'), ('allow_team_providers', 'true') @@ -357,8 +355,6 @@ func TruncateAll(t *testing.T) { `) DB.Exec(` INSERT INTO platform_policies (key, value) VALUES - ('allow_user_byok', 'false'), - ('allow_user_personas', 'false'), ('allow_registration', 'true'), ('default_user_active', 'false'), ('allow_team_providers', 'true') diff --git a/server/handlers/admin.go b/server/handlers/admin.go index b0ba4e0..3b230b1 100644 --- a/server/handlers/admin.go +++ b/server/handlers/admin.go @@ -369,7 +369,6 @@ func (h *AdminHandler) PublicSettings(c *gin.Context) { "storage_configured": storageConfigured, "policies": gin.H{ "allow_registration": policies["allow_registration"], - "allow_user_byok": policies["allow_user_byok"], }, }) } diff --git a/server/handlers/profile_bootstrap.go b/server/handlers/profile_bootstrap.go index 205f698..85b2e0d 100644 --- a/server/handlers/profile_bootstrap.go +++ b/server/handlers/profile_bootstrap.go @@ -83,10 +83,6 @@ func (h *ProfileBootstrapHandler) GetBootstrap(c *gin.Context) { // ── Policies ──────────────────────────── policies := make(map[string]bool) - if ps := h.stores.Policies; ps != nil { - policies["allow_user_byok"], _ = ps.GetBool(ctx, "allow_user_byok") - policies["allow_user_personas"], _ = ps.GetBool(ctx, "allow_user_personas") - } // ── Settings ──────────────────────────── settings := make(map[string]interface{}) diff --git a/server/handlers/profile_permissions.go b/server/handlers/profile_permissions.go index a972bca..1db1e10 100644 --- a/server/handlers/profile_permissions.go +++ b/server/handlers/profile_permissions.go @@ -64,10 +64,6 @@ func (h *ProfilePermissionsHandler) GetMyPermissions(c *gin.Context) { // Policies that affect UI gating policies := make(map[string]bool) - if ps := h.stores.Policies; ps != nil { - policies["allow_user_byok"], _ = ps.GetBool(ctx, "allow_user_byok") - policies["allow_user_personas"], _ = ps.GetBool(ctx, "allow_user_personas") - } c.JSON(http.StatusOK, gin.H{ "permissions": list, diff --git a/server/models/models.go b/server/models/models.go index a988d29..076eb1d 100644 --- a/server/models/models.go +++ b/server/models/models.go @@ -84,10 +84,8 @@ type TeamMember struct { // PLATFORM POLICIES var PolicyDefaults = map[string]string{ - "allow_user_byok": "false", - "allow_user_personas": "false", - "allow_registration": "true", - "default_user_active": "false", + "allow_registration": "true", + "default_user_active": "false", "allow_team_providers": "true", } diff --git a/server/pages/templates/base.html b/server/pages/templates/base.html index 59e77bc..8179c26 100644 --- a/server/pages/templates/base.html +++ b/server/pages/templates/base.html @@ -51,11 +51,11 @@ if (fav) fav.href = fav.href.replace(/favicon(-light)?\.svg/, resolved === 'light' ? 'favicon-light.svg' : 'favicon.svg'); } catch(e) {} })(); - // Early appearance — apply scale + msg font from localStorage on all surfaces. + // Early appearance — apply scale from localStorage on all surfaces. // Scale uses transform on .surface-inner so shell stays fixed, content fills viewport. (function() { try { - var p = JSON.parse(localStorage.getItem('cs-appearance') || '{}'); + var p = JSON.parse(localStorage.getItem('sb-appearance') || '{}'); if (p.scale && p.scale !== 100) { var s = p.scale / 100; document.addEventListener('DOMContentLoaded', function() { @@ -63,7 +63,6 @@ if (el) { el.style.transform = 'scale('+s+')'; el.style.transformOrigin = 'top left'; el.style.width = (100/s)+'%'; el.style.height = (100/s)+'%'; } }); } - if (p.msgFont && p.msgFont !== 14) document.documentElement.style.setProperty('--msg-font', p.msgFont + 'px'); } catch(e) {} })(); diff --git a/server/pages/templates/workflow.html b/server/pages/templates/workflow.html index b51a15c..e6efdd2 100644 --- a/server/pages/templates/workflow.html +++ b/server/pages/templates/workflow.html @@ -163,7 +163,7 @@