DBView is a brutalist database explorer (Next.js 14, React 18, TypeScript, Tailwind CSS) that currently works as a read-only PostgreSQL browser with a SQL query editor. It has solid foundations: AES-256 encryption, query validation, rate limiting, security headers, dark mode, 6 color palettes, CodeMirror SQL editor, EXPLAIN plans, multi-schema support, and responsive design.
To make it worth using for everyday developers (not just a portfolio piece), it needs: data editing, connection URL parsing, multi-database support, keyboard shortcuts, deployment tooling, and power-user features.
Previous plan phases (1-4) are COMPLETE. This is the new plan.
Status: COMPLETE Goal: Make DBView worth opening over pgAdmin/TablePlus for quick tasks.
Paste postgresql://user:pass@host:5432/db instead of filling 5 fields.
New files:
lib/connection-url.ts—parseConnectionURL(),isConnectionURL(),detectDatabaseType()
Modify:
app/components/connection-form.tsx— Add URL/Fields toggle mode, auto-populate fields from URLapp/api/connect/route.ts— Accept optionalconnectionUrlfield
Double-click a cell to edit. Add/delete rows. Confirmation modal shows generated SQL before executing.
New files:
lib/mutation.ts— Parameterized query builders:buildUpdateQuery(),buildInsertQuery(),buildDeleteQuery(),validateIdentifier()app/api/mutate/route.ts— Mutation endpoint (bypassesvalidateQuery(), uses safe query builder). ChecksDBVIEW_READ_ONLYenv var.app/components/editable-cell.tsx— Inline cell editor (input/textarea based on data type)app/components/row-editor.tsx— Add new row formapp/components/mutation-confirmation.tsx— Modal showing generated SQL before execution
Modify:
app/components/data-table.tsx— Double-click-to-edit, delete button on row hover, "ADD ROW" button. Requires primary key info to build WHERE clauses. Tables without PK show editing as disabled.app/components/dashboard.tsx— Pass schema metadata to DataTable, add mutation handlersapp/contexts/dashboard-context.tsx— Add mutation functions,refreshTableData(),readOnlyModestatelib/rate-limiter.ts— Add rate limit for/api/mutate(20/min)
Global shortcut system with help overlay.
New files:
app/hooks/use-keyboard-shortcuts.ts— Central registry, event handler, skips inputs/CodeMirrorapp/components/keyboard-shortcuts-help.tsx— Overlay listing all shortcuts by category
Shortcuts:
| Key | Action |
|---|---|
Cmd+K |
Focus table search |
Cmd+J |
Toggle sidebar |
Cmd+/ |
Show shortcuts help |
Cmd+Shift+Q |
Go to query page |
Cmd+Shift+T |
Go to tables page |
Cmd+N |
Add new row |
Escape |
Close modal/cancel edit |
Modify:
app/components/dashboard.tsx— Register navigation/table shortcutsapp/components/query-editor.tsx— Register query shortcutsapp/components/header.tsx— Add keyboard icon to open shortcuts help
One-click SQL prettify.
New dependency: sql-formatter
New file:
lib/sql-formatter.ts— Wrapssql-formatterwith brutalist defaults (uppercase keywords, 2-space indent)
Modify:
app/components/query-editor.tsx— Add "FORMAT" button
Show table size, row counts, index usage, vacuum info when a table is selected.
New files:
app/api/table-stats/[name]/route.ts— Returns stats frompg_class,pg_stat_user_tablesapp/components/table-stats.tsx— Compact stats bar: total size, index size, est. rows, seq/idx scans, last vacuum
Modify:
lib/db.ts— AddgetTableStats()functionapp/contexts/dashboard-context.tsx— AddtableStatsstate, load on table selecttypes/index.ts— AddTableStatsinterface
-
npm run build— no errors - Paste a connection URL → fields auto-populate → connect works
- Double-click cell → edit → confirm → data updates in DB
- Add row → confirm → row appears
- Delete row → confirm → row removed
-
Cmd+/opens shortcuts overlay - FORMAT button prettifies SQL
- Table stats show when table is selected
- Tables without primary key show editing disabled with explanation
Status: NOT STARTED Goal: Replace the brutalist design with a clean, functional UI suited for data-heavy work.
The brutalist aesthetic (2px borders, all-caps text, monospace everywhere, box shadows) prioritizes style over usability. For a database tool where you stare at tables of data, scan column names, and read query results, the UI needs to get out of the way. This phase replaces it with a modern, minimal design inspired by tools like TablePlus, Supabase Studio, and pgAdmin 4.
Replace brutalist CSS variables and Tailwind config with a clean design system.
Modify:
-
app/globals.css— Replace brutalist base styles:- Remove
* { @apply font-mono }(only code/data should be monospace) - Remove
h1-h6 { @apply font-bold uppercase }(headings should be sentence-case) - Add Inter/system font stack as default body font
- Add proper color tokens:
--bg,--bg-secondary,--border,--text-primary,--text-secondary,--text-muted,--accent,--accent-hover,--danger,--success,--warning - Light mode: soft grays (#f9fafb backgrounds, #e5e7eb borders, #111827 text)
- Dark mode: dark grays (#0f1117 backgrounds, #1f2937 borders, #f9fafb text)
- Remove
-
tailwind.config.ts— Replace brutalist extensions:- Remove
boxShadow.brutal* - Remove
white/blackcolor overrides (restore Tailwind defaults) - Add
fontFamily.sans(Inter, system-ui stack) - Keep
fontFamily.monofor code/data - Add
borderRadiustokens (sm: 4px, md: 6px, lg: 8px) - Add subtle shadow tokens (
shadow-sm,shadow-md)
- Remove
Restyle the base components from brutalist to clean.
Modify:
app/components/ui/button.tsx— Rounded corners, subtle hover states, no box shadows. Variants:primary(filled accent),secondary(outlined),ghost(text only),danger(red).app/components/ui/input.tsx— Rounded, light border, focus ring instead of brutalist focus shadow. Proper placeholder styling.app/components/ui/modal.tsx— Backdrop blur, rounded card, smooth fade-in. Drop the heavy black border.app/components/ui/card.tsx— Light border, subtle shadow, rounded corners.app/components/ui/badge.tsx— Pill shape, muted backgrounds, no heavy borders.app/components/ui/toast.tsx— Rounded, slide-in animation, icon per type.app/components/ui/spinner.tsx— Ensure it fits the new aesthetic.app/components/ui/skeleton.tsx— Subtle pulse animation, rounded.app/components/ui/confirm-dialog.tsx— Consistent with new modal style.
Clean up the structural chrome.
Modify:
app/components/header.tsx— Slim horizontal bar, no heavy borders. Database name in normal case. Clean icon buttons.app/components/sidebar.tsx— Light background, subtle separator from main content, hover highlights instead of heavy selection borders. Tree-style indentation for schemas/tables/views.app/components/footer.tsx— Minimal, muted text.app/components/resizable-splitter.tsx— Thin drag handle, subtle hover indicator.app/components/main-content.tsx— Clean padding, no heavy borders.app/components/mobile-menu.tsx— Slide-in drawer with backdrop.app/components/breadcrumb.tsx— Normal case, subtle separators, no heavy styling.
The most impactful changes — these are what users stare at.
Modify:
app/components/data-table.tsx— Thin borders or border-bottom only. Alternating row backgrounds. Compact row height. Sticky header. Monospace only for data cells, not headers. Remove all-caps from headers.app/components/table-schema.tsx— Clean collapsible card. Normal-case headers. Subtle PK badge.app/components/table-stats.tsx— Subtle stat chips or inline metrics. No heavy border box.app/components/relationship-display.tsx— Clean expandable sections. Subtle FK/index badges.app/components/pagination.tsx— Clean page buttons, muted info text.app/components/column-visibility.tsx— Clean dropdown/popover with checkboxes.app/components/export-dropdown.tsx— Clean dropdown menu.app/components/table-list.tsx— Clean list with hover states, active indicator.app/components/empty-state.tsx— Centered, muted, with icon.app/components/error-state.tsx— Red accent, clean retry button.
Update the Phase 1 feature UIs.
Modify:
app/components/connection-form.tsx— Clean form layout. Card-based. Proper field labels.app/components/connection-selector.tsx— Clean tabs or segmented control.app/components/saved-connections.tsx— Clean list with edit/delete actions.app/components/editable-cell.tsx— Clean inline input, subtle edit indicator.app/components/row-editor.tsx— Clean form in modal.app/components/mutation-confirmation.tsx— Clean confirmation dialog with syntax-highlighted SQL.app/components/keyboard-shortcuts-help.tsx— Clean overlay with grouped shortcuts. Kbd-style key badges.app/components/query-editor.tsx— Clean toolbar, subtle button styling.app/components/sql-editor.tsx— Ensure CodeMirror theme aligns with new palette.app/components/query-history.tsx— Clean list with timestamps.app/components/explain-plan.tsx— Clean tree display.app/components/theme-toggle.tsx— Clean icon toggle.app/components/connection-status.tsx— Subtle status indicator.
Modify:
app/components/skeletons/table-skeleton.tsx— Match new table styling.app/components/skeletons/sidebar-skeleton.tsx— Match new sidebar styling.
- Start with
globals.css+tailwind.config.ts(design tokens) — this immediately shifts the base look. - Restyle UI primitives (
button,input,modal,card,badge,toast) — these cascade everywhere. - Update layout components (
header,sidebar,footer,splitter) — the app frame. - Update data display components (
data-table,table-schema,pagination) — the core experience. - Update feature components and skeletons — finishing touches.
-
pnpm run build— no errors - Light mode looks clean with proper grays, rounded corners, readable text
- Dark mode has proper contrast, no brutalist artifacts
- Data table is readable with proper row density
- All modals/dialogs use new style (no heavy borders)
- All text is sentence-case (no unnecessary ALLCAPS)
- Monospace font only used for data cells, SQL, and code
- All Phase 1 features still function correctly
Status: NOT STARTED Goal: Make DBView deployable for teams with a single
docker-compose up.
New files:
Dockerfile— Multi-stage build (node:20-alpine builder + runner), Next.js standalone outputdocker-compose.yml— Service with env vars:ENCRYPTION_KEY,DATABASE_URL,DBVIEW_AUTH_ENABLED,DBVIEW_READ_ONLY.dockerignore— Exclude node_modules, .next, .git
Modify:
next.config.js(create if needed) — Addoutput: 'standalone'
Auto-connect from DATABASE_URL env var on startup.
Modify:
app/api/connect/route.ts— CheckDATABASE_URLon first requestlib/db/index.ts— AddconnectFromEnv()usingparseConnectionURL()app/contexts/connection-context.tsx— Check server for pre-configured connection on mount
New dependency: bcryptjs
New files:
lib/auth.ts— Session validation, bcrypt password checkapp/api/auth/login/route.ts— Login endpointapp/login/page.tsx— Brutalist login page
Modify:
middleware.ts— Checkauth-sessioncookie whenDBVIEW_AUTH_ENABLED=true
Env vars: DBVIEW_AUTH_ENABLED, DBVIEW_USERNAME, DBVIEW_PASSWORD_HASH
New files:
lib/audit-log.ts— Circular buffer (1000 entries) + stdout logging. Logs: timestamp, user, action, query, execution time, row count.app/api/audit/route.ts— GET recent audit entries
Modify:
app/api/query/route.ts— Log after query executionapp/api/mutate/route.ts— Log after mutation
Already wired in Phase 1B's /api/mutate route via DBVIEW_READ_ONLY env var.
Modify:
app/api/health/route.ts— ReturnreadOnlyModeflagapp/components/dashboard.tsx— Hide edit/insert/delete UI when read-only
-
docker buildsucceeds -
docker-compose upwithDATABASE_URLauto-connects - Auth login page appears when
DBVIEW_AUTH_ENABLED=true - Audit log records queries and mutations
-
DBVIEW_READ_ONLY=truehides all editing UI
Status: NOT STARTED Goal: Features that make daily drivers switch permanently.
New files:
app/hooks/use-saved-queries.ts— localStorage-backed saved queries with tagsapp/components/saved-queries.tsx— Saved queries panel with search and tags
Modify:
app/components/query-editor.tsx— Add "SAVE" button and saved queries sidebartypes/index.ts— AddSavedQueryinterface
SVG-based entity-relationship diagram for the current schema.
New files:
app/components/er-diagram.tsx— SVG renderer with tables as boxes, FK lines between themlib/er-layout.ts— Simple force-directed or grid layout algorithmapp/api/relationships/route.ts— All relationships for all tables in a schema
Modify:
app/components/header.tsx— Add "ER DIAGRAM" nav button
New dependency: papaparse
New files:
app/api/import/route.ts— Accepts CSV, parses, inserts into tableapp/components/csv-import.tsx— File upload with column mapping
New files:
app/components/table-wizard.tsx— Step-by-step form: table name, columns (name, type, nullable, default, PK), constraintsapp/api/ddl/route.ts— Executes CREATE TABLElib/ddl-builder.ts— Builds CREATE TABLE SQL from wizard input (dialect-aware)
Use actual table/column names in CodeMirror auto-completion.
Modify:
app/components/sql-editor.tsx— Passschemaoption to CodeMirror'ssql()extension with real table/column dataapp/contexts/dashboard-context.tsx— Cache table/column names for auto-completion
- Save a query → appears in saved queries panel → click to load
- ER diagram shows all tables with FK connections
- Import CSV into a table → data appears
- Create a table via wizard → table appears in sidebar
- Auto-complete suggests real table/column names
Status: NOT STARTED Goal: Final polish for a production-quality tool.
Side-by-side comparison of two query results.
New file:
app/components/result-diff.tsx— Row-by-row diff with highlighted changes
Export multiple tables at once as a ZIP file.
New dependency: archiver
New files:
app/api/export/batch/route.ts— Accepts table names, streams ZIP of CSV/JSONapp/components/batch-export.tsx— Table selection UI
Active queries, slow query log, connection pool usage, table bloat.
New file:
app/components/performance-dashboard.tsx— Usespg_stat_activity,pg_stat_user_tables,pg_stat_bgwriter
Allow custom query templates and data transformations.
New files:
lib/plugin-system.ts— Plugin registry with lifecycle hookslib/plugins/— Directory for built-in plugins
- Diff two query results → changes highlighted
- Batch export 3 tables → downloads ZIP
- Performance dashboard shows live stats
- Plugin loads and executes
| Phase | Package | Purpose |
|---|---|---|
| 1 | sql-formatter |
SQL prettifying |
| 2 | mysql2 |
MySQL database driver |
| 3 | bcryptjs |
Password hashing for auth |
| 4 | papaparse |
CSV parsing for import |
| 5 | archiver |
ZIP file creation for batch export |
lib/db.ts→lib/db/postgresql.ts— Database operations (decomposed in Phase 2)app/components/data-table.tsx— Gains editing in Phase 1Bapp/components/connection-form.tsx— URL parsing (1A), DB type selector (2D)app/contexts/dashboard-context.tsx— Mutations (1B), stats (1E), auto-complete (4E)types/index.ts— Grows with every phasemiddleware.ts— Auth check (3C)- All 14 API routes — Provider pattern migration (Phase 2)