Skip to content

Data model

Postgres, managed with SQLAlchemy 2.0 models (nimi_service/models.py, the source of truth) and Alembic migrations (nimi-service/db/migrations/). Rows use internal numeric IDs; provider IDs are stored as (provider, external_id), unique together. Sender types are normalized to human / bot.

Tables

Ingested data (what the provider returned)

Table Contents
channels Registered channels: provider, external ID, label, rca_enabled, backfill days, ingest watermark, reaction check time.
messages Top-level messages: sender, created time, rendered_text (readable form), raw provider payload, reaction summary, is_backfill.
thread_messages Thread replies (including NIMI's own replies), same shape.
reactions Individual reactions on messages.

Derived (rebuildable with reparse)

Table Contents
signatures Coarse "kind of message" keys with a sample title and service.
message_parses Per top-level message: parser version, kind (alert / log / …), title, status, service, signature.

Workflow

Table Contents
rca_requests One per analyzed message (or manual text): status (see lifecycle), skip_reason, triage decision / reason / output / model / cost, attempts, timestamps.
rca_request_subjects Per request: subjects and their decision (new or reused, with the reused result).
rca_results Skill runs: outcome, report, structured fields (origin, confidence, self-healing, repo, commit), cost, duration, model, session ID, skill version.
rca_posts Messages posted (kind rca / reuse / mixed / not_applicable / notice), their destination (thread or webhook) and chat IDs.
rca_post_reuse_links Which earlier results a reuse reply pointed to.
rca_feedback Verdicts from reactions (correct / partial / wrong), soft-deleted when a reaction is removed.
rca_exclusions Exclusion rules: match fields, reason, expiry, hit counts.

Operations

Table Contents
red_flags Red flags: kind, severity, source, links to message/request/channel, dedupe key, occurrences, notification and resolution state. Never stores sensitive values.
service_state Small persistent key/value state, e.g. the Claude pause.

Views

View Read by Contents
signature_stats service / humans Occurrences, first and last seen per signature.
rca_feedback_summary service / humans Current feedback counts per result.
skill_messages the skill (nimi_skill_reader) Top-level bot messages from all channels with their parse and signature. No thread replies, human messages or raw payloads.
skill_rcas the skill (nimi_skill_reader) Previous RCAs (outcomes rca, not_applicable, insufficient_context) with source message details, subjects and feedback counts.
review_messages development reviews (nimi_readonly) Bot messages, top-level and thread replies.

The skill and review views use security_barrier so their filters apply before any caller condition.

Database roles

Role (default) Used by Access
nimi_service the service Owns the database and schema: read/write; the only role that can create objects.
nimi_skill_reader the skill, via nimi-sql SELECT on skill_messages and skill_rcas only. Read-only sessions, 5s statement timeout, 5 connections. Granted by db upgrade.
nimi_readonly development reviews (optional, dev/review_access.sh) SELECT on review_messages only. Read-only, 30s timeout, 3 connections.

The triage model has no database access: the service puts what it needs into the prompt.