Build admin panels and dashboards for any database β zero code, AI-powered.
DBoard connects to your existing database and uses AI to instantly generate admin panels, dashboards, forms, and queries from a simple natural language prompt. No coding required.
Connect PostgreSQL, MySQL, MongoDB, SQLite, or Supabase β describe what you want in plain English β and DBoard builds it. Edit rows with validated forms, visualize data with auto-generated charts, run queries with a built-in SQL console, and share dashboards with your team.
Dashboard with charts, metrics, and real-time data
SQL query editor with syntax highlighting and saved queries
Database monitoring with live metrics and table inventory
Schema comparison between two databases
Zero-Code Admin Panelsβ Generate full CRUD interfaces from a natural language prompt β no templates, no configuration** AI-Powered Dashboards**β "Show me monthly revenue by product category" β instant chart with no SQL needed** Multi-Database**β Connect PostgreSQL, MySQL, SQLite, MongoDB, Supabase, or SQL Server through one unified interface** Database-First**β Works with your existing database. No data migration, no vendor lock-in, no schema redesign** SQL Console**β Write and execute queries with syntax highlighting, saved queries, history, and AI-powered generation** Data Grid**β Browse, search, filter, sort, inline edit, bulk delete, and import/export (CSV, JSON, Excel, PDF)** Schema Diff**β Compare schemas across two databases and visualize differences instantly** DB Monitor**β Real-time health checks, table inventory, row counts, and performance metrics** Sharing & Collaboration**β Share connections and dashboards with read/write/admin permissions** Webhooks**β Send real-time notifications to Slack, Discord, PagerDuty, or custom HTTP endpoints** API Keys**β Generate scoped API keys for programmatic access to your databases** Secure**β CSRF protection, SSRF guard, AES-256-GCM encryption at rest, rate limiting, audit logs** Self-Hosted**β Your data never leaves your server. Deploy with Docker in one command** Dark Mode**β Eye-friendly dark theme with 6 built-in color presets and full customization
| Database | Status | Default Port | Adapter | Notes |
|---|---|---|---|---|
| PostgreSQL | β | 5432 | SQL (Knex) | Full support including pg_stat views |
| MySQL | β | 3306 | SQL (Knex) | Full support |
| SQLite | β | β | SQL (Knex) | File-based, no network config |
| MongoDB | β | 27017 | Native | Document introspection, aggregation |
| Supabase | β | β | REST API | Uses Supabase JS client |
| SQL Server | β | 1433 | SQL (Knex) | Full support via mssql driver |
- Node.js 20+ (recommended: use nvm) - npm, yarn, or pnpm
- Git
git clone https://github.com/Haimanot25/dboard.git
cd dboard
npm install
cp .env.example .env
openssl rand -base64 32 # Use for NEXTAUTH_SECRET
openssl rand -base64 32 # Use for ENCRYPTION_KEY
npx prisma generate
npx prisma db push
npm run dev
Open http://localhost:3000 and register your first account.
export NEXTAUTH_SECRET=$(openssl rand -base64 32)
export ENCRYPTION_KEY=$(openssl rand -base64 32)
docker compose up -d
Open http://localhost:3000.
| Variable | Description | Required | Default |
|---|---|---|---|
DATABASE_URL |
|||
| SQLite URL for Prisma (application metadata) | Yes | file:./dev.db |
|
NEXTAUTH_SECRET |
|||
| Secret for NextAuth.js session encryption | Yes | β | |
NEXTAUTH_URL |
|||
| Canonical URL for NextAuth.js | Yes | http://localhost:3000 |
|
ENCRYPTION_KEY |
|||
| Key for encrypting database passwords and API keys (AES-256-GCM) | Yes | β | |
ALLOW_PRIVATE_DB_HOSTS |
|||
Set to 1 to allow connections to localhost/private IPs (dev only) |
|||
| No | 0 |
Production:Generate strong secrets withopenssl rand -base64 32
. Never use default or placeholder values.
| Layer | Technology |
|---|---|
| Framework | Next.js 14 (App Router) |
| Language | TypeScript 5 (strict mode) |
| Database ORM | Prisma 5 |
| Authentication | NextAuth.js 4 (Credentials + JWT) |
| UI Components | shadcn/ui (Radix UI + Tailwind CSS) |
| State Management | TanStack React Query 5 |
| Table Grid | TanStack React Table 8 |
| Drag & Drop | @dnd-kit |
| Command Palette | cmdk |
| Charts | Custom SVG (Bar, Line, Pie, Sparkline, Heatmap) |
| Testing | Vitest (unit) + Playwright (E2E) |
| Linting | ESLint + eslint-plugin-security |
| Dead Code Detection | Knip |
dboard/
βββ .github/
β βββ workflows/ci.yml # CI/CD pipeline (7 jobs)
βββ docs/ # Screenshots and documentation assets
βββ e2e/ # Playwright E2E tests
β βββ auth.spec.ts
β βββ connections.spec.ts
β βββ dashboard.spec.ts
β βββ data-browse.spec.ts
β βββ query.spec.ts
βββ prisma/
β βββ schema.prisma # Database schema (16 models)
β βββ seed.ts # Database seed script
βββ public/ # Static assets (logos, favicon)
βββ scripts/
β βββ seed-demo-db.sql # Demo database seed SQL
βββ src/
β βββ app/
β β βββ (auth)/ # Auth route group
β β β βββ login/
β β β βββ layout.tsx
β β βββ (dashboard)/ # Dashboard route group
β β β βββ connections/ # Connection management
β β β β βββ page.tsx # List connections
β β β β βββ [id]/ # Connection detail
β β β β βββ tables/ # Browse tables
β β β β βββ query/ # SQL editor
β β β β βββ schema/ # Schema viewer
β β β β βββ settings/# Connection settings
β β β β βββ edit/ # Edit connection
β β β βββ dashboards/ # Dashboard management
β β β β βββ page.tsx # List dashboards
β β β β βββ [id]/ # Dashboard detail
β β β βββ admin-pages/ # Admin page management
β β β βββ settings/ # Application settings
β β β β βββ ai/ # AI provider config
β β β β βββ profile/ # User profile
β β β β βββ theme/ # Theme editor
β β β β βββ plugins/ # Plugin manager
β β β β βββ audit-logs/ # Audit log viewer
β β β β βββ notifications/
β β β β βββ templates/ # Dashboard templates
β β β β βββ backup/ # Backup & restore
β β β βββ db-monitor/ # Database monitoring
β β β βββ ai/ # AI generation page
β β β βββ schema-diff/ # Schema comparison
β β β βββ profile/ # User profile page
β β βββ api/ # API routes (80 endpoints)
β β β βββ auth/ # Authentication
β β β βββ connections/ # Connection CRUD + health + info
β β β βββ dashboards/ # Dashboard CRUD + charts + shares
β β β βββ data/ # Table data CRUD + bulk operations
β β β βββ query/ # SQL execution + saved + history + AI
β β β βββ schema/ # Introspection + diff + config
β β β βββ ai/ # AI generation + providers
β β β βββ settings/ # Profile + notifications
β β β βββ admin-pages/ # Admin page CRUD
β β β βββ views/ # Saved views
β β β βββ favorites/ # Favorite toggle
β β β βββ shares/ # Connection sharing
β β β βββ webhooks/ # Webhook CRUD + actions
β β β βββ api-keys/ # API key CRUD
β β β βββ activity/ # Activity feed
β β β βββ audit-logs/ # Audit log viewer
β β β βββ alerts/ # Alert management
β β β βββ plugins/ # Plugin registry
β β β βββ theme/ # Theme presets
β β β βββ csrf/ # CSRF token
β β β βββ export/ # Data export
β β β βββ import/ # Data import
β β β βββ dashboard-templates/
β β βββ layout.tsx # Root layout
β β βββ providers.tsx # React Query + Theme providers
β β βββ globals.css # Global styles
β βββ components/
β β βββ layout/ # Layout components
β β β βββ DashboardShell.tsx
β β β βββ Sidebar.tsx
β β β βββ TopNav.tsx
β β βββ ui/ # shadcn/ui primitives
β β βββ shared/ # Shared components
β β βββ dashboard/ # Dashboard components
β β βββ data-grid/ # Data grid components
β β βββ connections/ # Connection components
β β βββ query/ # Query editor components
β β βββ schema/ # Schema components
β β βββ settings/ # Settings components
β β βββ ai/ # AI components
β β βββ db-monitor/ # Database monitoring components
β βββ hooks/ # 20 custom React hooks
β βββ lib/
β β βββ ai/ # AI providers and generation
β β βββ db/
β β β βββ drivers/ # Database adapters
β β β βββ encryption.ts # AES-256-GCM encryption
β β β βββ ssrf-guard.ts # SSRF protection
β β β βββ plugins/ # Adapter plugin system
β β βββ theme/ # Theme system
β β βββ widgets/ # Widget plugin registry
β β βββ webhooks/ # Webhook plugin registry
β β βββ schema/ # Schema caching
β β βββ crud/ # Query builder
β β βββ auth.ts # Authentication config
β β βββ auth-helpers.ts # Auth utilities
β β βββ csrf.ts # CSRF protection
β β βββ permissions.ts # Permission system
β β βββ api-keys.ts # API key management
β β βββ audit.ts # Audit logging
β β βββ rate-limit.ts # Rate limiting
β β βββ with-rate-limit.ts # Rate limit middleware
β β βββ login-rate-limit.ts # Login rate limiting
β β βββ sql-guard.ts # SQL write detection
β β βββ prisma.ts # Prisma client
β β βββ utils.ts # Utility functions
β βββ types/ # TypeScript type definitions
β βββ generated/ # Prisma generated client
βββ tests/ # Unit/integration tests
βββ .env.example # Environment template
βββ .eslintrc.json # ESLint config
βββ .gitignore # Git ignore rules
βββ .gitleaks.toml # Secret scanning config
βββ components.json # shadcn/ui config
βββ docker-compose.yml # Docker Compose config
βββ Dockerfile # Multi-stage Docker build
βββ knip.json # Dead code detection config
βββ next.config.mjs # Next.js config + security headers
βββ package.json # Dependencies and scripts
βββ playwright.config.ts # E2E test config
βββ postcss.config.mjs # PostCSS config
βββ tailwind.config.ts # Tailwind CSS config
βββ tsconfig.json # TypeScript config
βββ vitest.config.ts # Vitest test config
βββ CONTRIBUTING.md # Contributing guidelines
βββ CODE_OF_CONDUCT.md # Code of conduct
βββ LICENSE # MIT License
βββ SECURITY.md # Security policy
βββ CHANGELOG.md # Version history
βββ README.md # This file
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DashboardShell β
β ββββββββββββ ββββββββββββββββββββββββββββββββββββββββββββ β
β β β β TopNav β β
β β Sidebar β β [Menu] [Page Title] [SearchβK] [π] [βΌ] β β
β β β ββββββββββββββββββββββββββββββββββββββββββββ€ β
β β [Dash] β β β β
β β [Admin] β β Page Content β β
β β [Settingsβ β (children prop) β β
β β [DB Mon] β β β β
β β β β β β
β β ββββββββ β β β β
β β β
Favs β β β β
β β β β β β
β β ββββββββ β β β β
β β [User] β β β β
β β [π][β‘] β β β β
β ββββββββββββ ββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Browser Request
β
βΌ
βββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β Next.js βββββΆβ Auth Check βββββΆβ CSRF Check β
β Middleware β β (JWT/API Key)β β (Origin) β
βββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β
βΌ
ββββββββββββββββ ββββββββββββββββ
β Rate Limit βββββΆβ Route β
β (IP+Path) β β Handler β
ββββββββββββββββ ββββββββββββββββ
β
βΌ
ββββββββββββββββ ββββββββββββββββ
β Prisma βββββΆβ SQLite β
β (Metadata) β β (App DB) β
ββββββββββββββββ ββββββββββββββββ
β
βΌ
ββββββββββββββββ ββββββββββββββββ
β Adapter βββββΆβ Target DB β
β (PG/MySQL/..) β (User's DB) β
ββββββββββββββββ ββββββββββββββββ
DBoard uses SQLite (via Prisma) to store application metadata. The schema contains 16 models:
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| String | @unique |
|
| name | String? | |
| password | String? | PBKDF2 hash (salt:hash) |
| role | String | @default("editor") β viewer, editor, admin |
| createdAt | DateTime | @default(now()) |
| updatedAt | DateTime | @updatedAt |
Relations: connections, dashboards, adminPages, apiKeys, auditLogs, queryHistory, savedViews, alerts, aiProviders, favorites, connectionShares, dashboardShares
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| name | String | Display name |
| type | String | @default("postgresql") β postgresql, mysql, sqlite, mongodb, supabase, mssql |
| host | String | @default("localhost") |
| port | Int | @default(5432) |
| database | String | Database name |
| username | String | |
| encryptedPassword | String? | AES-256-GCM encrypted |
| ssl | Boolean | @default(false) |
| readOnly | Boolean | @default(false) |
| poolMin | Int | @default(0) |
| poolMax | Int | @default(10) |
| poolIdleTimeout | Int | @default(30000) |
| queryTimeoutMs | Int | @default(30000) |
| userId | String | Owner |
| createdAt | DateTime | @default(now()) |
| updatedAt | DateTime | @updatedAt |
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| name | String | |
| description | String? | |
| userId | String | Owner |
| createdAt | DateTime | @default(now()) |
| updatedAt | DateTime | @updatedAt |
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| dashboardId | String | |
| title | String | |
| type | String | @default("bar") β bar, line, pie, table, sparkline, heatmap |
| connectionId | String | |
| query | String | SQL query |
| config | String | @default("{}") β JSON config |
| width | Int | @default(1) β grid columns |
| height | Int | @default(1) β grid rows |
| x | Int | @default(0) β grid position |
| y | Int | @default(0) β grid position |
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| name | String | |
| key | String | @unique β dbo_ + 64 hex chars |
| lastChars | String | Last 8 chars for display |
| permissions | String | @default("read") β read, write, admin |
| connectionId | String | Scoped to one connection |
| userId | String | Owner |
| expiresAt | DateTime? | |
| lastUsedAt | DateTime? | Fire-and-forget update |
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| connectionId | String | |
| userId | String | |
| sql | String | |
| durationMs | Int | @default(0) |
| rowCount | Int | @default(0) |
| error | String? | |
| saved | Boolean | @default(false) |
| createdAt | DateTime | @default(now()) |
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| connectionId | String | @unique |
| config | String | JSON schema configuration |
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| connectionId | String | |
| userId | String | |
| action | String | e.g., "connection.created", "row.updated" |
| tableName | String? | |
| recordId | String? | |
| details | String? | JSON details |
| ip | String? | |
| dashboardId | String? |
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| name | String | |
| url | String | Target URL |
| events | String | @default("row.created,row.updated,row.deleted") |
| connectionId | String | |
| enabled | Boolean | @default(true) |
| secret | String? | For signature verification |
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| connectionId | String | |
| sharedWithId | String | |
| sharedById | String | |
| permission | String | @default("read") β read, write, admin |
@@unique([connectionId, sharedWithId]) |
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| dashboardId | String | |
| sharedWithId | String | |
| sharedById | String | |
| permission | String | @default("read") |
@@unique([dashboardId, sharedWithId]) |
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| name | String | |
| connectionId | String | |
| tableName | String | |
| config | String | JSON view configuration |
| userId | String |
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| userId | String | |
| name | String | @default("chatgpt") |
| displayName | String | @default("ChatGPT / OpenAI") |
| encryptedApiKey | String? | AES-256-GCM encrypted |
| baseUrl | String? | |
| isEnabled | Boolean | @default(true) |
| sortOrder | Int | @default(0) |
@@unique([userId, name]) |
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| providerId | String | |
| modelId | String | |
| displayName | String | |
| isDefault | Boolean | @default(false) |
| sortOrder | Int | @default(0) |
@@unique([providerId, modelId]) |
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| name | String | |
| connectionId | String | |
| tableName | String | |
| condition | String | Alert condition |
| enabled | Boolean | @default(true) |
| webhookUrl | String? | |
| String? | ||
| lastTriggeredAt | DateTime? | |
| userId | String |
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| name | String | |
| description | String? | |
| userId | String | |
| connectionId | String | |
| config | String | @default("{}") β JSON page config |
| Field | Type | Attributes |
|---|---|---|
| id | String | @id @default(cuid()) |
| userId | String | |
| kind | String | "dashboard" or "adminPage" |
| targetId | String | |
@@unique([userId, kind, targetId]) |
DBoard implements multiple layers of security to protect your data:
File: src/lib/db/ssrf-guard.ts
All outbound database and webhook connections are validated against Server-Side Request Forgery:
Private IP blockingβ Blocks RFC 1918 addresses (10.x, 172.16-31.x, 192.168.x), loopback (127.x), link-local (169.254.x), and IPv6 ULA/link-localDNS validationβ Resolves hostnames before connecting; blocks connections if any resolved address is private** DNS rebinding protection**β Validates resolved addresses match expectations** Protocol enforcement**β Only HTTP/HTTPS allowed for webhooks
Configuration: Set ALLOW_PRIVATE_DB_HOSTS=1
in .env
to allow localhost connections (development only).
File: src/lib/db/encryption.ts
| Property | Value |
|---|---|
| Algorithm | AES-256-GCM (authenticated encryption) |
| Key Derivation | crypto.scryptSync() with salt "dboard-v1" |
| IV | 16 random bytes per encryption |
| Output Format | hex(iv):hex(authTag):hex(ciphertext) |
Used to encrypt:
- Database passwords (
Connection.encryptedPassword
) - AI provider API keys (
AiProvider.encryptedApiKey
)
File: src/lib/csrf.ts
All state-changing endpoints (POST/PUT/DELETE) validate that the Origin
header matches the Host
header. Skipped for API key authentication (non-browser clients).
File: src/lib/auth.ts
| Property | Value |
|---|---|
| Password Hashing | PBKDF2 with SHA-512 |
| Iterations | 600,000 |
| Salt | 16 random bytes per password |
| Comparison | crypto.timingSafeEqual() (timing-attack resistant) |
| Session Strategy | JWT with 24-hour max age |
| Custom Login Page | /login |
Login Rate Limiting (src/lib/login-rate-limit.ts
):
| Track | Max Attempts | Window | Lockout |
|---|---|---|---|
| Per-account (email) | 5 | 15 min | 15 min |
| Per-IP | 30 | 15 min | 15 min |
General Rate Limiting (src/lib/with-rate-limit.ts
):
- Default: 100 requests per 60-second window per IP+path
- Configurable per-route (5β30 requests per 60 seconds)
- Returns
429 Too Many Requests
withRetry-After
header
File: src/lib/sql-guard.ts
Protects read-only connections from write operations:
β Detects INSERT, UPDATE, DELETE, DROP, ALTER, TRUNCATE, CREATE, GRANT, REVOKE, and 15+ other write keywordsisWriteQuery(sql)
β Validates query starts with SELECT, WITH, SHOW, DESCRIBE, EXPLAIN, or PRAGMAisReadQuery(sql)
Literal strippingβ Removes string literals before checking to prevent false positives from data values
File: src/lib/permissions.ts
| Role | Hierarchy | Capabilities |
|---|---|---|
| viewer | 1 | Read-only access to connection data |
| editor | 2 | Read + write access (default for new users) |
| admin | 3 | Full access including sharing and deletion |
Connection access logic:
- Admin role can access everything
- Owner (created the connection) gets access; write blocked if
readOnly
is set - Shared access via
ConnectionShare
with read/write/admin permission levels
File: src/lib/api-keys.ts
Format:dbo_
prefix + 64 hex characters (32 random bytes)Scope: Each key is scoped to a single connectionPermissions:read
(1) <write
(2) <admin
(3)Authentication:X-API-Key
header orAuthorization: Bearer dbo_*
CSRF: Skipped for API key requests (non-browser clients)Expiry: Optional expiration date; checked on every requestTracking:lastUsedAt
updated on each use
| Provider | API Format | Base URL | Auth | Free Tier |
|---|---|---|---|---|
| ChatGPT / OpenAI | OpenAI Chat | https://api.openai.com/v1 |
||
| Bearer token | No | |||
| Groq | OpenAI Chat | https://api.groq.com/openai/v1 |
||
| Bearer token | Yes | |||
| Google Gemini | Gemini Content | https://generativelanguage.googleapis.com/v1beta |
||
| Query key | Yes | |||
| Ollama | OpenAI Chat | http://localhost:11434 |
||
| None | Yes (local) | |||
| OpenRouter | OpenAI Chat | https://router.ai/api/v1 |
||
| Bearer token | Varies |
| Provider | Models |
|---|---|
| OpenAI | GPT-4o, GPT-4o Mini, GPT-4 Turbo, o3-mini |
| Groq | GPT-OSS 120B, Llama 3 70B, Llama 3 8B, Mixtral 8x7B, Gemma 2 9B |
| Gemini | Gemini 2.0 Flash, Gemini 2.0 Flash Lite, Gemini 2.5 Pro |
| Ollama | Llama 3, Llama 3.1, Mistral, CodeLlama |
| OpenRouter | GPT-4o Mini, GPT-4o, Claude 3.5 Sonnet, Llama 3.3 70B, DeepSeek Chat |
| Type | Description | Output |
|---|---|---|
query |
||
| Generate SQL from natural language | Raw SQL string | |
dashboard |
||
| Generate a multi-chart dashboard | Dashboard + chart configs | |
panel |
||
| Generate a CRUD admin panel | Panel config with columns, filters, actions | |
form |
||
| Generate form fields from schema | Form field configuration |
- Navigate to Settings β AI - Select a provider (e.g., Groq for free usage)
- Enter your API key (encrypted at rest with AES-256-GCM)
- Set a default model
- Use in the SQL editor (AI tab) or AI generation page
DBoard supports three types of plugins:
Connect to databases beyond the built-in six. Each adapter must implement the DatabaseAdapter
interface:
interface DatabaseAdapter {
connect(config: ConnectionConfig): Promise<void>;
disconnect(): Promise<void>;
test(config: ConnectionConfig): Promise<boolean>;
introspect(): Promise<SchemaResult>;
executeRaw(query: string, params?: unknown[]): Promise<QueryResult>;
list(table: string, options: ListOptions, columns: ColumnMeta[]): Promise<PaginatedResult>;
get(table: string, pkValue: string, pkColumn: string): Promise<Record<string, unknown> | null>;
create(table: string, data: Record<string, unknown>, columns: ColumnMeta[]): Promise<Record<string, unknown>>;
update(table: string, pkValue: string, pkColumn: string, data: Record<string, unknown>, columns: ColumnMeta[]): Promise<Record<string, unknown>>;
delete(table: string, pkValue: string, pkColumn: string): Promise<void>;
bulkDelete(table: string, pkValues: string[], pkColumn: string): Promise<void>;
}
NPM naming: @dboard/adapter-<name>
or dboard-adapter-<name>
Built-in adapters: PostgreSQL, MySQL, SQLite, SQL Server, MongoDB, Supabase
External adapter examples: ClickHouse, DynamoDB, Firestore, Redis, Cassandra
Create custom chart and visualization types for dashboards:
interface WidgetDefinition {
id: string;
name: string;
description: string;
category: "chart" | "visualization" | "table" | "custom";
icon: string;
renderer: ComponentType<WidgetRendererProps>;
defaultConfig?: Record<string, unknown>;
configSchema?: WidgetConfigField[];
}
NPM naming: @dboard/widget-<name>
or dboard-widget-<name>
Built-in widgets: Bar Chart, Pie Chart, Line Chart, Data Table, Sparkline, Heatmap
External widget examples: Geo Map, Network Graph, Gauge, Treemap
Create custom notification targets for data change events:
interface WebhookAction {
id: string;
name: string;
description: string;
icon: string;
configFields: WebhookConfigField[];
deliver(url: string, payload: WebhookPayload, config: Record<string, unknown>): Promise<WebhookDeliveryResult>;
}
NPM naming: @dboard/webhook-<name>
or dboard-webhook-<name>
Built-in actions: Slack, Discord, PagerDuty, Custom HTTP
External webhook examples: Email, Jira, Microsoft Teams
DBoard supports two authentication methods:
Session-based (browser):
curl -X POST http://localhost:3000/api/auth/callback/credentials \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "email=user@example.com&password=secret" \
-c cookies.txt
API key (programmatic):
curl -H "X-API-Key: dbo_your_api_key_here" http://localhost:3000/api/data/conn_123/users
curl -H "Authorization: Bearer dbo_your_api_key_here" http://localhost:3000/api/data/conn_123/users
Content-Type:application/json
(unless noted otherwise)Error format:{ "error": "Error message" }
Success format: Resource object or{ "success": true }
Rate limit headers:X-RateLimit-Remaining
,Retry-After
(on 429)
All rate limits are per IP + path, per 60-second window:
| Limit | Endpoints |
|---|---|
| 5 req | Register, AI reset |
| 10 req | Connection test, API key create, schema diff, export, import, dashboard duplicate |
| 15 req | AI generate |
| 20 req | Connection create/update/delete, admin pages, shares, webhooks, charts, alerts, settings |
| 30 req | Data CRUD, query execute, dashboard CRUD, views, favorites, activity, API keys |
| 100 req | Default (GET-heavy routes) |
Register a new user account.
Rate Limit: 5 req/hour per IP
curl -X POST http://localhost:3000/api/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","name":"Alice","password":"securepass"}'
Response (200):
{ "id": "clx123...", "email": "user@example.com", "name": "Alice" }
List all connections for the current user.
curl -b cookies.txt http://localhost:3000/api/connections
Response (200):
[
{
"id": "clx123...",
"name": "My PostgreSQL",
"type": "postgresql",
"host": "localhost",
"port": 5432,
"database": "mydb",
"username": "postgres",
"ssl": false,
"readOnly": false,
"createdAt": "2026-08-02T00:00:00.000Z"
}
]
Create a new database connection.
CSRF Required | Rate Limit: 20 req/60s
curl -X POST http://localhost:3000/api/connections \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"name":"Production DB","type":"postgresql","host":"db.example.com","port":5432,"database":"prod","username":"admin","password":"secret","ssl":true}'
Request Body:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| name | string | Yes | β | Display name |
| type | string | No | "postgresql" |
|
| Database type | ||||
| host | string | No | "localhost" |
|
| Hostname or IP | ||||
| port | number | No | 5432 | Port number |
| database | string | Yes | β | Database name |
| username | string | No | "" |
|
| Username | ||||
| password | string | No | β | Password (encrypted at rest) |
| ssl | boolean | No | false |
|
| Use SSL connection | ||||
| readOnly | boolean | No | false |
|
| Read-only mode |
Response (200): Connection object (without password)
Test a connection without saving it.
CSRF Required | Rate Limit: 10 req/60s
curl -X POST http://localhost:3000/api/connections/test \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"type":"postgresql","host":"localhost","port":5432,"database":"test","username":"postgres","password":"secret"}'
Response (200): { "success": true, "message": "Connection successful" }
Get a single connection by ID.
curl -b cookies.txt http://localhost:3000/api/connections/clx123...
Update an existing connection.
CSRF Required | Rate Limit: 30 req/60s
curl -X PUT http://localhost:3000/api/connections/clx123... \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"name":"Updated Name","ssl":true}'
Delete a connection.
CSRF Required | Rate Limit: 30 req/60s
curl -X DELETE http://localhost:3000/api/connections/clx123... -b cookies.txt
Health-check a connection (measures latency).
curl -b cookies.txt http://localhost:3000/api/connections/clx123.../health
Response (200): { "status": "online", "latencyMs": 12 }
Response (500): { "status": "offline", "error": "...", "latencyMs": null }
Get detailed database metadata (version, size, tables, row counts, cache hit ratio, uptime).
curl -b cookies.txt http://localhost:3000/api/connections/clx123.../info
Response (200):
{
"connectionId": "clx123...",
"status": "online",
"version": "PostgreSQL 16.2",
"databaseSize": "15 MB",
"tableCount": 12,
"totalRecords": 45230,
"activeConnections": 3,
"cacheHitRatio": 99.8,
"uptime": "14 days",
"tables": [
{ "name": "users", "type": "table", "rowCount": 1500, "totalSize": "240 kB", "indexCount": 3 }
]
}
List all dashboards for the current user.
curl -b cookies.txt http://localhost:3000/api/dashboards
Create a new dashboard.
CSRF Required | Rate Limit: 30 req/60s
curl -X POST http://localhost:3000/api/dashboards \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"name":"Sales Dashboard","description":"Revenue tracking"}'
Get a dashboard with its charts.
curl -b cookies.txt http://localhost:3000/api/dashboards/clx456...
Delete a dashboard.
CSRF Required | Rate Limit: 20 req/60s
curl -X DELETE http://localhost:3000/api/dashboards/clx456... -b cookies.txt
Add a chart to a dashboard.
CSRF Required | Rate Limit: 20 req/60s
curl -X POST http://localhost:3000/api/dashboards/clx456.../charts \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"title":"User Count","type":"bar","connectionId":"clx123...","query":"SELECT count(*) FROM users"}'
Delete a chart from a dashboard.
Update a chart in a dashboard.
Duplicate a dashboard with all its charts.
CSRF Required | Rate Limit: 10 req/60s
curl -X POST http://localhost:3000/api/dashboards/clx456.../duplicate -b cookies.txt
List all shares for a dashboard.
Share a dashboard with another user.
CSRF Required | Rate Limit: 30 req/60s
curl -X POST http://localhost:3000/api/dashboards/clx456.../shares \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"sharedWithEmail":"bob@example.com","permission":"read"}'
Remove a dashboard share.
List rows from a table with pagination, sorting, and search.
curl -b cookies.txt "http://localhost:3000/api/data/clx123.../users?page=1&pageSize=20&sortBy=created_at&sortDir=desc&search=alice"
Query Parameters:
| Param | Type | Default | Description |
|---|---|---|---|
| page | number | 1 | Page number |
| pageSize | number | 20 | Rows per page (max 100) |
| sortBy | string | β | Column to sort by |
| sortDir | string | "asc" |
|
| Sort direction: asc, desc | |||
| search | string | β | Search across string columns |
| * | string | β | Custom column filters (column=value) |
Response (200):
{
"data": [{ "id": 1, "name": "Alice", "email": "alice@example.com" }],
"columns": [{ "name": "id", "dataType": "integer", "isPrimaryKey": true }],
"tableName": "users",
"isView": false,
"page": 1,
"pageSize": 20,
"total": 150,
"totalPages": 8
}
Insert a new row.
CSRF Required (skipped for API key) | Rate Limit: 30 req/60s
curl -X POST http://localhost:3000/api/data/clx123.../users \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"name":"Bob","email":"bob@example.com"}'
Get a single row by primary key.
curl -b cookies.txt http://localhost:3000/api/data/clx123.../users/42
Update a row by primary key.
CSRF Required (skipped for API key) | Rate Limit: 30 req/60s
curl -X PUT http://localhost:3000/api/data/clx123.../users/42 \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"name":"Bob Updated"}'
Delete a row by primary key.
CSRF Required (skipped for API key) | Rate Limit: 30 req/60s
curl -X DELETE http://localhost:3000/api/data/clx123.../users/42 -b cookies.txt
Bulk delete rows by IDs (max 1000).
CSRF Required (skipped for API key) | Rate Limit: 30 req/60s
curl -X POST http://localhost:3000/api/data/clx123.../users/bulk-delete \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"ids":[1,2,3,4,5]}'
Response (200): { "success": true, "deleted": 5 }
Execute a raw SQL query.
CSRF Required (skipped for API key)
curl -X POST http://localhost:3000/api/query/clx123... \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"sql":"SELECT * FROM users WHERE created_at > '\''2026-01-01'\''"}'
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
| sql | string | Yes | SQL query to execute |
| dateFrom | string | No | Start date for date-range injection |
| dateTo | string | No | End date for date-range injection |
Response (200):
{
"columns": ["id", "name", "email"],
"data": [{ "id": 1, "name": "Alice", "email": "alice@example.com" }],
"rowCount": 1,
"totalRows": 1,
"truncated": false,
"durationMs": 12,
"isReadQuery": true
}
List saved queries for a connection (max 50).
curl -b cookies.txt http://localhost:3000/api/query/clx123.../saved
Save a query.
curl -X POST http://localhost:3000/api/query/clx123.../saved \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"sql":"SELECT count(*) FROM users"}'
Delete a saved query.
List query execution history (max 200).
curl -b cookies.txt "http://localhost:3000/api/query/clx123.../history?limit=20"
Generate SQL from natural language using AI.
CSRF Required
curl -X POST http://localhost:3000/api/query/clx123.../ai \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"prompt":"Show me all users who signed up this week","modelId":"gpt-4o-mini"}'
Response (200): { "sql": "SELECT * FROM users WHERE created_at >= date('now', '-7 days')" }
Introspect a connection's database schema (cached for 60 seconds).
curl -X POST http://localhost:3000/api/schema/introspect \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"connectionId":"clx123..."}'
Compare schemas between two connections.
CSRF Required | Rate Limit: 10 req/60s
curl -X POST http://localhost:3000/api/schema/diff \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"sourceConnectionId":"clx123...","targetConnectionId":"clx456..."}'
Response (200):
{
"onlyInSource": ["legacy_users"],
"onlyInTarget": ["new_table"],
"columnDiffs": [{ "table": "users", "added": ["avatar"], "removed": [] }],
"sourceTableCount": 12,
"targetTableCount": 11
}
Save schema configuration (column-level metadata).
Get schema configuration for a connection.
Generate structured content from a prompt.
CSRF Required | Rate Limit: 15 req/60s
curl -X POST http://localhost:3000/api/ai/generate \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"prompt":"Create a user management panel","connectionId":"clx123...","type":"panel","modelId":"gpt-4o-mini"}'
Types: panel
, dashboard
, form
, query
Test an AI provider connection.
CSRF Required | Rate Limit: 10 req/60s
curl -X POST http://localhost:3000/api/ai/test \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"providerId":"chatgpt","modelId":"gpt-4o-mini"}'
List all AI providers and models (API keys masked).
curl -b cookies.txt http://localhost:3000/api/ai/providers
Update an AI provider (API key, base URL, enabled status).
Reset all AI providers to defaults. Rate Limit: 5 req/60s
Set the global default AI model.
Update user profile (name).
curl -X PUT http://localhost:3000/api/settings/profile \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"name":"Alice Smith"}'
Get notification preferences.
Update notification preferences.
List all admin pages.
Create a new admin page.
curl -X POST http://localhost:3000/api/admin-pages \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"name":"User Management","connectionId":"clx123...","config":{}}'
Get a single admin page.
Update an admin page.
Delete an admin page.
List saved views for a connection.
Create a saved view.
curl -X POST http://localhost:3000/api/views/clx123... \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"name":"Active Users","tableName":"users","config":{"filters":{"status":"active"}}}'
Delete a saved view.
List all favorites for the current user.
Toggle a favorite.
curl -X POST http://localhost:3000/api/favorites \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"kind":"dashboard","targetId":"clx456..."}'
Response (200): { "favorited": true }
or { "favorited": false }
List connection shares. Optional: ?connectionId=xxx
Share a connection with another user.
CSRF Required | Rate Limit: 30 req/60s
curl -X POST http://localhost:3000/api/shares \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"connectionId":"clx123...","sharedWithEmail":"bob@example.com","permission":"read"}'
Remove a connection share.
List webhooks. Optional: ?connectionId=xxx
Create a webhook.
CSRF Required | Rate Limit: 30 req/60s
curl -X POST http://localhost:3000/api/webhooks \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"name":"Slack Notify","url":"https://hooks.slack.com/...","events":"row.created,row.updated","connectionId":"clx123..."}'
Update a webhook.
Delete a webhook.
List available webhook action types (no auth required).
List all API keys. Optional: ?connectionId=xxx
curl -b cookies.txt http://localhost:3000/api/api-keys
Create a new API key (shown only once).
CSRF Required | Rate Limit: 10 req/60s
curl -X POST http://localhost:3000/api/api-keys \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"name":"CI Pipeline","connectionId":"clx123...","permissions":"read","expiresInDays":90}'
Response (200):
{
"id": "clx789...",
"name": "CI Pipeline",
"key": "dbo_a1b2c3d4e5f6...",
"lastChars": "...f6g7h8i9",
"permissions": "read",
"expiresAt": "2026-11-01T00:00:00.000Z"
}
Note:The full API key is shown only in this response. Store it securely.
Delete an API key.
List the current user's activity feed (max 200).
curl -b cookies.txt "http://localhost:3000/api/activity?limit=20"
List audit logs. Optional connection filter.
curl -b cookies.txt "http://localhost:3000/api/audit-logs?limit=50"
List alerts for a connection.
Create an alert.
curl -X POST http://localhost:3000/api/alerts/clx123... \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"name":"High Row Count","tableName":"logs","condition":"row_count > 1000000","webhookUrl":"https://hooks.slack.com/..."}'
Enable or disable an alert.
Delete an alert.
List all registered plugins (no auth required).
List available theme presets (no auth required).
Generate a CSRF token (sets cookie).
Export table data. Formats: json
, csv
, jsonl
, xlsx
, pdf
.
curl -b cookies.txt "http://localhost:3000/api/export/clx123.../users?format=csv" --output users.csv
Import data from file (CSV, JSON, JSONL). Max 10MB, max 10,000 rows.
curl -X POST http://localhost:3000/api/import/clx123.../users \
-b cookies.txt \
-F "file=@users.csv" \
-F "format=csv"
Response (200): { "imported": 500, "total": 500, "truncated": false }
List built-in dashboard templates (Database Overview, Table Health, Query Performance, Sales Dashboard, User Analytics).
docker build -t dboard .
docker run -p 3000:3000 \
-e NEXTAUTH_SECRET=$(openssl rand -base64 32) \
-e ENCRYPTION_KEY=$(openssl rand -base64 32) \
-e DATABASE_URL=file:/data/dboard.db \
-v dboard-data:/data \
dboard
export NEXTAUTH_SECRET=$(openssl rand -base64 32)
export ENCRYPTION_KEY=$(openssl rand -base64 32)
docker compose up -d
docker compose logs -f
docker compose down
npm i -g vercel
vercel
Note:For Vercel, use an external database (PostgreSQL) instead of SQLite forDATABASE_URL
.
npm run build
pm2 start npm --name "dboard" -- start
pm2 save
pm2 startup
| Platform | DATABASE_URL | Notes |
|---|---|---|
| Local dev | file:./dev.db |
|
| SQLite, zero config | ||
| Docker | file:/data/dboard.db |
|
| Persistent via volume | ||
| Vercel | postgresql://... |
|
| External PostgreSQL required | ||
| Self-hosted | file:./data/dboard.db or postgresql://... |
|
| SQLite or external DB |
| Script | Command | Description |
|---|---|---|
dev |
||
npm run dev |
||
| Start development server | ||
build |
||
npm run build |
||
| Production build | ||
start |
||
npm run start |
||
| Start production server | ||
lint |
||
npm run lint |
||
| Run ESLint | ||
test |
||
npm run test |
||
| Run unit tests (Vitest) | ||
test:watch |
||
npm run test:watch |
||
| Run tests in watch mode | ||
test:coverage |
||
npm run test:coverage |
||
| Generate coverage report | ||
test:e2e |
||
npm run test:e2e |
||
| Run E2E tests (Playwright) | ||
test:e2e:ui |
||
npm run test:e2e:ui |
||
| Playwright UI mode | ||
lint:security |
||
npm run lint:security |
||
| Security-focused linting | ||
lint:dead |
||
npm run lint:dead |
||
| Dead code detection (Knip) | ||
audit:deps |
||
npm run audit:deps |
||
| Dependency vulnerability audit | ||
format |
||
npm run format |
||
| Format code with Prettier | ||
format:check |
||
npm run format:check |
||
| Check formatting | ||
seed |
||
npm run seed |
||
| Seed the database | ||
prisma:generate |
||
npx prisma generate |
||
| Regenerate Prisma client | ||
prisma:push |
||
npx prisma db push |
||
| Push schema changes |
Unit tests (Vitest):
npm run test # Run all tests
npm run test:watch # Watch mode
npm run test:coverage # Coverage report (70% threshold)
E2E tests (Playwright):
npm run test:e2e # Run all E2E tests
npm run test:e2e:ui # Interactive UI mode
Coverage thresholds: 70% lines, functions, branches, and statements.
npm run lint # ESLint (includes security rules)
npm run lint:dead # Dead code detection
npm run lint:security # Security-focused linting
npm run format:check # Prettier formatting check
The GitHub Actions workflow (.github/workflows/ci.yml
) runs 7 jobs:
Security Scanβnpm audit
+eslint-plugin-security
Lintβnext lint
+prettier --check
Type Checkβtsc --noEmit
Dead Code Detectionβknip
Unit Testsβvitest
with coverageE2E Testsβ Playwright (Chromium)** Build**βnext build
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
-
Fork the repository
-
Create a feature branch:
git checkout -b feature/my-feature -
Make your changes
-
Run tests:
npm run test -
Run linting:
npm run lint -
Commit your changes
-
Push to your fork and submit a Pull Request
Look for issues labeled good first issue
in the GitHub issue tracker.
All project documentation is maintained in the repository root:
| Document | Description |
|---|---|
This fileβ full project documentation, API reference, and setup guideCONTRIBUTING.mdCODE_OF_CONDUCT.mdSECURITY.mdCHANGELOG.mdLICENSEAUDIT-REPORT.mdNew here? Start withQuick StartaboveAPI integration? SeeAPI Referencewith curl examples for all 80 endpointsContributing? ReadCONTRIBUTING.mdfor the development workflowFound a bug?Open an issue** Security concern?**Follow the process inSECURITY.md
This project is licensed under the MIT License β see the LICENSE file for details.
Issues:GitHub Issues** Security:SeeSECURITY.mdfor vulnerability reporting Contributing:**SeeCONTRIBUTING.md