One code-grounded internal guide per backend service (Responsibility / Data / Kafka / API surface / Gotchas), authored by parallel per-service agents reading each service's own source, then an adversarial verify pass (DB names, topics, endpoints spot-checked against code — 0 hard errors). Several guides correctly document CODE over stale CLAUDE.md (remote = HTTP long-poll not WebSocket; analytics = has a DB, not stateless; devices = has its own backend). Unconfirmed facts are marked (unverified). audience: internal, all DRAFT. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6.6 KiB
module, title, tab, order, audience
| module | title | tab | order | audience |
|---|---|---|---|---|
| technical.devices | Devices — device management & source of truth for device data | Overview | 10 | internal |
DRAFT · internal. Written 2026-07-01 from hiveops-devices source. Verify against code before relying on specifics.
Responsibility
hiveops-devices (Spring Boot backend, backend/, artifact hiveops-devices, port 8096) is the system of record for everything device/ATM-related: device inventory, groups, makes/models, custom field definitions, cassette configurations, agent tokens, agent profiles/scripts, per-institution agent properties, and config/hardware change tracking. It also serves the agent-facing internal endpoints (registration, heartbeat, config/hardware sync, log & module upload). It publishes device changes on Kafka so mirror consumers (incident/fleet/reports/recon) stay in sync. See [platform.service-ownership].
Note: the repo
CLAUDE.mdis stale on this point — it claims "no dedicated devices microservice / calls hiveops-incident." The backend underbackend/is real and owns these domains. The frontend (port 5177,devices.bcos.cloud) is the SPA layer.
Data
- Database:
hiveiq_devices(spring.datasource.urldefaultjdbc:postgresql://localhost:5432/hiveiq_devices, overridable via envDB_URL).ddl-auto=validate; schema managed by Flyway (V1–V16). See [platform.data-stores]. - Key tables / entities:
| Table | Entity | Purpose |
|---|---|---|
atms |
Atm |
Core device inventory (source of truth) |
atm_properties |
AtmProperties |
Per-device properties |
atm_groups |
AtmGroup |
Device groupings |
atm_make / atm_model |
AtmMake / AtmModel |
Make/model catalog |
atm_field_definitions |
AtmFieldDefinition |
Custom field defs |
atm_config_changes / atm_hardware_changes |
AtmConfigChange / AtmHardwareChange |
Config/hardware change audit |
atm_module_status |
AtmModuleStatus |
Per-device module state |
atm_log_collects |
AtmLogCollect |
Log collection records |
cassette_configurations / cassette_slots |
CassetteConfiguration / CassetteSlot |
Cassette templates |
device_cassette_config |
DeviceCassetteConfig |
Per-device cassette config |
agent_tokens |
AgentToken |
Agent auth tokens |
agent_profiles |
AgentProfile |
Agent config profiles |
agent_scripts |
AgentScript |
Pushable agent scripts |
institution_keys |
InstitutionKey |
Institution key registry |
institution_agent_properties |
InstitutionAgentProperties |
Per-institution agent props |
institution_config_audit |
InstitutionConfigAudit |
Institution config audit trail |
device_fleet_tasks |
DeviceFleetTask |
Fleet task mirror for devices |
atm_service_schedule |
AtmServiceSchedule |
Service schedule |
Kafka
Bootstrap: KAFKA_BOOTSTRAP_SERVERS (default kafka:29092). Trusted deserializer packages: com.hiveops.devices.kafka, com.hiveops.journal.kafka. See [platform.kafka].
Produced:
| Topic | Producer class | Notes |
|---|---|---|
hiveops.device.events |
DeviceEventPublisher (constant KafkaProducerConfig.DEVICE_EVENTS_TOPIC) |
keyed by atmId; DeviceEventType = DEVICE_CREATED, DEVICE_UPDATED, DEVICE_DELETED |
Consumed:
| Topic | Listener class |
|---|---|
hiveops.fleet.task.events (FleetTaskKafkaConfig.TOPIC) |
FleetTaskEventConsumer |
journal.replenishments (ReplenishmentKafkaConfig.TOPIC) |
ReplenishmentConsumer |
API surface
Admin controllers require JWT with role MSP_ADMIN or BCOS_ADMIN on mutating endpoints. Many device paths carry a Phase-2 /api/devices* alias alongside the legacy /api/atms* path.
Base paths: /api/atms + /api/devices, /api/atm-groups, /api/atm-makes, /api/atm-models, /api/atm-field-definitions, /api/cassette-configurations, /api/institution-keys, /api/agent-tokens, /api/agent-profiles, /api/fleet/scripts, /api/internal/*.
| Method + Path | Purpose |
|---|---|
GET /api/atms (alias /api/devices) |
List devices |
GET /api/atms/paginated |
Paginated/filterable device list |
GET /api/atms/{id} |
Device detail |
GET /api/atms/dashboard/stats |
Fleet dashboard stats |
GET /api/atms/summary |
Device summary |
POST /api/atms |
Create device (admin) |
PATCH /api/atms/{id}/institution |
Reassign institution (admin) |
POST /api/atms/config/sync · /api/atms/hardware/sync |
Config/hardware sync ingest |
GET /api/atm-groups · POST /api/atm-groups/{id}/atms/{atmId} |
Groups + membership |
GET/POST /api/cassette-configurations |
Cassette templates |
GET /api/devices/cassette-config |
Resolve device cassette config |
GET/POST /api/institution-keys · GET /api/institution-keys/{key}/agent-properties |
Institution keys + agent props |
GET/POST /api/agent-tokens · POST /api/agent-tokens/{id}/revoke |
Agent token lifecycle |
GET/POST/PUT/DELETE /api/agent-profiles · GET /api/agent-profiles/modules-manifest |
Agent profiles + CDN modules manifest proxy |
POST /api/internal/atms/register |
Agent auto-registration (INTERNAL) |
POST /api/internal/atms/agent/{country}/{atm}/heartbeat |
Agent heartbeat (INTERNAL) |
POST /api/internal/agent-tokens/validate |
Token validation (INTERNAL) |
Gotchas
- Stale CLAUDE.md.
hiveops-devices/CLAUDE.mdsays the app has no backend and callshiveops-incident; that's outdated — thebackend/service exists and owns these domains. - DB uses
DB_URL(full JDBC URL) viaspring.datasource.url=${DB_URL:...}, not split host/port/name vars. - Two auth realms. Admin controllers use
@PreAuthorize("hasAnyRole('MSP_ADMIN','BCOS_ADMIN')"); internal/agent controllers (/api/internal/*) usehasRole('INTERNAL')(e.g.InternalAtmController,AgentTokenInternalController,InternalLogController). - Phase-2 path aliases.
/api/atms,/api/atm-groups,/api/atm-makes,/api/atm-models,/api/atm-field-definitionseach also respond on a/api/device*alias for the ongoing ATM→device rename; both must stay routable in nginx. - CDN token.
agent.cdn.token(envCDN_TOKEN) has a hardcoded fallback inapplication.propertiesused by the/api/agent-profiles/modules-manifestproxy. - Publish-on-every-change. Device mirrors in incident/fleet/reports/recon depend on
hiveops.device.events; any write path that skipsDeviceEventPublisherleaves those mirrors stale (no reconciler). - Error message hiding.
server.error.include-message=neverandmanagement.endpoint.health.show-details=never— expect terse errors in prod.