Files
hiveops-guide/backend/src/main/resources/content/devices/device-groups/internal.md
T
johannes 2f94d62769 content(guide): role-tabs (Internal/Architect/Claude) for all 63 customer modules (DRAFT, Refs #1 #3)
Full role-tab rollout: every customer module now has Customer/Internal/
Architect/Claude tabs, grounded per-module in real code. Backend serves 296
docs / 96 modules. Grounding surfaced ~20 real bugs across services (filed
separately after verification).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 12:14:54 -04:00

4.7 KiB

module, title, tab, order, audience
module title tab order audience
devices.device-groups Device Groups Internal 20 internal

Internal · ops/support/admin. Grounded in hiveops-devices backend + AtmGroups.svelte (2026-07-01). Owner service: hiveops-devices (port 8096, DB hiveiq_devices).

What this module actually is

A CRUD screen over the atm_groups table plus its atm_group_members join table. Groups are named, colored collections of devices used for filtered device lists and bulk hardware-profile pushes. Deleting a group or dropping a device only touches the join table — no device is ever deleted.

Roles required

  • Read (list groups, view a group): any authenticated JWT. GET /api/atm-groups and GET /api/atm-groups/{id} have no @PreAuthorize — they are readable by any logged-in user, scoped by institution (see below).
  • All mutations (create, update, delete, assign ATMs, add/remove single ATM, assign hardware profile): @PreAuthorize("hasAnyRole('MSP_ADMIN','BCOS_ADMIN')"). A non-admin PUT/POST/DELETE returns 403.

Institution scoping (why a user "can't see a group")

AtmGroupService calls InstitutionContext.resolveScope() on every read/write:

  • scope null → full access (MSP/BCOS admin) — sees all groups.
  • scope empty list → sees zero groups.
  • scope non-empty → only groups whose institution_key is in scope (findAllWithAtmsByInstitutionKeyIn).
  • On create, if the caller is scoped to exactly one institution, the group's institution_key is forced to that key — the Institution dropdown selection in the form is ignored for single-institution users.

First thing to check when "my group vanished / I can't edit it": the caller's JWT institution scope vs the group's institution_key.

Admin-only actions on the screen

  • + New GroupPOST /api/atm-groups.
  • EditPUT /api/atm-groups/{id} (name/description/color/institution/membership; only non-null fields are applied).
  • Assign DevicesPUT /api/atm-groups/{id}/atms with a full [atmId, ...] list — this replaces the whole membership set, it is not additive.
  • Assign ProfilePOST /api/atm-groups/{id}/hardware-profile { "profileKey": "..." }, then the frontend fires a POST /fleet/tasks (CONFIG_UPDATE, patch atm.hardware.profile).
  • DeleteDELETE /api/atm-groups/{id}.

Set Default / Clear Default — NOT server state

The Set Default / ✕ Clear buttons are purely client-side. The chosen group id is stored in browser localStorage under key hiveops_defaultGroupId (stores.ts). It is:

  • per-browser, per-machine — never synced to the account or DB;
  • used only to pre-filter the device list (passes groupId to /api/atms/paginated).

"My default group didn't follow me to another machine" is expected behaviour, not a bug. To reset it: clear site data / localStorage.

Common failure modes + fixes

Symptom Likely cause Fix
409 / 500 on create or edit with terse message atm_groups.name is UNIQUE globally (not per-institution). A duplicate name — even across institutions — violates the constraint. server.error.include-message=never hides the detail. Pick a unique name; check DB for the colliding row.
403 on any save Caller lacks MSP_ADMIN/BCOS_ADMIN. Use an admin JWT.
Group list empty for a real user Institution scope is empty, or all groups are tied to institutions outside scope. Check JWT institutionKey claim / scope.
"Assign Profile" says N devices but no config lands on ATMs Two steps: profile save succeeded but the follow-up fleet task failed, or ATMs are offline/haven't polled. Check /fleet/tasks for the queued CONFIG_UPDATE; verify agents are polling.
Assigning devices wiped others out Assign Devices is a full replace, not add. Re-open, select the complete intended set.
Removed a device but it's "back" Edit form / Assign panel was opened from stale data. Reload groups (GET /api/atm-groups) and retry.
Group shows "All" institution but a scoped admin can still edit it verifyGroupAccess only blocks when institution_key is non-null. Null (All) groups are editable by any in-scope admin. Intended today; note it before blaming data.

Quick checks

# List groups (any authed JWT)
curl -s https://api.bcos.cloud/devices/api/atm-groups -H "Authorization: Bearer $JWT"

# DB: group + member counts
SELECT g.id, g.name, g.institution_key, count(m.atm_id) AS atms
FROM atm_groups g LEFT JOIN atm_group_members m ON m.group_id = g.id
GROUP BY g.id ORDER BY g.name;

See also [devices.device-groups] Overview (customer) and the Architect tab for data flow.