# supabase

::: warning Coming soon
This plugin is not released yet. The agent side lives on the unmerged `supabase-plugin` branch of the plugins package. The server rules and the dashboard card are on the matching frontend branch.
:::

The supabase plugin watches Supabase Cloud projects. Per project it reports whether the project is paused, the health of each Supabase service, and disk, memory, connections and database size. It runs on any agent, because it only makes HTTPS calls.

## Set it up

Each project can use one or both of two sources. Each source has its own credential.

| Source | Credential | Gives |
|---|---|---|
| Management API, `api.supabase.com/v1` | A personal access token. It covers every project in the account that made it. | Project status, the only place "paused" shows up. Region and Postgres version. Health for each service. |
| The project's metrics endpoint, `https://<PROJECT_REF>.supabase.co/customer/v1/privileged/metrics` | The project's secret API key, sent as basic auth with user `service_role`. | Disk, memory, connections and database size. |

Either one alone works. A project with neither reports an error.

1. Find each project's ref. It is the subdomain in `https://<PROJECT_REF>.supabase.co`.
2. Create a personal access token in each Supabase account that owns a project, and copy each project's secret key if you want the figures.
3. Add a `supabase` block to the agent config and add `supabase` to the `plugins` array.

```json
{
  "plugins": ["supabase"],
  "supabase": {
    "refreshInterval": 60000,
    "accessToken": "sbp_<DEFAULT_ACCOUNT_TOKEN>",
    "diskWarnPct": 80,
    "diskCritPct": 90,
    "connWarnPct": 85,
    "projects": [
      { "ref": "<PROJECT_REF>", "name": "portal" },
      {
        "ref": "<OTHER_PROJECT_REF>",
        "name": "calendar",
        "accessToken": "sbp_<OTHER_ACCOUNT_TOKEN>",
        "serviceKey": "sb_secret_<SECRET_KEY>"
      }
    ]
  }
}
```

The top-level `accessToken` is the default. A project in a different Supabase account needs its own `accessToken`, since one token only covers its own account.

| Option | Default | What it does |
|---|---|---|
| `projects` | required | List of projects. Each has `ref`, and optionally `name`, `accessToken` and `serviceKey`. Entries without `ref` are skipped. |
| `projects[].name` | project name from the API, else `ref` | Card title. |
| `accessToken` | none | Default personal access token. |
| `services` | `auth`, `db`, `pooler`, `realtime`, `rest`, `storage` | Services asked of the health endpoint. Drop one a project does not use. |
| `diskWarnPct` | `80` | Disk use, in percent, that warns. |
| `diskCritPct` | `90` | Disk use, in percent, that is an error. |
| `connWarnPct` | `85` | Connections in use, as a percent of `max_connections`, that warns. |
| `requestTimeout` | `10000` | Milliseconds per HTTP request. |
| `refreshInterval` | `60000` | Milliseconds between polls. |

## What it reports

One report per project per interval, keyed `supabase-<ref>`. Projects are polled one after another, and the first poll runs on start.

- `ref`, `name` and `reachable`.
- `projectStatus`, such as `ACTIVE_HEALTHY` or `INACTIVE`, plus `region` and `pgVersion`.
- `services[]`, each with `name`, `healthy`, `status` and `error`.
- `metrics`, from the Prometheus endpoint. `diskPct`, `diskUsedBytes` and `diskTotalBytes` read the `/data` volume, or `/` when there is no `/data`. Also `memPct`, `load1`, `connections`, `maxConnections` and `dbSizeBytes`. A series that is missing reports null, not 0.
- `errors[]`, one entry per configured source that failed while another answered.
- `diskWarnPct`, `diskCritPct` and `connWarnPct`, the thresholds from the agent config. The server judges with these.

If every source fails, the report is `{ reachable: false, error }`.

## When it alerts

The server checks these in order and stops at the first match.

| Condition | Severity | Reason text |
|---|---|---|
| `error` set, or `reachable` is false | error | `<name>: <error>` |
| `projectStatus` is `INACTIVE` | error | `<name>: project is paused` |
| `projectStatus` is a transient state | warning | `<name>: project <status>` |
| `projectStatus` is any other value besides `ACTIVE_HEALTHY` | error | `<name>: project <status>` |
| The `db` service is unhealthy and not `COMING_UP` | error | `<name>: database unhealthy, <error>` |
| `diskPct` at or above `diskCritPct` | error | `<name>: disk <n>% full` |
| Any service unhealthy | warning | `<name>: <services> unhealthy` |
| `diskPct` at or above `diskWarnPct` | warning | `<name>: disk <n>% full` |
| Connections at or above `connWarnPct` of the maximum | warning | `<name>: <n> of <max> connections in use` |
| `errors[]` is not empty | warning | `<name>: <first error>` |

The transient states are `COMING_UP`, `RESTORING`, `UPGRADING`, `RESTARTING`, `RESIZING`, `PAUSING`, `GOING_DOWN` and `UNKNOWN`.

A new problem does not notify on the first bad report. The server waits for a second consecutive bad report. A report that comes back online resolves the alert.

## On the dashboard

One card per project, titled with the project name and labelled `Supabase · <region>`. Each reading shows only when it was measured.

| Reading | Source | Warn | Crit |
|---|---|---|---|
| PROJECT | `projectStatus`. `ACTIVE_HEALTHY` reads ACTIVE, `INACTIVE` reads PAUSED | any other state | PAUSED |
| DISK | `metrics.diskPct` | `diskWarnPct` | `diskCritPct` |
| CONNS | `connections` / `maxConnections` | `connWarnPct` | none |
| DB SIZE | `metrics.dbSizeBytes` | none | none |
| MEM | `metrics.memPct` | none | none |
| POSTGRES | `pgVersion`, major and minor | none | none |

Below that, one row per service. Healthy is green, `COMING_UP` is amber, anything else is red. When the report is unreachable, the card shows only `API UNREACHABLE`. The card links to the project in the Supabase dashboard.

## Gotchas

- The branch's commit message says the health and project response fields, and the metric series names, were written from memory. They have not been run against a live project. - The dashboard and the server do not color everything the same way. An unhealthy service other than `db` is red on the card but only a warning on the server. A project state outside the transient list is amber on the card but an error on the server.
- `load1`, `diskUsedBytes` and `diskTotalBytes` are reported but not shown. `memPct` is shown but never judged.
- A partial report, where one source failed, does not show which source failed on the card. The reason text carries the first error.
