Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
10 KiB
PRD — Tactical RMM Integration
- Slug:
tacticalrmm-integration - Date:
2026-02-13 - Status: Draft
Summary
Add a Tactical RMM integration that works in both Community Edition (CE) and Enterprise Edition (EE). The integration should:
- Connect to a Tactical RMM instance using either API key auth or username/password (Knox token) auth (including optional TOTP).
- Sync Tactical inventory into Alga Assets (clients/sites/agents -> clients/assets + mappings).
- Support near-real-time updates via Tactical alert-action webhooks (alerts only), plus optional alert backfill via the Tactical alerts API.
- Fit the existing multi-provider RMM platform patterns established by the NinjaOne integration (shared DB tables, org mapping, device sync, asset fields).
Problem
Alga currently has an RMM integration pattern (NinjaOne) that syncs devices and supports webhooks, but it is EE-oriented and provider-specific. We want to support Tactical RMM as an additional provider, available in both CE and EE, and integrate it cleanly into the existing Assets system and the “RMM” Integrations settings tab.
Goals
- CE + EE: Tactical RMM appears in Settings -> Integrations -> RMM and can be configured in both editions.
- Connection management:
- Support Tactical API key auth.
- Support Tactical username/password auth with TOTP handling (checkcreds + login).
- Store credentials securely (tenant secrets) and show masked status in UI.
- Inventory sync:
- Sync Tactical Clients into
rmm_organization_mappings. - Map Tactical Clients to Alga Clients (companies) via UI.
- Sync Tactical Agents into Alga Assets using the beta API at fleet scale.
- Sync Tactical Clients into
- Asset enrichment:
- Populate core RMM fields on
assets(rmm_provider,rmm_device_id,rmm_organization_id,agent_status,last_seen_at,last_rmm_sync_at). - Populate cached “RMM vitals” fields when available (current user, uptime, LAN/WAN IP).
- Add support for Tactical’s “overdue” state (distinct from offline).
- Populate core RMM fields on
- Realtime (alerts):
- Provide a webhook endpoint for Tactical alert actions with shared-secret header validation.
- On webhook receive, upsert
rmm_alertsand trigger a targeted “sync single agent” refresh.
- Optional: alerts backfill via Tactical alerts API for historical visibility.
Non-goals
- Remote access (MeshCentral / remote background): explicitly deferred.
- Full “device created/updated/deleted” webhooks (Tactical doesn’t provide them natively; only alerts).
- Patch deployment / remediation (scan + display only, if we even include scan hooks).
- Deep ticket-automation parity with NinjaOne (auto ticket creation/rules) unless explicitly requested later.
Users and Primary Flows
Primary user: MSP admin / system admin configuring integrations.
Flows:
- Configure Tactical:
- On the Tactical server, enable the Beta API: set
BETA_API_ENABLED = Trueand restart Tactical. - Open Settings -> Integrations -> RMM -> Tactical RMM.
- Enter the Tactical API host as the instance URL: the
api.subdomain (e.g.https://api.example.com), not the dashboard (rmm.) URL. - Choose auth mode:
- API key: paste key, save, verify.
- Username/password: enter creds, if TOTP required prompt for code, login, store token.
- On the Tactical server, enable the Beta API: set
- Sync Tactical Clients:
- Click “Sync Clients” (organizations).
- Map Tactical Clients to Alga Clients (companies) in an org mapping table.
- Sync Assets:
- Click “Sync Devices”.
- Alga upserts Assets and extension records and creates external mappings.
- Realtime alerts:
- Admin copies webhook URL + secret, configures Tactical alert-action webhook with
X-Alga-Webhook-Secret. - Alerts trigger/resolve -> Alga receives webhook -> stores alert -> refreshes affected asset.
- Admin copies webhook URL + secret, configures Tactical alert-action webhook with
- Optional: “Sync Alerts” to backfill alerts from Tactical.
UX / UI Notes
- Tactical RMM should appear next to NinjaOne under the Integrations “RMM” category tab.
- Settings card should match the “feel” of NinjaOne settings:
- Status panel (connected/disconnected, last sync, counts).
- Credential management section (masked + update).
- Sync buttons.
- Organization mapping section.
- Webhook section (URL, header name, secret, payload template).
- Since Tactical is CE + EE, the Tactical settings UI must not rely on EE-only dynamic imports.
Requirements
Functional Requirements
- Connection status
- Show whether Tactical is configured and reachable.
- Show instance URL and auth mode.
- Credential storage
- Store and retrieve per-tenant credentials via secret provider.
- Mask secrets in UI (show only last 4 chars).
- Sync clients (organizations)
- Fetch Tactical Clients via beta API.
- Upsert
rmm_organization_mappingsfor providertacticalrmm.
- Org mapping management
- Allow selecting an Alga Client for each Tactical Client mapping.
- Persist
auto_sync_assetstoggles.
- Sync devices (agents)
- For each mapped Tactical Client:
- fetch sites (paged) and agents (paged and filtered by
client_id). - upsert
assets+ extension data. - upsert
tenant_external_entity_mappingsfor the agent. - mark missing agents as inactive (optional; see Open Questions).
- fetch sites (paged) and agents (paged and filtered by
- For each mapped Tactical Client:
- Agent status mapping
- Compute
online|offline|overdueusing the provided deterministic rules fromlast_seen,offline_time,overdue_time. - Persist status to
assets.agent_status.
- Compute
- Realtime alerts via webhooks
- Provide
POST /api/webhooks/tacticalrmm. - Validate
X-Alga-Webhook-Secret. - Accept a small JSON contract (required:
agent_id; optional:alert_id,event,severity,message,alert_time,client_id,site_id). - Upsert
rmm_alertsand associate to an asset when possible. - Trigger “sync single agent” after alert receives/resolves.
- Provide
- Alert backfill (optional but planned)
- Use Tactical alerts endpoint to fetch active/recent alerts and upsert into
rmm_alerts.
- Use Tactical alerts endpoint to fetch active/recent alerts and upsert into
- Software inventory ingestion (bulk, cached)
- Use Tactical
GET /software/to ingest cached software inventory without per-agent refresh.
- Use Tactical
Non-functional Requirements
- Fleet-scale pagination: use beta endpoints with
page_size=1000and loop pages. - Resilience:
- Handle 401 by re-authing (username/password mode) or failing with actionable error (API key mode).
- Avoid per-agent “refresh” calls by default (software refresh is expensive).
- Multi-provider safety: Tactical must not break NinjaOne; providers must co-exist in the same tenant.
Data / API / Integrations
Point the integration at the Tactical API host (the api. subdomain), for example https://api.example.com. Do not use the dashboard host (rmm.). The dashboard serves the single-page app and returns its HTML with a 200 for every path, so sync reads zero records and silently does nothing.
Tactical's Beta API must be enabled for inventory sync. Set BETA_API_ENABLED = True in Tactical and restart it. While it is off, the /beta/v1/* endpoints return 404 and both the connection test and sync fail.
Tactical endpoints (base URL https://<tactical-api-host>, served at the root with no /api prefix):
- Auth (username/password):
POST /v2/checkcreds/{ username, password }->{ totp: true }or short-lived tokenPOST /v2/login/{ username, password, twofactor? }-> Knox token response- Auth header:
Authorization: Token <knox_token>
- Auth (api key):
- Auth header:
X-API-KEY: <key>
- Auth header:
- Inventory (beta API, requires
BETA_API_ENABLED):GET /beta/v1/client/GET /beta/v1/site/?page_size=1000&page=NGET /beta/v1/agent/?client_id=<client_pk>&page_size=1000&page=N
- Alerts:
PATCH /alerts/with filter body for backfill/top-N
- Software:
GET /software/bulk cached software inventoryPUT /software/<agent_id>/per-agent refresh (non-goal by default)
Alga DB tables involved:
rmm_integrations(one row per tenant+provider; store instance_url, is_active, settings JSON including webhook secret and auth mode).rmm_organization_mappings(Tactical Client PK mapped to Alga Client).assets+ extension tables (workstation/server fields; cached “vitals” fields already exist).tenant_external_entity_mappings(agent_id crosswalk; store client/site in metadata).rmm_alertsfor alert ingestion and association.
Security / Permissions
- Configuration actions require settings permissions (same posture as NinjaOne).
- Secrets stored in tenant secret store (never in plaintext in DB tables).
- Webhook endpoint is unauthenticated but must require shared-secret header and be explicitly enabled/configured by admin.
Observability
- Minimal: structured logs for sync start/finish/errors and webhook receives.
- (Optional) publish existing event-bus events where appropriate (RMM_WEBHOOK_RECEIVED, RMM_DEVICE_UPDATED, etc.) to align with NinjaOne patterns.
Rollout / Migration
- Add
tacticalrmmprovider to RMM provider unions in Typescript. - Potential migration if we choose to add new agent status value (
overdue) to UI filters and any code expecting only online/offline/unknown. - Ensure
/api/webhooks/tacticalrmmis added to API auth middleware skip paths.
Open Questions
- Should we treat Tactical “overdue” as a first-class
agent_statusenum value everywhere (recommended), or map it tooffline? - Do we support marking assets as inactive when agents disappear from Tactical (requires a “full inventory snapshot” delete detection)?
- Asset type mapping: do we classify Tactical agents as workstation vs server based on OS string heuristics, or introduce a Tactical-specific mapping override?
- Should alert backfill be limited to “active only” or allow recent resolved (time window)?
Acceptance Criteria (Definition of Done)
- Tactical RMM is visible and configurable in CE and EE under Integrations -> RMM.
- Admin can connect using API key or username/password (with TOTP when required), and connection status is shown.
- Admin can sync Tactical Clients and map them to Alga Clients.
- Admin can sync Tactical Agents into Alga Assets; assets show provider + agent status + last seen where available.
- Tactical alert-action webhook can be configured with custom headers; Alga validates
X-Alga-Webhook-Secret, records alerts, and refreshes the affected asset. - Optional: alerts backfill and bulk software inventory ingestion work without per-agent refresh calls.