# feat(#1508): config-driven disabled tabs in customizer modal
Fixes#1508.
## Why
The customizer modal mixes one-shot operator chrome (`branding`, `home`,
`geofilter`, `export`) with daily-use viewer toggles (`theme`, `nodes`,
`display`). Non-technical users get confused by the admin tabs and skip
past the controls they actually need. There's no current way to hide
individual tabs server-side — only via CSS, which doesn't prevent state
mutation.
## What
Adds a single operator knob: `customizer.disabledTabs` in `config.json`.
The named tab ids are filtered out of `_renderTabs()` in
`public/customize-v2.js` before render.
- `config.example.json` — new `customizer` block, default
`disabledTabs: []` (zero behavior change for existing operators).
- `cmd/server/config.go` — new `CustomizerConfig` type, optional pointer
on `Config`.
- `cmd/server/routes.go` + `cmd/server/types.go` — `/api/config/client`
now surfaces `customizer.disabledTabs` (always an array, empty when
unset).
- `public/customize-v2.js` — `_renderTabs()` filters by id.
- `cmd/server/customizer_disabled_tabs_test.go` — RED-then-green tests
covering both the configured-and-defaulted shapes.
## TDD trail
1. RED commit adds the failing tests + minimal `CustomizerConfig` stub
so the package still compiles; both tests fail on the assertion
(`body.customizer` is `<nil>`) — not on import.
2. GREEN commit wires the field through `/api/config/client` and the
frontend tab filter; both tests pass.
## Scope
5 files. No new API surface, no UI for editing the list (operator edits
`config.json` directly per the issue body). Backward-compatible: missing
`customizer` block defaults the list to empty.
---------
Co-authored-by: bot <bot@local>