package models import "time" // Alert is the machine-owned signal record: what Alertmanager told us, and // nothing else. It has two states, firing and resolved, and no human ever writes // to it — acknowledgement, assignment, notes and closure all live on the // Incident an alert belongs to. type Alert struct { ID int64 `json:"id"` // TeamID is the team whose integration received this alert, and TeamName // rides along so a combined list can label a row without a second request. TeamID int64 `json:"team_id"` TeamName string `json:"team_name,omitempty"` Fingerprint string `json:"fingerprint"` Name string `json:"name"` Status string `json:"status"` // "firing" or "resolved" Labels map[string]string `json:"labels"` Annotations map[string]string `json:"annotations"` StartsAt time.Time `json:"starts_at"` EndsAt *time.Time `json:"ends_at,omitempty"` GeneratorURL string `json:"generator_url"` // ReceivedAt is when the server last accepted a webhook for this // fingerprint, including the unchanged firing notifications Alertmanager // re-sends every repeat_interval. // // This is a documented part of the public API, not an internal ingest // detail: StartsAt never changes for an alert instance, so ReceivedAt is // the only signal a client has that a firing alert is still being // refreshed. The sweeper stale-dates against it (see expireStale), API // clients render it, and GET /api/alerts is ordered by it. Anything that // stops the webhook handler from advancing it on a re-send is a breaking // change — see "received_at is a liveness heartbeat" in the README and // TestWebhook_ResendBumpsReceivedAt. ReceivedAt time.Time `json:"received_at"` // IncidentID is the most recent incident this alert belongs to. An alert row // is reused across occurrences of the same fingerprint, so over its life it // belongs to a series of incidents; incident_alerts keeps the full history // and this is only the newest link. IncidentID *int64 `json:"incident_id,omitempty"` // ResolutionSource records why a resolved alert left the firing state: // "alertmanager" for a real resolved webhook, "expiry" when the sweeper // inferred it after the alert stopped being refreshed. Nil while firing, and // cleared again by a re-fire under the same fingerprint. // // Also public API: it is how a client knows whether EndsAt was observed or // inferred. Under "expiry" nothing ever reported an end, so EndsAt is only // an upper bound (see expireStale) and ReceivedAt is the more truthful // signal. Treat the value set as open — see "resolution_source says how much // to trust ends_at" in the README, and TestWebhook_ResolvedSetsSource / // TestExpiry_StaleFiringAlert. ResolutionSource *string `json:"resolution_source,omitempty"` ArchivedAt *time.Time `json:"archived_at,omitempty"` }