UniFi's /rest/apgroup endpoints (and per-SSID ap_group_ids writes via
/rest/wlanconf) require session-cookie auth — they don't accept the
X-API-Key header. The Integration API doesn't expose AP groups at all.
So with the current deployment running on API-key auth, every AP-group
operation returned 400 api.err.InvalidObject. Removing the dead code
rather than carrying a feature that can't function.
* Deleted ApGroupController, ApGroups.vue, the /ap-groups/* routes,
and getApGroups/createApGroup/updateApGroup/deleteApGroup from
UnifiApiClient.
* Removed the per-SSID AP-group assignment from Wifi.vue + the
updateApGroups action + /wifi/{wlanId}/ap-groups route + the
ap_group_ids field from the mapWlan output.
* Removed the AP Groups nav entry from composer.json.
If a future deploy adds local-admin username+password auth, AP groups
can be reintroduced — the UnifiApiClient::buildRequest() session-cookie
path is intact.
v1.3.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously SyncPpskSchedules returned early when the global setting
was disabled, leaving any PPSK that had been held by a prior sync
stuck in 'held' state. It also only iterated whereNotNull(schedule),
so null-schedule PPSKs ("always on") were never drift-corrected back
to active either.
Now the command always runs and computes a per-PPSK target state:
- global ppsk_scheduling disabled → target = active (always)
- global enabled + null schedule → target = active (always)
- global enabled + has schedule → follow the schedule's slot
PPSKs that drift from the target get enabled/disabled accordingly.
Schedules in unifi_ppsks.schedule are preserved across global toggles
either way — disabling the setting doesn't touch them, so re-enabling
resumes the operator's per-PPSK schedules.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The AP Groups page (ApGroups.vue + ApGroupController + UnifiApiClient
CRUD methods) has been built but never declared in composer.json's
pages list, so it was hidden from the menu. Added it at sort_order=6,
between WiFi Networks and Portal.
The WiFi Networks page already has per-SSID AP-group assignment via
the existing updateApGroups route — that wires into UniFi's standard
ap_group_ids field on wlanconf. (UniFi doesn't expose per-AP-only
assignment separately; the convention is "make a one-AP group for
this AP and assign the SSID to it.")
For the "always pull from UniFi on load" guarantee:
- getWlans() and getApGroups() are already uncached — fresh on every
page load
- getDevices() (feeds the AP picker for group membership) is cached
for unifi.cache_ttl seconds; both ApGroupController::index and
WifiController::index now Cache::forget('unifi:devices') before
reading so the device list is always fresh
v1.3.0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drops unifi.timezone from the settings form (now lives in
Admin → Settings on the shell). Schedulers (PPSK sync, password
rotation) now read \App\Support\Timezone::current() — same fallback
chain as the rest of the platform.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The /api/self/sites and /proxy/network/api/self/sites endpoints belong
to the legacy session-cookie API — they don't accept X-API-Key auth and
return 401 for keys generated in UniFi OS → Control Plane → Integrations.
Adds /proxy/network/integration/v1/sites as the first endpoint tried,
which is the actual home of API keys. Integration response rows look
like { id, internalReference, name }; getSites normalizes them to the
legacy { name, desc } shape using internalReference as the slug so
downstream URLs (which build paths from $this->site) keep working.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add password rotation: RotatePasswords console command + migration + service updates
- Add PPSK management: UnifiPpsk model, migration, SyncPpskSchedules console
- Add VLAN groups and AP groups: VlanGroupController, ApGroupController, model, migration
- Add RebootAllAps console command
- Add in_alert column to device states
- Wire new features through service provider, routes, and existing controllers/services
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>