Setup wizard

POST /api/bng/setup-wizard/apply                       admin_only

Applies a complete day-one configuration in a single call: service plans, address
pools, captive portal, RADIUS servers, data-plane interface selection, platform
identity, and the authentication mode. Each section is dispatched to the
controller independently, in a fixed order, inside its own error guard.

The call always returns 200. There is no aggregate failure status. Outcomes
are reported per section:

{
  "results": [
    { "section": "Plans",          "ok": true,  "detail": "2/2 applied" },
    { "section": "Pools",          "ok": false, "detail": "1/2 applied (poolB: 422)" },
    { "section": "Captive Portal", "ok": true,  "detail": "portal_ip=10.0.0.5 on 100.64.64.0/18" },
    { "section": "RADIUS",         "ok": true,  "detail": "auth=2, acct=2" },
    { "section": "Data Plane",     "ok": true,  "detail": "uplink=… access=…" },
    { "section": "Platform",       "ok": true,  "detail": "recorded: hostname=…, tz=…" },
    { "section": "Authentication", "ok": true,  "detail": "mode=radius" }
  ],
  "saved_at": 1782700000.0
}

The results array always contains exactly these seven entries in this order, so
a script can index them positionally. An automation must inspect every ok
field; a 200 alone does not mean the configuration applied.

Three sections are recorded rather than applied. Data-plane interface selection
is persisted for later finalisation on the dataplane workflow; platform identity
requires installer-level privilege; and the authentication mode is a settings
value rather than a controller call. The response details say so explicitly.

The submitted configuration is persisted as a wizard snapshot with RADIUS
secrets and the local password redacted
in the stored copy. The plaintext values
are of course forwarded to the controller, which needs them — the redaction
applies to the on-disk record.