---
id: w1/m25/t001
title: "`processes` endpoint: live `pg_stat_activity` snapshot (REST/GraphQL/MCP)"
worker: worker1
status: todo
estimate: 45m
depends_on: []
---

## Objective

Expose Render's `GET /postgres/{id}/processes` equivalent: a live snapshot of `pg_stat_activity` for a tenant's managed Postgres instance, across REST, GraphQL, and MCP.

## Context

- `lego/backend/internal/postgres/` — existing CRUD, connection-info, access-control, and query verbs (`query.go`).
- Managed Postgres connection details already resolvable from the `Database` CR / CNPG `Cluster` (see `lifecycle.go`, `access.go`).

## Steps

1. Add a `Processes` verb to the postgres package's core that runs `SELECT ... FROM pg_stat_activity` against the target instance using the existing connection-resolution path.
2. Wire it into REST (`GET /v1/postgres/{id}/processes`), GraphQL, and MCP (`get_postgres_processes` or similar), matching Render's field shape where documented.
3. Scope to the caller's workspace (reuse the existing `can_operate`/access check from `access.go`).

## Files

- `lego/backend/internal/postgres/query.go` (or new `observability.go`)
- `lego/backend/internal/postgres/rest.go`, `graphql.go`, `mcp.go` (or wherever those adapters live)

## Acceptance criteria

- [ ] `GET /v1/postgres/{id}/processes` returns live `pg_stat_activity` rows for a real CNPG-backed instance.
- [ ] GraphQL and MCP equivalents return the same data.
- [ ] Access is scoped to the owning workspace; a caller without access gets denied.

## Out of scope

- `top-queries`, `sizes`, `table-scans`, `parameter-overrides` — separate tasks.
