cd /news/ai-products/i-built-an-open-source-admin-panel-b… Β· home β€Ί topics β€Ί ai-products β€Ί article
[ARTICLE Β· art-85677] src=github.com β†— pub= topic=ai-products verified=true sentiment=↑ positive

I built an open-source admin panel builder for existing databases

DBoard, an open-source admin panel builder created by developer Haimanot25, uses AI to generate admin panels, dashboards, forms, and queries from natural language prompts for existing databases, supporting PostgreSQL, MySQL, MongoDB, SQLite, Supabase, and SQL Server. The tool, available on GitHub, offers zero-code CRUD interfaces, AI-powered dashboards, a SQL console, schema diff, database monitoring, and self-hosting via Docker, with features like CSRF protection, AES-256-GCM encryption, and audit logs.

read33 min views2 publishedAug 4, 2026
I built an open-source admin panel builder for existing databases
Image: source

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

── more in #ai-products 4 stories Β· sorted by recency
── more on @dboard 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/i-built-an-open-sour…] indexed:0 read:33min 2026-08-04 Β· β€”