Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ npx postgresai checkup --json postgresql://... | claude -p "find issues and sugg
|---|---|
| **Demo** | [demo.postgres.ai](https://demo.postgres.ai) (login: `demo` / `demo`) |
| **Docs** | [postgres.ai/docs](https://postgres.ai/docs) |
| **Architecture** | [C4 model](docs/architecture/README.md) |
| **Issues** | [GitLab](https://gitlab.com/postgres-ai/postgresai/-/issues) |
| **Community** | [Postgres.FM](https://postgres.fm) · [Postgres.TV](https://postgres.tv) |

Expand Down
210 changes: 210 additions & 0 deletions docs/architecture/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
# PostgresAI — C4 Architecture Model

This directory holds the [C4 model](https://c4model.com/) for PostgresAI, an
AI-native PostgreSQL observability platform (monitoring, health checks, and root
cause analysis).

The model is maintained in two complementary forms:

| File | Purpose |
|------|---------|
| [`workspace.dsl`](./workspace.dsl) | **Source of truth.** [Structurizr DSL](https://docs.structurizr.com/dsl) describing people, systems, containers, components and their relationships. Renders all C4 levels and stays in sync as a single definition. |
| `README.md` (this file) | GitHub-renderable [Mermaid](https://mermaid.js.org/syntax/c4.html) diagrams for quick reading without tooling. |

The C4 model describes architecture at four levels of zoom: **System Context**
(L1) → **Containers** (L2) → **Components** (L3) → Code (L4, left to the source).

## How to view the Structurizr model

```bash
# Render/edit interactively with Structurizr Lite
docker run -it --rm -p 8080:8080 \
-v "$(pwd)/docs/architecture:/usr/local/structurizr" \
structurizr/lite
# then open http://localhost:8080
```

---

## Level 1 — System Context

How PostgresAI fits among its users and the external systems it talks to.

```mermaid
C4Context
title System Context — PostgresAI

Person(dba, "Engineer / DBA", "Runs health checks, reviews dashboards, resolves issues")
Person(ai, "AI Coding Agent", "Claude Code, Cursor, Windsurf — consumes reports & MCP tools")

System(pgai, "PostgresAI", "AI-native PostgreSQL observability platform")

System_Ext(target, "Target PostgreSQL", "Databases being observed (self-hosted, RDS/Aurora, CloudSQL, Supabase)")
System_Ext(console, "console.postgres.ai", "Managed cloud: UI, Issues API, report/file storage, auth")
System_Ext(supabase, "Supabase Management API", "Executes SQL on Supabase databases")
System_Ext(aws, "AWS / Amazon Managed Prometheus", "RDS/Aurora + managed metrics")
System_Ext(llm, "LLM Provider", "Anthropic Claude / OpenAI GPT")

Rel(dba, pgai, "Runs checkups, views dashboards, manages issues")
Rel(ai, pgai, "Reads reports, calls MCP tools")
Rel(pgai, target, "Connects to & queries", "SQL")
Rel(pgai, console, "Uploads reports, syncs issues, authenticates", "HTTPS")
Rel(pgai, supabase, "Executes SQL", "HTTPS")
Rel(pgai, aws, "Reads metrics", "HTTPS")
Rel(ai, llm, "Analyzes JSON reports")

UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="2")
```

---

## Level 2 — Containers

The separately deployable/runnable units inside PostgresAI. The CLI delivers the
zero-setup express checkup; the rest form the optional full monitoring stack
(`docker-compose.yml` / Helm chart).

```mermaid
C4Container
title Containers — PostgresAI

Person(dba, "Engineer / DBA")
Person(ai, "AI Coding Agent")

System_Ext(target, "Target PostgreSQL")
System_Ext(console, "console.postgres.ai")
System_Ext(supabase, "Supabase Management API")
System_Ext(aws, "Amazon Managed Prometheus")

System_Boundary(pgai, "PostgresAI") {
Container(cli, "CLI", "Node.js / TypeScript", "Express checkup, stack install, prepare-db, auth (postgresai / pgai)")
Container(mcp, "MCP Server", "Node.js / TypeScript", "Exposes Issues tools to AI agents")
Container(reporter, "Reporter", "Python", "Generates 45+ structured health-check reports")
Container(flask, "Monitoring Backend", "Python / Flask", "Query history + PromQL proxy API")
Container(pgwPg, "pgwatch → Postgres", "Go", "Collects metrics into the Postgres sink")
Container(pgwProm, "pgwatch → Prometheus", "Go", "Collects metrics into VictoriaMetrics")
ContainerDb(vm, "VictoriaMetrics", "TSDB", "Prometheus-compatible metrics store")
ContainerDb(sink, "Postgres Sink", "PostgreSQL 17", "Historical metrics & check data")
Container(grafana, "Grafana", "Grafana 12", "13+ observability dashboards")
Container(telemetry, "Telemetry Agent", "Node.js", "Hourly system telemetry")
Container(pilot, "pg_index_pilot", "SQL / PL-pgSQL", "Autonomous index lifecycle")
}

Rel(dba, cli, "Runs commands")
Rel(dba, grafana, "Views dashboards", "HTTPS")
Rel(ai, mcp, "Calls tools", "MCP/stdio")

Rel(cli, target, "Health-check & prepare-db SQL", "SQL")
Rel(cli, console, "Uploads reports, syncs issues, auth", "HTTPS")
Rel(cli, supabase, "Runs queries", "HTTPS")
Rel(cli, reporter, "Triggers report generation")
Rel(mcp, console, "Reads/writes issues", "HTTPS")

Rel(pgwPg, target, "Scrapes", "SQL")
Rel(pgwProm, target, "Scrapes", "SQL")
Rel(pgwPg, sink, "Writes metrics", "SQL")
Rel(pgwProm, vm, "Writes metrics", "HTTP")

Rel(reporter, vm, "Reads metrics", "PromQL")
Rel(reporter, sink, "Reads history", "SQL")
Rel(reporter, aws, "Reads metrics", "HTTPS")
Rel(reporter, console, "Uploads reports", "HTTPS")

Rel(flask, vm, "Proxies PromQL", "HTTP")
Rel(flask, sink, "Reads query history", "SQL")
Rel(grafana, vm, "Queries metrics", "PromQL")
Rel(grafana, sink, "Queries history", "SQL")
Rel(grafana, flask, "Calls backend API", "HTTP")

Rel(telemetry, console, "Posts telemetry", "HTTPS")
Rel(pilot, target, "Manages indexes", "SQL")

UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="1")
```

---

## Level 3 — Components: CLI

The CLI is the primary entry point and the most component-rich container
(`cli/lib/*.ts`).

```mermaid
C4Component
title Components — CLI

Person(dba, "Engineer / DBA")
System_Ext(target, "Target PostgreSQL")
System_Ext(console, "console.postgres.ai")
System_Ext(supabase, "Supabase Management API")

Container_Boundary(cli, "CLI") {
Component(cmd, "Command Dispatch", "postgres-ai.ts", "Parses commands/flags, orchestrates workflows")
Component(checkup, "Checkup Engine", "checkup.ts", "Runs 45+ health checks, builds JSON reports")
Component(checkupApi, "Checkup API Client", "checkup-api.ts", "Uploads/fetches reports")
Component(init, "DB Init / prepare-db", "init.ts", "Creates monitoring role, schema, permissions")
Component(instances, "Targets / Instances", "instances.ts", "Manages monitored targets")
Component(issues, "Issues Client", "issues.ts", "Console Issues API CRUD")
Component(auth, "Auth (OAuth2/PKCE)", "auth-server.ts, pkce.ts", "Login & API-key handling")
Component(storage, "Storage Client", "storage.ts", "File upload/download")
Component(sb, "Supabase Client", "supabase.ts", "Runs SQL via Supabase API")
Component(cfg, "Local Config", "config.ts, util.ts", "~/.postgres-ai settings")
}

Rel(dba, cmd, "Runs commands")
Rel(cmd, checkup, "Invokes")
Rel(cmd, init, "Invokes")
Rel(cmd, instances, "Invokes")
Rel(cmd, issues, "Invokes")
Rel(cmd, auth, "Invokes")

Rel(checkup, target, "Runs SQL", "SQL")
Rel(checkup, checkupApi, "Uploads report")
Rel(checkup, cfg, "Reads settings")
Rel(checkupApi, console, "HTTPS")
Rel(init, target, "Creates role/schema", "SQL")
Rel(issues, console, "HTTPS")
Rel(auth, console, "OAuth2/PKCE", "HTTPS")
Rel(storage, console, "Uploads files", "HTTPS")
Rel(sb, supabase, "HTTPS")

UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="1")
```

---

## Level 3 — Components: Reporter

```mermaid
C4Component
title Components — Reporter

System_Ext(aws, "Amazon Managed Prometheus")
System_Ext(console, "console.postgres.ai")
ContainerDb(vm, "VictoriaMetrics")
ContainerDb(sink, "Postgres Sink")

Container_Boundary(reporter, "Reporter") {
Component(gen, "Report Generators", "postgres_reports.py", "Per-check report logic (A/D/F/H/I/K/M/N series)")
Component(schemas, "Report Schemas", "schemas/*.schema.json", "29 JSON Schemas validating output")
}

Rel(gen, vm, "Reads metrics", "PromQL")
Rel(gen, sink, "Reads history", "SQL")
Rel(gen, aws, "Reads metrics", "HTTPS")
Rel(gen, schemas, "Validates against")
Rel(gen, console, "Uploads reports", "HTTPS")

UpdateLayoutConfig($c4ShapeInRow="2", $c4BoundaryInRow="1")
```

---

## Maintaining this model

- Treat `workspace.dsl` as the source of truth; update it when containers,
components, or integrations change.
- Keep the Mermaid diagrams above in sync for at-a-glance reading on GitHub.
- Useful references: [c4model.com](https://c4model.com/),
[Structurizr DSL docs](https://docs.structurizr.com/dsl),
[Mermaid C4 syntax](https://mermaid.js.org/syntax/c4.html).
166 changes: 166 additions & 0 deletions docs/architecture/workspace.dsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
workspace "PostgresAI" "AI-native PostgreSQL observability: monitoring, health checks, and root cause analysis." {

!identifiers hierarchical

model {
# ---------------------------------------------------------------
# People / external actors
# ---------------------------------------------------------------
dba = person "Engineer / DBA" "Runs health checks, reviews dashboards, and resolves issues."
aiAgent = person "AI Coding Agent" "Claude Code, Cursor, Windsurf, etc. Consumes structured reports and the MCP server." "AI"

# ---------------------------------------------------------------
# External software systems
# ---------------------------------------------------------------
targetPg = softwareSystem "Target PostgreSQL" "The PostgreSQL database(s) being observed (self-hosted, RDS/Aurora, CloudSQL, Supabase, etc.)." "External, Database"
console = softwareSystem "console.postgres.ai" "PostgresAI managed cloud: web UI, Issues API, report & file storage, auth (OAuth2/PKCE)." "External"
supabaseApi = softwareSystem "Supabase Management API" "Executes SQL against Supabase-hosted databases." "External"
awsApm = softwareSystem "AWS / Amazon Managed Prometheus" "RDS, Aurora and Amazon Managed Prometheus metrics sources." "External"
llm = softwareSystem "LLM Provider" "Anthropic Claude / OpenAI GPT used to analyze JSON reports." "External, AI"

# ---------------------------------------------------------------
# The PostgresAI system and its containers
# ---------------------------------------------------------------
pgai = softwareSystem "PostgresAI" "AI-native PostgreSQL observability platform." {

cli = container "CLI" "Express checkup, stack install, target & DB prep, auth. Binaries: postgresai / pgai." "Node.js / TypeScript" "EntryPoint" {
cmd = component "Command Dispatch" "Parses commands and flags, orchestrates workflows." "postgres-ai.ts"
checkup = component "Checkup Engine" "Runs 45+ health checks and builds structured JSON reports." "checkup.ts"
checkupApi = component "Checkup API Client" "Uploads/fetches reports to/from console.postgres.ai." "checkup-api.ts"
init = component "DB Init / prepare-db" "Creates monitoring role, schema and permissions on targets." "init.ts"
instances = component "Targets / Instances" "Manages monitored targets (instances.yml)." "instances.ts"
issues = component "Issues Client" "CRUD against the console Issues API." "issues.ts"
auth = component "Auth (OAuth2/PKCE)" "Browser-based login and API-key handling." "auth-server.ts, pkce.ts"
storage = component "Storage Client" "Uploads/downloads files to PostgresAI storage." "storage.ts"
supabase = component "Supabase Client" "Runs queries via the Supabase Management API." "supabase.ts"
config = component "Local Config" "Reads/writes ~/.postgres-ai settings." "config.ts, util.ts"
}

mcp = container "MCP Server" "Model Context Protocol server exposing Issues tools to AI coding agents." "Node.js / TypeScript" "EntryPoint" {
mcpTools = component "MCP Tools" "list_issues, view_issue, create_issue, update_issue, ..." "mcp-server.ts"
}

pgwatchPg = container "pgwatch (Postgres sink)" "Collects pg_stat_statements, wait events, table/index stats; writes to the Postgres sink." "Go (patched v3.7.0)"
pgwatchProm = container "pgwatch (Prometheus sink)" "Same collector, writes metrics to VictoriaMetrics." "Go (patched v3.7.0)"

reporter = container "Reporter" "Generates 45+ structured health-check reports (A/D/F/H/I/K/M/N series) from metrics & history." "Python" {
reportGen = component "Report Generators" "Per-check report logic." "postgres_reports.py"
schemas = component "Report Schemas" "29 JSON Schemas validating report output." "schemas/*.schema.json"
}

flask = container "Monitoring Backend" "API for pg_stat_statements query history and PromQL proxying." "Python / Flask + Gunicorn" {
api = component "API Endpoints" "Query history, query-id mapping, PromQL proxy." "app.py"
promql = component "PromQL Utils" "Escaping/formatting PromQL." "promql_utils.py"
}

grafana = container "Grafana" "13+ dashboards (Four Golden Signals, wait events, indexes, replication, ...)." "Grafana 12.x" "WebUI"
vmetrics = container "VictoriaMetrics" "Prometheus-compatible time-series store for metrics." "VictoriaMetrics" "Database"
sinkPg = container "Postgres Sink" "Stores historical metrics and check data." "PostgreSQL 17" "Database"

telemetry = container "Telemetry Agent" "Hourly system metrics (OOM, free RAM/disk) posted to the platform." "Node.js / TypeScript"
indexPilot = container "pg_index_pilot" "Autonomous index lifecycle: bloat estimation, recommendations, reindexing." "SQL / PL-pgSQL + Bash"
}

# ---------------------------------------------------------------
# Relationships — Context level
# ---------------------------------------------------------------
dba -> pgai "Runs checkups, views dashboards, manages issues"
aiAgent -> pgai "Reads reports, calls MCP tools"
pgai -> targetPg "Connects to and queries"
pgai -> console "Uploads reports, syncs issues, authenticates" "HTTPS"
pgai -> supabaseApi "Executes SQL" "HTTPS"
pgai -> awsApm "Reads metrics" "HTTPS"
aiAgent -> llm "Analyzes JSON reports"

# ---------------------------------------------------------------
# Relationships — Container level
# ---------------------------------------------------------------
dba -> pgai.cli "Runs commands"
dba -> pgai.grafana "Views dashboards" "HTTPS"
aiAgent -> pgai.mcp "Calls tools" "MCP/stdio"

pgai.cli -> targetPg "Runs health-check & prepare-db SQL" "SQL/TCP"
pgai.cli -> console "Uploads reports, syncs issues, auth" "HTTPS"
pgai.cli -> supabaseApi "Runs queries" "HTTPS"
pgai.cli -> pgai.reporter "Triggers report generation"

pgai.mcp -> console "Reads/writes issues" "HTTPS"

pgai.pgwatchPg -> targetPg "Scrapes metrics" "SQL/TCP"
pgai.pgwatchProm -> targetPg "Scrapes metrics" "SQL/TCP"
pgai.pgwatchPg -> pgai.sinkPg "Writes metrics" "SQL/TCP"
pgai.pgwatchProm -> pgai.vmetrics "Writes metrics" "HTTP"

pgai.reporter -> pgai.vmetrics "Reads metrics" "PromQL/HTTP"
pgai.reporter -> pgai.sinkPg "Reads history" "SQL/TCP"
pgai.reporter -> awsApm "Reads metrics" "HTTPS"
pgai.reporter -> console "Uploads reports" "HTTPS"

pgai.flask -> pgai.vmetrics "Proxies PromQL" "HTTP"
pgai.flask -> pgai.sinkPg "Reads query history" "SQL/TCP"
pgai.grafana -> pgai.vmetrics "Queries metrics" "PromQL/HTTP"
pgai.grafana -> pgai.sinkPg "Queries history" "SQL/TCP"
pgai.grafana -> pgai.flask "Calls backend API" "HTTP"

pgai.telemetry -> console "Posts system telemetry" "HTTPS"
pgai.indexPilot -> targetPg "Manages indexes" "SQL/TCP"

# ---------------------------------------------------------------
# Relationships — Component level (CLI)
# ---------------------------------------------------------------
pgai.cli.cmd -> pgai.cli.checkup "Invokes"
pgai.cli.cmd -> pgai.cli.init "Invokes"
pgai.cli.cmd -> pgai.cli.instances "Invokes"
pgai.cli.cmd -> pgai.cli.issues "Invokes"
pgai.cli.cmd -> pgai.cli.auth "Invokes"
pgai.cli.checkup -> targetPg "Runs SQL" "SQL/TCP"
pgai.cli.checkup -> pgai.cli.checkupApi "Uploads report"
pgai.cli.checkupApi -> console "HTTPS"
pgai.cli.init -> targetPg "Creates role/schema" "SQL/TCP"
pgai.cli.issues -> console "HTTPS"
pgai.cli.auth -> console "OAuth2/PKCE" "HTTPS"
pgai.cli.storage -> console "Uploads files" "HTTPS"
pgai.cli.supabase -> supabaseApi "HTTPS"
pgai.cli.checkup -> pgai.cli.config "Reads settings"
}

views {
systemContext pgai "SystemContext" {
include *
autolayout lr
description "C4 Level 1 — PostgresAI in context."
}

container pgai "Containers" {
include *
autolayout lr
description "C4 Level 2 — containers inside PostgresAI."
}

component pgai.cli "CliComponents" {
include *
autolayout lr
description "C4 Level 3 — components inside the CLI."
}

component pgai.reporter "ReporterComponents" {
include *
autolayout lr
description "C4 Level 3 — components inside the Reporter."
}

styles {
element "Person" { shape person background #08427b color #ffffff }
element "AI" { background #6b3fa0 color #ffffff }
element "Software System" { background #1168bd color #ffffff }
element "External" { background #999999 color #ffffff }
element "Container" { background #438dd5 color #ffffff }
element "Component" { background #85bbf0 color #000000 }
element "Database" { shape cylinder }
element "WebUI" { shape webBrowser }
element "EntryPoint" { shape roundedBox }
}

theme default
}
}
Loading