Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/nicolas344/Sentinel-SoftServe/llms.txt

Use this file to discover all available pages before exploring further.

Sentinel stores every incident and its status-transition timeline in Supabase (PostgreSQL). The schema lives in supabase/migrations/ and consists of two migration files that must be applied in order. The backend will fail to start correctly if the incidents table does not exist, so apply the migrations before running docker compose up -d for the first time.
Fresh project vs. existing project: If you are setting up a brand-new Supabase project, apply both migration files in order — 0001_initial_schema.sql first, then 0002_production_hardening.sql. If you are working with the team’s existing Supabase project, the baseline schema is already in place — apply only 0002_production_hardening.sql, which is safe to run on top of an existing installation (it only adds columns and indexes).

How to apply migrations

1

Open the SQL Editor

Go to your Supabase project → SQL Editor in the left sidebar, then click New query.
2

Apply the initial schema

Open supabase/migrations/0001_initial_schema.sql in your editor, paste the full contents into the SQL Editor, and click Run.
3

Apply production hardening

Open supabase/migrations/0002_production_hardening.sql, paste its contents into a new query tab, and click Run.

Migration 0001 — Initial schema

supabase/migrations/0001_initial_schema.sql creates the core tables, indexes, and enables Supabase Realtime on the incidents table. It also enables the pgcrypto extension for UUID generation.

incidents table

This is the primary table — every alert received by the backend becomes a row here.
ColumnTypeConstraintsDescription
iduuidPK, default gen_random_uuid()Unique incident identifier
titletextNOT NULLHuman-readable incident title
targettextNOT NULLContainer name, pod name, or database identifier affected
severitytextNOT NULL, check: critical, high, medium, lowIncident severity classified by the agent
statustextNOT NULL, default detected, check (enum below)Current lifecycle state of the incident
source_typetextNOT NULL, default container, check: container, database, manualOrigin type of the alert
container_runtimetextcheck: docker, podman, kubernetesContainer runtime, when source_type = container
incident_typetextClassified incident sub-type (e.g. oom, app_crash, connection_exhaustion)
logstextRaw log snippet collected from Loki at detection time
server_nametextHost or node name where the incident occurred
agent_reasoningtextFull agent reasoning trace from the investigation step
proposed_actiontextCorrective action proposed by the agent and presented for human approval
action_resulttextOutput of the executed action after engineer approval
action_errortextError message if the action execution failed
metrics_snapshotjsonbPrometheus metrics snapshot captured at detection time
post_mortem_mdtextMarkdown post-mortem report generated after incident resolution
post_mortem_updated_attimestamptzTimestamp of the last post-mortem update
executed_attimestamptzWhen the approved corrective action was executed
resolved_attimestamptzWhen the incident reached resolved status
created_attimestamptzNOT NULL, default now()When the incident was first created
updated_attimestamptzLast update timestamp (set by the backend on every write)
status allowed values:
detected → investigating → analyzed → awaiting_approval
→ executing_solution → verifying → resolved | failed
Indexes created:
idx_incidents_status      ON public.incidents (status)
idx_incidents_target      ON public.incidents (target)
idx_incidents_created_at  ON public.incidents (created_at DESC)

incident_events table

An append-only timeline of every status transition for each incident. The frontend uses this to render the incident timeline view.
ColumnTypeConstraintsDescription
iduuidPK, default gen_random_uuid()Unique event identifier
incident_iduuidNOT NULL, FK → incidents(id) ON DELETE CASCADEParent incident
statustextNOT NULLThe status the incident transitioned to
created_attimestamptzNOT NULL, default now()When the transition occurred
Index created:
idx_incident_events_incident_id  ON public.incident_events (incident_id, created_at)

Supabase Realtime

The migration enables Supabase Realtime on the incidents table so the React frontend can subscribe to live row-level changes without polling:
ALTER PUBLICATION supabase_realtime ADD TABLE public.incidents;
The frontend subscribes to this publication on mount and updates the dashboard in real time whenever an incident is inserted or its status changes.

Migration 0002 — Production hardening

supabase/migrations/0002_production_hardening.sql adds two columns and a partial unique index to the incidents table. It is safe to apply to an existing database — all statements use ADD COLUMN IF NOT EXISTS and CREATE INDEX IF NOT EXISTS.

New columns

ColumnTypeDescription
approved_bytextRecords which engineer approved, rejected, or postponed a proposed action — provides a human-in-the-loop audit trail
fingerprinttextDeduplication key sent by Alertmanager with each alert. Used to prevent duplicate active incidents for the same underlying alert.

Partial unique index

CREATE UNIQUE INDEX uniq_incidents_active_fingerprint
    ON public.incidents (fingerprint)
    WHERE fingerprint IS NOT NULL
      AND status NOT IN ('resolved', 'failed');
This index enforces at the database level that no two active incidents share the same Alertmanager fingerprint. Resolved and failed incidents are excluded from the uniqueness constraint so the same alert can fire again after it has been resolved. This eliminates the race condition that could otherwise arise from a check-then-insert pattern in the backend.

Build docs developers (and LLMs) love