Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
11 KiB
Scratchpad — Workflow Integration Modules: NinjaOne First Pass
- Plan slug:
2026-05-10-workflow-integration-modules-ninjaone - Created:
2026-05-10
What This Is
Rolling notes for adding first-party workflow integration modules and the first NinjaOne workflow module/actions.
Decisions
- (2026-05-10) Use a first-party workflow integration module registry instead of only action-prefix grouping. Rationale: integrations need tenant availability, icon/logo metadata, default action, and future extensibility without hardcoding each integration into the generic designer.
- (2026-05-10) Define NinjaOne “in use” as an active
rmm_integrationsrow withprovider = 'ninjaone',is_active = true, and non-nullconnected_at. - (2026-05-10) First pass will implement a mixed NinjaOne action set: find/list device, sync single device, reboot device, list active alerts, get alert, acknowledge alert.
- (2026-05-10) Do not add
ninjaone.alerts.create_ticket. Users should chain NinjaOne alert outputs into the generic Ticket module (tickets.create, etc.). This keeps PSA ticket behavior generic and avoids duplicated ticket rules. - (2026-05-10) Label
ninjaone.alerts.resetas Acknowledge alert in the UI. The technical action ID can reflect the NinjaOne API reset operation, but users should see MSP/operator terminology. - (2026-05-10) Any workflow editor can add/use NinjaOne workflow actions. No extra integration/action permission gate in this pass.
Discoveries / Constraints
- (2026-05-10) Review follow-up fixed package typecheck failures caused by Vitest
vi.mockthird-argument usage for@alga-psa/db/workDate; the package export exists, so the virtual flag was unnecessary. - (2026-05-10) Review follow-up fixed NinjaOne handler guards: local device query no longer references nonexistent
assets.hostname, alert DB reads/updates are scoped byintegration_id, timestamp outputs are normalized to ISO strings, and device IDs are coerced/validated as positive integers before side-effect calls. - (2026-05-10) Existing action catalog builder lives at
shared/workflow/runtime/designer/actionCatalog.tsand already groups unknown action prefixes intotileKind: 'app'records. - (2026-05-10) Existing designer catalog endpoint is backed by
listWorkflowDesignerActionCatalogActioninee/packages/workflows/src/actions/workflow-runtime-v2-actions.ts. - (2026-05-10) Existing app filtering only checks enabled extension installs via
tenant_extension_installandextension_registry; it does not handle first-party integration availability. - (2026-05-10) Current Workflow Designer icon mapping lives in
ee/server/src/components/workflow-designer/WorkflowDesigner.tsxingetPaletteIcon. - (2026-05-10) NinjaOne integration code already exists under
ee/server/src/lib/integrations/ninjaone/, includingninjaOneClient.ts,sync/syncEngine.ts, and alert/webhook handling. - (2026-05-10)
rmm_integrationsschema includesprovider,is_active,connected_at,instance_url, sync status fields, and tenant-scoped uniqueness on(tenant, provider). - (2026-05-10) Temporal activities import workflow runtime from
@alga-psa/workflows/runtime/core, so worker/runtime bootstrap must be considered carefully when adding EE/server-only NinjaOne registrations.
Commands / Runbooks
- (2026-05-10) Initial context commands used:
rg "WorkflowDesignerCatalog|actionCatalog|buildWorkflowDesignerActionCatalog|workflow module" -n server ee shared packagesrg "loadAvailableWorkflowDesignerAppKeys|availableAppKeys|integration" ee/packages/workflows/src/actions/workflow-runtime-v2-actions.ts server/src ee/server shared -nrg "rmm_integrations|ninjaone|quickbooks|xero|email_providers|calendar_providers|microsoft_profiles" ee/server/migrations server/migrations packages -nrg "NinjaOne|ninjaone|remote|device|alert|webhook|rmm" ee/server/src/lib/integrations/ninjaone packages/integrations/src/actions/integrations packages/integrations/src/lib/rmm -n
Links / References
shared/workflow/runtime/registries/actionRegistry.tsshared/workflow/runtime/designer/actionCatalog.tsshared/workflow/runtime/init.tsee/packages/workflows/src/runtime/bootstrap.tsee/packages/workflows/src/runtime/worker.tsee/packages/workflows/src/actions/workflow-runtime-v2-actions.tsserver/src/app/api/workflow/registry/designer-catalog/route.tsee/server/src/components/workflow-designer/WorkflowDesigner.tsxee/server/src/components/workflow-designer/GroupedActionConfigSection.tsxserver/migrations/20251124000001_create_rmm_integration_tables.cjsee/server/src/lib/integrations/ninjaone/ninjaOneClient.tsee/server/src/lib/integrations/ninjaone/sync/syncEngine.tsee/server/src/lib/integrations/ninjaone/alerts/alertProcessor.ts
Open Questions
- Should the first pass render a true NinjaOne SVG/logo asset, or is a
ninjaoneicon token mapped in the existing palette sufficient? - Should
ninjaone.devices.findbe local-only, live API-backed, or support both? Recommendation in PRD: local-first with optional live mode only if low risk.
Progress Updates
-
(2026-05-10) Implemented first-party workflow integration module registry in
shared/workflow/runtime/registries/integrationModuleRegistry.tswith duplicate-key protection and singleton accessor. -
(2026-05-10) Extended
buildWorkflowDesignerActionCatalogto accept explicit first-party app module definitions and produce stable app records from declarativeallowedActionIds. -
(2026-05-10) Added server-side first-party availability filtering keyed by
availabilityKeyinlistWorkflowDesignerActionCatalogAction; preserved extension install filtering path. -
(2026-05-10) Registered
app:ninjaonefirst-party workflow module in EE runtime core with icon tokenninjaone, default actionninjaone.devices.find, and explicit six-action allow-list. -
(2026-05-10) Added six NinjaOne workflow actions in
ee/packages/workflows/src/runtime/actions/registerNinjaOneWorkflowActions.ts:ninjaone.devices.findninjaone.devices.syncninjaone.devices.rebootninjaone.alerts.list_activeninjaone.alerts.getninjaone.alerts.reset(labelledAcknowledge alert)
-
(2026-05-10) Handlers now fail fast for missing tenant and inactive integration, use engine-provided idempotency for side-effectful operations, and return normalized non-secret outputs.
-
(2026-05-10) Mapped
ninjaoneicon token in Workflow Designer palette (WorkflowDesigner.tsx) for a distinct NinjaOne tile icon. -
(2026-05-10) Added registry pattern documentation for future integrations at
ee/docs/plans/2026-05-10-workflow-integration-modules-ninjaone/INTEGRATION_MODULE_REGISTRY.md. -
(2026-05-10) Added/updated tests:
shared/workflow/runtime/__tests__/workflowIntegrationModuleRegistry.test.ts(duplicate-key + metadata roundtrip)shared/workflow/runtime/__tests__/workflowDesignerActionCatalog.test.ts(explicit module record behavior)ee/packages/workflows/src/actions/workflow-runtime-v2-designer-catalog.integration-filtering.test.ts:T003active NinjaOne tenant includesapp:ninjaonein designer catalogT004inactive/missing NinjaOne excludesapp:ninjaoneT005extension app filtering still works with first-party filtering (app:acme.syncallowed when installed)
ee/packages/workflows/src/runtime/__tests__/ninjaOneWorkflowActions.registration.test.ts:T006verifies bootstrap and worker runtime entrypoints both register exactly the six NinjaOne action IDsT007verifies side-effect/idempotency metadata andninjaone.alerts.resetUI label/description (Acknowledge alert)T014verifies NinjaOne registry action input/output schemas are present and parse representativeaction.callconfiguration payloads
ee/server/src/components/workflow-designer/__tests__/ninjaOneDesignerCatalog.contract.test.ts:T015verifies NinjaOne grouped action options and explicitninjaoneicon token mapping contract inWorkflowDesigner.tsxT016verifies NinjaOne module does not include ticket-creation actions and generic Ticket module remains thetickets.createpath
ee/packages/workflows/src/runtime/actions/__tests__/ninjaOneWorkflowActions.handlers.test.ts:T008verifiesninjaone.devices.findhappy path (local lookup) returns normalized device output and does not leak secret-like source fieldsT009verifiesninjaone.devices.syncdelegates to sync strategy and returns synced identifiersT010verifiesninjaone.devices.rebootinactive-integration guard and successful reboot delegationT011verifiesninjaone.alerts.list_activeoutput includes alert/device/asset/severity/message fields for ticket mappingsT012verifiesninjaone.alerts.gethappy path and not-found behaviorT013verifiesninjaone.alerts.resetcalls NinjaOne reset operation and returns acknowledged output
-
(2026-05-10) Added targeted unit/integration-style coverage around
listWorkflowDesignerActionCatalogActionfilter behavior by mocking auth/runtime and exercisingrmm_integrationsplus extension-install query paths. Rationale: prove regression-safe catalog filtering without requiring full end-to-end server harness for this plan slice. -
(2026-05-10) Added runtime registration coverage using real runtime bootstrap/worker initialization and shared action registry reads. Included virtual test shim for
@alga-psa/db/workDateto satisfy shared runtime import graph in package-level Vitest execution. -
(2026-05-10) Added handler-level test harness for NinjaOne actions with mocked integration client/sync strategy imports and action-registry invocation to validate output contracts directly at handler boundary.
Validation Runbook
npx vitest run --config shared/vitest.config.ts shared/workflow/runtime/__tests__/workflowIntegrationModuleRegistry.test.ts shared/workflow/runtime/__tests__/workflowDesignerActionCatalog.test.tsnpx tsc -p ee/packages/workflows/tsconfig.json --noEmitcd ee/packages/workflows && npx vitest run src/actions/workflow-runtime-v2-designer-catalog.integration-filtering.test.tscd ee/packages/workflows && npx vitest run src/runtime/__tests__/ninjaOneWorkflowActions.registration.test.tscd ee/packages/workflows && npx vitest run src/runtime/actions/__tests__/ninjaOneWorkflowActions.handlers.test.tscd ee/server && npx vitest run src/components/workflow-designer/__tests__/ninjaOneDesignerCatalog.contract.test.ts
Gotchas
- Root vitest config does not discover
ee/packages/workflows/src/runtime/__tests__by default; shared runtime tests were executed viashared/vitest.config.ts. createNinjaOneClientsecond argument is region, not instance URL; workflow action handlers must call it with workflow context rather than raw URL.