This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
DBSight is a database performance analyzer — Go API server with embedded background worker + React SPA. Single binary serves API, worker (goroutine), and static files. Supports PostgreSQL via pg_stat_statements, MySQL 5.7+/8.0+ via performance_schema, and MariaDB 10.x+ via performance_schema.
pnpm workspaces monorepo: apps/web/ (React SPA) + apps/docs/ (Starlight docs site). Go module stays at root.
make build # Build frontend then Go binary → bin/dbsight
go build -o bin/dbsight . # Go only (requires apps/web/dist/ from prior pnpm build)
pnpm --filter web build # Frontend only (tsc + vite)
pnpm --filter docs build # Docs site only (Astro/Starlight)docker-compose up -d postgres # Start local PostgreSQL
go run . migrate # Run DB migrations
go run . serve # Start API server (port 42198) with embedded worker
pnpm --filter web dev # Vite dev server with /api proxy to :42198
pnpm --filter docs dev # Starlight docs dev servergo test ./internal/... # Go tests
go vet ./internal/... # Go static analysis
pnpm --filter web lint # Biome (lint + format check)
pnpm --filter web lint:fix # Biome auto-fix
pnpm --filter web format # Biome format onlygo test ./internal/crypto/ -v -run TestEncryptDecryptSingle binary (main.go at repo root) with cobra CLI:
dbsight serve— starts HTTP server + worker goroutinedbsight migrate— runs embedded SQL migrations
//go:embed apps/web/dist in main.go embeds the React build into the binary. Must run pnpm --filter web build before go build.
main.go — Entry point, cobra CLI, runServer() wiring, embed directive
internal/config/ — Config struct loaded from env vars
internal/models/ — Domain types (Connection, SlowQuery, QueryDelta, etc.)
internal/store/store.go — Store interface (connections, snapshots, index stats)
internal/store/postgres.go — pgxpool implementation of Store
internal/store/migrate.go — Embedded SQL migration runner
internal/adapter/adapter.go — DBAnalyzer interface + factory (PostgreSQL, MySQL, MariaDB)
internal/adapter/postgres.go — PostgreSQL adapter (Connect/Close)
internal/adapter/postgres_slow_queries.go — pg_stat_statements queries
internal/adapter/postgres_explain.go — PostgreSQL EXPLAIN plan
internal/adapter/postgres_indexes.go — PostgreSQL index stats from pg_stat_user_indexes
internal/adapter/postgres_stats.go — PostgreSQL database-level stats
internal/adapter/mysql.go — MySQL adapter (Connect/Close)
internal/adapter/mysql_slow_queries.go — MySQL performance_schema queries
internal/adapter/mysql_explain.go — MySQL EXPLAIN FORMAT=JSON
internal/adapter/mysql_indexes.go — MySQL index stats from information_schema
internal/adapter/mysql_stats.go — MySQL database-level stats (SHOW GLOBAL STATUS)
internal/adapter/mariadb.go — MariaDB adapter (Connect/Close)
internal/adapter/mariadb_slow_queries.go — MariaDB performance_schema queries
internal/adapter/mariadb_explain.go — MariaDB EXPLAIN FORMAT=JSON
internal/adapter/mariadb_indexes.go — MariaDB index stats with JSON_ARRAYAGG
internal/adapter/mariadb_stats.go — MariaDB database-level stats
internal/adapter/mysqlcompat/ — Shared helpers for MySQL/MariaDB
internal/adapter/mysqlcompat/helpers.go — DSN builder, EXPLAIN JSON parsing
internal/api/router.go — Chi router, CORS, SPA fallback
internal/api/handlers/ — HTTP handlers (connection CRUD, queries, SSE, paste)
internal/worker/scheduler.go — Ticker-based worker with concurrency limit (10)
internal/worker/collector.go — Per-connection metrics collector
internal/crypto/encrypt.go — AES-256-GCM encrypt/decrypt for DSN storage
migrations/ — SQL files embedded via migrations/embed.goKey patterns:
Appstruct ininternal/api/app.goholds dependencies (Store, CryptoKey, NewAdapter factory)- All adapter code lives in
internal/adapter/package (flat, not subpackaged) to avoid import cycles - Migrations use
//go:embedinmigrations/embed.go, consumed bystore.RunMigrations() - Worker starts as
go worker.Run(ctx, ...)insiderunServer()
apps/web/src/
types/index.ts — TS interfaces mirroring Go models
api/client.ts — Typed fetch wrapper for all API endpoints
hooks/ — use-connections, use-queries, use-sse
components/layout/ — Sidebar + Layout shell
components/connections/ — ConnectionForm, ConnectionList
components/queries/ — SlowQueryTable (TanStack Table v8), QueryDetailDrawer, QuerySparkline
components/ui/ — shadcn/ui components (DO NOT edit manually — use `npx shadcn@latest add`)
pages/ — Route pages (kebab-case filenames)
App.tsx — React Router wiringKey patterns:
@/path alias configured in tsconfig + vite for imports- shadcn/ui + Tailwind CSS v4 for styling
- Vite proxy:
/api→http://localhost:42198in dev mode - SSE hook (
use-sse.ts) with auto-reconnect for live query updates
GET/POST /api/connections
GET/PUT/DELETE /api/connections/{id}
POST /api/connections/{id}/test
GET /api/connections/{id}/queries — Latest snapshot with deltas
GET /api/connections/{id}/queries/stream — SSE live updates
GET /api/connections/{id}/queries/history — Historical snapshots
POST /api/paste/queries — Parse slow log text
/* — SPA fallback (serves apps/web/dist/index.html)| Variable | Default | Description |
|---|---|---|
PORT |
42198 |
HTTP server port |
DATABASE_URL |
(required) | PostgreSQL connection string for app metadata DB |
ENCRYPTION_KEY |
(required) | 64 hex chars (32 bytes) for AES-256-GCM DSN encryption |
WORKER_INTERVAL_SECS |
30 |
Background worker polling interval |
- DSN stored as AES-256-GCM ciphertext in
connections.encrypted_dsn(BYTEA) EncryptedDSNfield hasjson:"-"tag — never serialized to API responses- EXPLAIN uses
SET TRANSACTION READ ONLYto mitigate injection risk - All store queries use parameterized placeholders
- Request body limits: 1MB for CRUD, 10MB for paste endpoint
- No authentication in MVP — localhost-only tool