---
module: aria.precursor-alerts
title: Precursor Alerts
tab: Internal
order: 20
audience: internal
---

Ops/support view of the ARIA **Precursor Alerts** screen (multi-phase attack-sequence detection: jackpotting / skimming precursors). Served by **hiveops-aria** only. Nothing here touches incident/journal/devices data directly.

## Who can use it

- **All three endpoints require `hasRole('BCOS_ADMIN')`** — not the usual `hasAnyRole('MSP_ADMIN','BCOS_ADMIN')`. An MSP_ADMIN JWT will get **403** on this screen even though they can use other apps. This is the #1 "I can't see any alerts / it's empty for me" cause.
- Auth is a stateless JWT (ARIA's own `JwtAuthenticationFilter`). `resolvedBy` is stamped from the caller's JWT email; if the principal is missing it records `"unknown"`.

## What an operator does here

- **Review active alerts** — list defaults to Active (`resolved=false`), newest-triggered first.
- **Filter** by Device ID, Status (Active / Resolved / All), Type (Jackpotting / Skimming / Unknown).
- **Open a row** → side panel lists the individual threat events that make up the sequence (calls `/sequences/{id}/events`).
- **Resolve** a row or hit Mark Resolved in the panel. Resolve is idempotent — resolving an already-resolved alert just returns it unchanged.
- Auto-refresh polls the list every **60s** (client-side toggle, persisted in `localStorage` key `aria_alerts_autoRefresh`).

## Admin-only actions

- **Resolve alert:** `POST /api/aria/sequences/{id}/resolve` (BCOS_ADMIN). Sets `resolved_at`/`resolved_by`. There is **no un-resolve / re-open endpoint** — once resolved it stays resolved.
- Alerts themselves are **generated automatically** by the detection engine on event ingestion. There is no manual "create alert" action and no admin knob in the UI to force one.

## First things to check when it misbehaves

1. **"Empty list / 403"** → confirm the JWT role is **BCOS_ADMIN**. MSP_ADMIN is not enough here.
2. **"No alerts are ever raised despite threat events"** — walk the pipeline:
   - Are events actually arriving? Check `POST /api/aria/ingest/events` (ThreatEvent ingestion). If ingestion is gated, the `X-Service-Secret` header must match `ARIA_SERVICE_SECRET`; **if that env var is blank, ingestion accepts anything** — so a silent-drop is more likely an empty request than auth.
   - A sequence needs **≥2 threat events on the same device within the detection window** (`ARIA_SEQUENCE_WINDOW_MINUTES`, default **15 min**). Sparse/slow events won't correlate.
   - Detection **requires a `PHYSICAL_ACCESS` attack phase** to be present. Without it, no jackpotting/skimming sequence is ever raised — this is by design, not a bug.
   - Classification assigns the `attack_phase` and `severity`; if the classifier isn't tagging phases (bad/missing IOC catalog), sequences won't form. Check the IOC catalog (`GET /api/aria/ioc`).
3. **"Only one alert per device, second attack not showing"** — expected. There is a dedup guard: while a device has an **unresolved** alert, no new alert is created for it. Resolve the existing one to allow the next.
4. **"Resolved-by shows `unknown`"** → JWT reached the endpoint without a populated principal email; check the token/claims.
5. **"Alerts stopped updating on screen"** → auto-refresh toggle is off, or the 60s poll is failing silently; hit the manual ↻ button and watch the network call to `GET /api/aria/sequences`.
6. **Events panel empty ("No events tagged to this sequence yet")** → the alert's `sequence_id` has no matching rows in `threat_event`. Events are stamped with the sequence UUID at detection time; if they were purged/re-ingested the linkage is lost.

## Data locations (for support triage)

- DB: **`hiveiq_aria`** (Postgres on the database VM, ProxyJump). Tables: `precursor_sequence_alert`, `threat_event`.
- Logs: search for `ARIA SEQUENCE ALERT` (warn on every raised sequence) and `ARIA event ingested` in Loki. Sequence-detection failures log `Sequence detection failed for device ...`.

## Config that changes behavior

- `ARIA_SEQUENCE_WINDOW_MINUTES` (default 15) — correlation window.
- `ARIA_SERVICE_SECRET` — ingestion gate (blank = open).
- Auto-response (shutdown) is **off by default** (`aria.autoresponse.shutdown.enabled=false`); resolving here is manual triage, not an automated containment action.
