# NexaPG - PostgreSQL Monitoring Stack NexaPG is a Docker-based PostgreSQL monitoring platform for multiple remote targets, built with FastAPI + React. ## PostgreSQL Version Support NexaPG targets PostgreSQL versions **14, 15, 16, 17, and 18**. - Compatibility is verified with an automated CI matrix. - Collector and overview queries include fallbacks for stats view differences between versions (for example `pg_stat_bgwriter` vs `pg_stat_checkpointer` fields). ## What it includes - Multi-target PostgreSQL monitoring (remote instances) - Polling collector for: - `pg_stat_database` - `pg_stat_activity` - `pg_stat_bgwriter` - `pg_locks` - `pg_stat_statements` (if enabled on target) - Core metadata database for: - Authentication and RBAC (`admin`, `operator`, `viewer`) - Monitored target configuration (encrypted credentials) - Metrics and query stats - Audit logs - JWT auth (access + refresh) - FastAPI + SQLAlchemy async + Alembic migrations - React (Vite) frontend with: - Login/logout - Dashboard overview - Target detail with charts and database overview - Query insights - Admin user management - Health endpoints: - `/api/v1/healthz` - `/api/v1/readyz` ## Repository structure - `backend/` FastAPI application - `frontend/` React (Vite) application - `ops/` helper scripts and env template copy - `docker-compose.yml` full stack definition - `.env.example` environment template ## Prerequisites Install these before starting: - Docker Engine 24+ - Docker Compose v2+ - GNU Make (optional, for `make up/down/logs/migrate`) - Open ports on your host: - frontend: `5173` (default) - backend: `8000` (or your `BACKEND_PORT`) - core DB: `5433` (or your `DB_PORT`) Optional but recommended: - `psql` client for troubleshooting target connectivity ## Quick start 1. Create local env file: ```bash cp .env.example .env ``` 2. Generate an encryption key and set `ENCRYPTION_KEY` in `.env`: ```bash python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" ``` 3. Start services: ```bash make up ``` 4. Open: - Frontend: `http://:5173` (or `https://`) - Backend API: `http://:8000/api/v1` (or `https:///api/v1`) - OpenAPI docs: `http://:8000/docs` (or `https:///docs`) Default initial admin (from `.env`): - Email: `admin@example.com` - Password: `ChangeMe123!` ## Common commands ```bash make up # build + start all services make down # stop all services make logs # follow logs make migrate # run Alembic migrations in backend container ``` PostgreSQL compatibility smoke check script: ```bash PG_DSN='postgresql://postgres:postgres@127.0.0.1:5432/compatdb?sslmode=disable' \ python backend/scripts/pg_compat_smoke.py ``` CI/runner-safe variant (tries multiple hosts): ```bash PG_DSN_CANDIDATES='postgresql://postgres:postgres@postgres:5432/compatdb?sslmode=disable,postgresql://postgres:postgres@127.0.0.1:5432/compatdb?sslmode=disable' \ python backend/scripts/pg_compat_smoke.py ``` ## Environment variables reference All variables are defined in `.env.example`. ### Application - `APP_NAME`: Display name used by backend/docs - `ENVIRONMENT`: `dev | staging | prod | test` - `LOG_LEVEL`: `DEBUG | INFO | WARNING | ERROR` ### Core database (internal) - `DB_NAME`: Internal metadata DB name - `DB_USER`: Internal metadata DB user - `DB_PASSWORD`: Internal metadata DB password - `DB_PORT`: Host port mapped to internal PostgreSQL `5432` ### Backend API - `BACKEND_PORT`: Host port mapped to backend container `8000` - `JWT_SECRET_KEY`: JWT signing key (must be changed) - `JWT_ALGORITHM`: JWT algorithm (default `HS256`) - `JWT_ACCESS_TOKEN_MINUTES`: access token lifetime - `JWT_REFRESH_TOKEN_MINUTES`: refresh token lifetime - `ENCRYPTION_KEY`: Fernet key for encrypting target passwords at rest - `CORS_ORIGINS`: comma-separated allowed origins or `*` (dev-only) - `POLL_INTERVAL_SECONDS`: collector polling interval - `INIT_ADMIN_EMAIL`: bootstrap admin email - `INIT_ADMIN_PASSWORD`: bootstrap admin password ### Frontend - `FRONTEND_PORT`: Host port mapped to frontend container `80` - `VITE_API_URL`: API base URL baked into frontend build - Proxy/SSL setup: use `/api/v1` - Direct server setup: use `http://:/api/v1` ## API overview (minimum) - Auth: - `POST /api/v1/auth/login` - `POST /api/v1/auth/refresh` - `POST /api/v1/auth/logout` - `GET /api/v1/me` - Targets: - `GET/POST /api/v1/targets` - `GET/PUT/DELETE /api/v1/targets/{id}` - `GET /api/v1/targets/{id}/metrics?from=&to=&metric=` - `GET /api/v1/targets/{id}/locks` - `GET /api/v1/targets/{id}/activity` - `GET /api/v1/targets/{id}/top-queries` - `GET /api/v1/targets/{id}/overview` - Admin users (admin-only): - `GET /api/v1/admin/users` - `POST /api/v1/admin/users` - `PUT /api/v1/admin/users/{user_id}` - `DELETE /api/v1/admin/users/{user_id}` ## Security notes - No secrets are hardcoded in source - Passwords are hashed with Argon2 - Target credentials are encrypted with Fernet - CORS is environment-configurable - Audit logs include auth, target, and user management events - Rate limiting is currently a placeholder for future middleware integration ## Important: `pg_stat_statements` Query Insights requires `pg_stat_statements` on each monitored target. ```sql CREATE EXTENSION IF NOT EXISTS pg_stat_statements; ``` ## Reverse proxy and SSL For production-like deployments behind HTTPS: - Set frontend API to relative path: `VITE_API_URL=/api/v1` - Route `/api/` from proxy to backend service - Keep frontend and API on the same public origin to avoid CORS/mixed-content problems ## CI Compatibility Matrix GitHub Actions workflow: - `.github/workflows/pg-compat-matrix.yml` It runs smoke checks against PostgreSQL `14`, `15`, `16`, `17`, and `18`.