Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

677 lines
17 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[
{
"id": "F001",
"description": "Corrective migration adds activity_type, acknowledged_at, acknowledged_by columns to rmm_alerts",
"implemented": true,
"prdRefs": [
"FR-1"
]
},
{
"id": "F002",
"description": "Migration adds dedup_key to rmm_alerts with index on (tenant, integration_id, dedup_key)",
"implemented": true,
"prdRefs": [
"FR-1"
]
},
{
"id": "F003",
"description": "Migration adds occurrence_count (default 1) and last_occurrence_at to rmm_alerts",
"implemented": true,
"prdRefs": [
"FR-1"
]
},
{
"id": "F004",
"description": "Migration adds nullable matched_rule_id to rmm_alerts",
"implemented": true,
"prdRefs": [
"FR-1"
]
},
{
"id": "F005",
"description": "Migration adds auto_ticket_created (default false) to rmm_alerts",
"implemented": true,
"prdRefs": [
"FR-1"
]
},
{
"id": "F006",
"description": "Migration adds conditions and actions jsonb (default {}) to rmm_alert_rules",
"implemented": true,
"prdRefs": [
"FR-1"
]
},
{
"id": "F007",
"description": "Migration drops the eleven flat filter/action columns from rmm_alert_rules",
"implemented": true,
"prdRefs": [
"FR-1"
]
},
{
"id": "F008",
"description": "Migration down() restores the prior schema",
"implemented": true,
"prdRefs": [
"FR-1"
]
},
{
"id": "F009",
"description": "NormalizedRmmAlertEvent contract defined in shared/rmm/alerts/contracts.ts with kind triggered|reset|acknowledged",
"implemented": true,
"prdRefs": [
"FR-2"
]
},
{
"id": "F010",
"description": "RmmAlertOutboundAdapter interface with per-provider resolution; providers without an adapter are skipped",
"implemented": true,
"prdRefs": [
"FR-2",
"FR-5"
]
},
{
"id": "F011",
"description": "Shared Zod schemas for rule conditions and actions JSONB shapes",
"implemented": true,
"prdRefs": [
"FR-2",
"FR-6"
]
},
{
"id": "F012",
"description": "mapNinjaOneWebhookToAlertEvent normalizer: field mapping, severity normalization, condition identity from statusCode falling back to activityType",
"implemented": true,
"prdRefs": [
"FR-2"
]
},
{
"id": "F013",
"description": "TacticalRMM payload normalizer producing NormalizedRmmAlertEvent",
"implemented": true,
"prdRefs": [
"FR-2"
]
},
{
"id": "F014",
"description": "NinjaOne webhook routes CONDITION TRIGGERED/RESET/ACKNOWLEDGED through processRmmAlertEvent, replacing inline rmm_alerts writes; auth/tenant-resolution/tier gating unchanged",
"implemented": true,
"prdRefs": [
"FR-2",
"FR-3"
]
},
{
"id": "F015",
"description": "Tactical webhook routes alert payloads through processRmmAlertEvent, replacing its direct rmm_alerts writes",
"implemented": true,
"prdRefs": [
"FR-2",
"FR-3"
]
},
{
"id": "F016",
"description": "processRmmAlertEvent entry point dispatches by event kind",
"implemented": true,
"prdRefs": [
"FR-3"
]
},
{
"id": "F017",
"description": "Triggered events upsert rmm_alerts on (tenant, integration_id, external_alert_id) with raw payload stored in metadata jsonb",
"implemented": true,
"prdRefs": [
"FR-3"
]
},
{
"id": "F018",
"description": "dedup_key computed from device + condition identity and stored on the alert row",
"implemented": true,
"prdRefs": [
"FR-3"
]
},
{
"id": "F019",
"description": "Rule evaluation selects active rules for the integration ordered by priority_order; first match wins",
"implemented": true,
"prdRefs": [
"FR-3"
]
},
{
"id": "F020",
"description": "All present condition fields must match: severities, activityTypes, alertClasses, sourceTypes, organizationIds, keywords",
"implemented": true,
"prdRefs": [
"FR-3"
]
},
{
"id": "F021",
"description": "messagePattern regex condition evaluated; a rule that fails to evaluate is logged and skipped without aborting the pipeline",
"implemented": true,
"prdRefs": [
"FR-3"
]
},
{
"id": "F022",
"description": "A rule with an empty conditions object matches every alert (catch-all)",
"implemented": true,
"prdRefs": [
"FR-3"
]
},
{
"id": "F023",
"description": "matched_rule_id persisted on the alert row for later lifecycle decisions",
"implemented": true,
"prdRefs": [
"FR-3"
]
},
{
"id": "F024",
"description": "No matching rule, or matched rule with createTicket false, stores the alert without creating a ticket",
"implemented": true,
"prdRefs": [
"FR-3",
"FR-4"
]
},
{
"id": "F025",
"description": "Dedup: alert whose dedup_key matches an alert with a still-open linked ticket joins that ticket and increments occurrence_count / last_occurrence_at",
"implemented": true,
"prdRefs": [
"FR-4"
]
},
{
"id": "F026",
"description": "Dedup repeat adds an internal 're-triggered — Nth occurrence' comment to the existing ticket",
"implemented": true,
"prdRefs": [
"FR-4"
]
},
{
"id": "F027",
"description": "No open dedup ticket: a new ticket is created via the shared alert ticket creator",
"implemented": true,
"prdRefs": [
"FR-4"
]
},
{
"id": "F028",
"description": "Ticket creation honors rule actions boardId, priorityOverride, and assignToUserId",
"implemented": true,
"prdRefs": [
"FR-4"
]
},
{
"id": "F029",
"description": "Severity-to-priority fallback mapping applies when no priorityOverride is set",
"implemented": true,
"prdRefs": [
"FR-4"
]
},
{
"id": "F030",
"description": "Ticket templates render {{device}}, {{message}}, {{severity}}, {{organization}} placeholders, with sensible defaults when no template is set",
"implemented": true,
"prdRefs": [
"FR-4"
]
},
{
"id": "F031",
"description": "Created tickets get source + source_reference, an asset association, and an initial internal comment with alert details",
"implemented": true,
"prdRefs": [
"FR-4"
]
},
{
"id": "F032",
"description": "Client resolution for the ticket: the asset's client, else the organization mapping's client",
"implemented": true,
"prdRefs": [
"FR-4"
]
},
{
"id": "F033",
"description": "auto_ticket_created set and ticket_id stored on the alert row after ticket creation",
"implemented": true,
"prdRefs": [
"FR-4"
]
},
{
"id": "F034",
"description": "Reset events mark the alert resolved and set resolved_at",
"implemented": true,
"prdRefs": [
"FR-5"
]
},
{
"id": "F035",
"description": "Reset with a linked ticket and rule autoResolveTicket always adds a resolution comment; without the flag the ticket is untouched",
"implemented": true,
"prdRefs": [
"FR-5"
]
},
{
"id": "F036",
"description": "Untouched determination: no human-authored comments, no time entries, no manual status change; rule auto-assignment does not count",
"implemented": true,
"prdRefs": [
"FR-5"
]
},
{
"id": "F037",
"description": "Untouched tickets close via actions.autoResolveStatusId, else the tenant's first is_closed status",
"implemented": true,
"prdRefs": [
"FR-5"
]
},
{
"id": "F038",
"description": "Touched tickets stay open after alert reset (comment only)",
"implemented": true,
"prdRefs": [
"FR-5"
]
},
{
"id": "F039",
"description": "Acknowledged events set alert status acknowledged with acknowledged_at/acknowledged_by",
"implemented": true,
"prdRefs": [
"FR-5"
]
},
{
"id": "F040",
"description": "Ticket-closed event-bus subscriber finds unresolved linked alerts by ticket_id and honors the matched rule's resetAlertOnTicketClose (default true)",
"implemented": true,
"prdRefs": [
"FR-5"
]
},
{
"id": "F041",
"description": "NinjaOne outbound adapter resets the alert via NinjaOneClient.resetAlert and updates the local alert status",
"implemented": true,
"prdRefs": [
"FR-5"
]
},
{
"id": "F042",
"description": "Outbound reset failures are logged and stamped into alert metadata and never block the ticket close",
"implemented": true,
"prdRefs": [
"FR-5"
]
},
{
"id": "F043",
"description": "Tactical outbound adapter implemented if its API supports alert resolution; otherwise the provider ships without an adapter and the pipeline skips outbound reset",
"implemented": true,
"prdRefs": [
"FR-5"
]
},
{
"id": "F044",
"description": "listRmmAlertRules server action returns rules for an integration ordered by priority_order",
"implemented": true,
"prdRefs": [
"FR-6"
]
},
{
"id": "F045",
"description": "createRmmAlertRule server action validates conditions/actions against the shared Zod schemas",
"implemented": true,
"prdRefs": [
"FR-6"
]
},
{
"id": "F046",
"description": "updateRmmAlertRule server action",
"implemented": true,
"prdRefs": [
"FR-6"
]
},
{
"id": "F047",
"description": "deleteRmmAlertRule server action",
"implemented": true,
"prdRefs": [
"FR-6"
]
},
{
"id": "F048",
"description": "reorderRmmAlertRules server action updates priority_order",
"implemented": true,
"prdRefs": [
"FR-6"
]
},
{
"id": "F049",
"description": "All rule CRUD actions are admin-gated and tenant-scoped",
"implemented": true,
"prdRefs": [
"FR-6"
]
},
{
"id": "F050",
"description": "Save-time validation rejects an invalid messagePattern regex",
"implemented": true,
"prdRefs": [
"FR-6"
]
},
{
"id": "F051",
"description": "Alert Rules section renders in RMM integration settings for both NinjaOne and TacticalRMM",
"implemented": true,
"prdRefs": [
"FR-7"
]
},
{
"id": "F052",
"description": "Rules list is priority-ordered with active toggle, reorder controls, edit and delete",
"implemented": true,
"prdRefs": [
"FR-7"
]
},
{
"id": "F053",
"description": "Rule editor Match group: severities, activity types, alert classes, source types, keywords, message regex",
"implemented": true,
"prdRefs": [
"FR-7"
]
},
{
"id": "F054",
"description": "Rule editor organization picker fed from rmm_organization_mappings",
"implemented": true,
"prdRefs": [
"FR-7"
]
},
{
"id": "F055",
"description": "Rule editor Actions group: create-ticket toggle, board picker, priority override, assignee picker",
"implemented": true,
"prdRefs": [
"FR-7"
]
},
{
"id": "F056",
"description": "Rule editor title/description template inputs with placeholder hints",
"implemented": true,
"prdRefs": [
"FR-7"
]
},
{
"id": "F057",
"description": "Rule editor autoResolveTicket and resetAlertOnTicketClose toggles and notify-users picker",
"implemented": true,
"prdRefs": [
"FR-7"
]
},
{
"id": "F058",
"description": "Rule editor surfaces validation errors inline; delete requires confirmation",
"implemented": true,
"prdRefs": [
"FR-7"
]
},
{
"id": "F059",
"description": "RMM_ALERT_TRIGGERED registered in the workflow v2 event catalog with a provider-generic payload schema",
"implemented": true,
"prdRefs": [
"FR-8"
]
},
{
"id": "F060",
"description": "RMM_ALERT_RESOLVED registered in the workflow v2 event catalog",
"implemented": true,
"prdRefs": [
"FR-8"
]
},
{
"id": "F061",
"description": "Pipeline publishes the workflow v2 alert events, replacing the orphaned legacy-bus publishes",
"implemented": true,
"prdRefs": [
"FR-8"
]
},
{
"id": "F062",
"description": "rmm.alerts.create_ticket workflow action invokes the shared ticket creator by alert ID",
"implemented": true,
"prdRefs": [
"FR-8"
]
},
{
"id": "F063",
"description": "rmm-alert notification category registered and honoring per-user notification preferences",
"implemented": true,
"prdRefs": [
"FR-8"
]
},
{
"id": "F064",
"description": "Matched rule notifyUserIds produce in-app notifications",
"implemented": true,
"prdRefs": [
"FR-8"
]
},
{
"id": "F065",
"description": "Matched rule notifyUserIds produce email notifications per user preference",
"implemented": true,
"prdRefs": [
"FR-8"
]
},
{
"id": "F066",
"description": "CSRF validation implemented in the NinjaOne OAuth callback using the state payload's csrf and timestamp",
"implemented": true,
"prdRefs": [
"FR-9"
]
},
{
"id": "F067",
"description": "ninjaone/alerts modules moved into shared/rmm/alerts with imports updated and the superseded resetInNinjaOne TODO removed",
"implemented": true,
"prdRefs": [
"FR-9"
]
},
{
"id": "F068",
"description": "rmm_organization_mappings.auto_create_tickets deprecated: no read paths remain; rules are the sole gate for ticket creation",
"implemented": true,
"prdRefs": [
"FR-9"
]
},
{
"id": "F069",
"description": "Migration creates rmm_maintenance_windows (optional integration/client/asset scopes, one-off starts_at/ends_at, weekly recurrence jsonb, name, is_active)",
"implemented": true,
"prdRefs": [
"FR-1",
"FR-10"
]
},
{
"id": "F070",
"description": "Migration adds suppressed_by_window_id to rmm_alerts; alert status supports 'suppressed'",
"implemented": true,
"prdRefs": [
"FR-1",
"FR-10"
]
},
{
"id": "F071",
"description": "Pipeline checks maintenance windows before rule matching: an active window matching all its non-null scopes at occurredAt suppresses the alert",
"implemented": true,
"prdRefs": [
"FR-10"
]
},
{
"id": "F072",
"description": "Weekly recurring windows evaluate day and time range in the window's timezone; one-off windows by starts_at/ends_at",
"implemented": true,
"prdRefs": [
"FR-10"
]
},
{
"id": "F073",
"description": "Suppressed alerts are stored with status suppressed and suppressed_by_window_id: no ticket, no notifications, no workflow events",
"implemented": true,
"prdRefs": [
"FR-10"
]
},
{
"id": "F074",
"description": "A reset for a suppressed alert resolves it quietly with no ticket actions",
"implemented": true,
"prdRefs": [
"FR-10"
]
},
{
"id": "F075",
"description": "Maintenance window CRUD server actions (list/create/update/delete), admin-gated, Zod-validated",
"implemented": true,
"prdRefs": [
"FR-10"
]
},
{
"id": "F076",
"description": "Maintenance Windows settings subsection beside Alert Rules: list plus editor with client/asset scope pickers and one-off or weekly recurring schedule with timezone",
"implemented": false,
"prdRefs": [
"FR-7",
"FR-10"
]
},
{
"id": "F077",
"description": "Per-integration Temporal schedule runs alert reconciliation every N minutes (default 15, configurable 560, default on for connected integrations)",
"implemented": true,
"prdRefs": [
"FR-11"
]
},
{
"id": "F078",
"description": "Poll cycle fetches RMM-active alerts and upserts ones missing locally as triggered events through the shared pipeline",
"implemented": true,
"prdRefs": [
"FR-11"
]
},
{
"id": "F079",
"description": "Poll cycle synthesizes reset events for local active alerts no longer active in the RMM",
"implemented": true,
"prdRefs": [
"FR-11"
]
},
{
"id": "F080",
"description": "Poll cycle processes still-active suppressed alerts whose window has ended through the normal rules path",
"implemented": true,
"prdRefs": [
"FR-10",
"FR-11"
]
},
{
"id": "F081",
"description": "Polling enable/disable and interval setting exposed in integration settings UI with 560 minute bounds",
"implemented": true,
"prdRefs": [
"FR-7",
"FR-11"
]
},
{
"id": "F082",
"description": "TacticalRMM reconciliation uses its alerts API through the same scheduled workflow",
"implemented": true,
"prdRefs": [
"FR-11"
]
},
{
"id": "F083",
"description": "Reconciliation schedule is created when an integration connects and removed when it disconnects",
"implemented": true,
"prdRefs": [
"FR-11"
]
}
]