Files
gridline/AGENTS.md
T
2026-07-26 02:55:26 +08:00

9.5 KiB

AGENTS.md

Guidance for AI coding agents working on Gridline.


Project Identity

Gridline is an open-source, cross-platform database GUI client for PostgreSQL (with MySQL, SQLite, and Redis to follow). It is built as a Tauri 2.0 desktop app — a lightweight native shell (~40MB baseline) around a React web frontend, with a Rust backend handling all database operations, CLI tool orchestration, and local persistence.

Core differentiators from commercial alternatives (DB Pro, TablePlus, etc.):

  • No paywalls — unlimited tabs, connections, and saved queries by default
  • First-class PostgreSQL administration: pg_dump, pg_restore, DB-to-DB sync
  • Full object explorer: Functions, Triggers, Sequences, Enums, Extensions — not just tables

Target audience: Developers managing multiple database environments across projects (Personal, Work, Client). The workspace/folder hierarchy is a first-class concept.


Tech Stack

Layer Technology Notes
Desktop shell Tauri 2.0 Native webview wrapper, Rust backend
Frontend React 19 + TypeScript 5.8 Vite 7 for bundling/HMR
Styling Tailwind CSS Dark-first, glassmorphic aesthetic
State Zustand or Jotai Pick one and stay consistent per feature
Editor Monaco Editor SQL mode with custom autocomplete providers
Data grid Glide Data Grid or TanStack Virtual Virtualized, canvas-rendered
Backend Rust (tokio async runtime) Connection pools, IPC commands, shell execution
DB drivers sqlx + tokio-postgres Async, pure-Rust PostgreSQL driver
Local storage SQLite via rusqlite User settings, workspace state, query history
Credentials OS keychain macOS Keychain, Linux Secret Service, Windows Credential Manager

Project Structure

gridline/
├── src/                          # React frontend (TypeScript)
│   ├── components/               # Reusable UI components
│   │   ├── layout/               # App shell, sidebar, tabs
│   │   ├── editor/               # Monaco wrapper, autocomplete
│   │   ├── grid/                 # Data grid, filters, export
│   │   ├── tree/                 # Workspace/object explorer tree
│   │   └── ui/                   # Primitives (buttons, modals, inputs)
│   ├── stores/                   # Zustand/Jotai stores
│   ├── hooks/                    # Custom hooks (useConnection, useQuery, etc.)
│   ├── lib/                      # Utilities, types, Tauri bindings
│   │   ├── commands.ts           # Typed wrappers around Tauri invoke()
│   │   ├── types.ts              # Shared TypeScript interfaces
│   │   └── utils.ts              # Formatting, validation helpers
│   ├── App.tsx
│   ├── main.tsx
│   └── index.css                 # Tailwind directives + custom theme tokens
├── src-tauri/                    # Rust backend
│   ├── src/
│   │   ├── main.rs               # Binary entry point
│   │   ├── lib.rs                # Tauri builder, command registration
│   │   ├── db/                   # Connection pooling, query execution
│   │   │   ├── mod.rs
│   │   │   ├── pool.rs           # Connection pool manager
│   │   │   └── introspection.rs  # Schema/system catalog queries
│   │   ├── commands/             # Tauri #[tauri::command] handlers
│   │   │   ├── mod.rs
│   │   │   ├── connections.rs    # CRUD for saved connections
│   │   │   ├── query.rs          # SQL execution
│   │   │   ├── schema.rs         # Object tree introspection
│   │   │   ├── backup.rs         # pg_dump / pg_restore wrappers
│   │   │   └── workspace.rs      # Workspace/folder persistence
│   │   ├── models/               # Serde structs shared across commands
│   │   │   ├── mod.rs
│   │   │   ├── connection.rs
│   │   │   ├── query.rs
│   │   │   └── workspace.rs
│   │   └── store/                # SQLite local persistence layer
│   │       ├── mod.rs
│   │       └── migrations.rs
│   ├── Cargo.toml
│   ├── tauri.conf.json
│   └── capabilities/             # Tauri capability permissions
├── public/                       # Static frontend assets
├── package.json
├── tsconfig.json
├── vite.config.ts
├── tailwind.config.ts
└── AGENTS.md                     # This file

Conventions

TypeScript / React

  • Components: PascalCase files, default exports for page-level, named exports for reusable primitives
  • Hooks: use prefix, one hook per file unless tightly coupled
  • Stores: One Zustand store per domain (connectionStore, queryStore, workspaceStore)
  • Types: Define interfaces in src/lib/types.ts; use type for unions/aliases
  • No any: Always type Tauri invoke() calls with explicit generics
  • CSS: Tailwind utility classes only; no CSS modules unless unavoidable (Monaco configuration is the exception)

Rust

  • Modules: One module file per concern; re-export through mod.rs
  • Errors: Use anyhow for application errors, thiserror for library-style enums
  • Commands: Keep #[tauri::command] functions thin — delegate to db/ or store/ modules
  • State: Use Tauri managed state (app.manage()) for connection pool handles
  • Naming: snake_case for functions/modules, CamelCase for types/structs

General

  • IPC flow: Frontend calls typed wrapper → wrapper calls invoke() → Rust command → Rust logic → returns Result<T, String>
  • Error handling: Rust commands return Result<T, String> (map errors to user-readable strings before crossing IPC boundary)
  • No secrets in logs: Never log connection strings, passwords, or query parameters
  • Dark mode first: All UI components must look correct in dark theme; light theme is secondary

Key Design Decisions

  1. Tauri over Electron — ~40MB RAM vs 250MB+. Native file dialogs, OS keychain access, and std::process::Command for pg_dump/pg_restore without Node.js overhead.

  2. Rust-native DB driverssqlx/tokio-postgres connect directly to PostgreSQL from the Rust backend. No Node.js pg library, no sidecar Node process. The frontend never touches database connections directly.

  3. System CLI tools for backup/restore — Rather than implementing pg_dump format parsers in Rust (enormous scope), we shell out to the user's installed pg_dump/pg_restore binaries. The app will detect missing tools and guide installation.

  4. SQLite for local state — Workspace tree, saved queries, connection metadata (NOT passwords), and query history go into a local SQLite database in the Tauri app data directory. This enables fast full-text search and relational queries without loading everything into memory.

  5. Virtualized grid from day one — Query results can be 100k+ rows. We must render with canvas/DOM virtualization (Glide Data Grid or TanStack Virtual), never with naive DOM row rendering.


Development Workflow

Commands

bun install              # Install frontend dependencies
bun run dev              # Vite dev server only (no Tauri)
bun run tauri dev        # Full Tauri app with hot-reload
bun run tauri build      # Production build
cargo build              # Rust backend only (from src-tauri/)
cargo test               # Rust tests

Adding a Tauri Command

  1. Define the command function in the appropriate src-tauri/src/commands/ module
  2. Register it in src-tauri/src/lib.rs via .invoke_handler(tauri::generate_handler![...])
  3. Create a typed wrapper function in src/lib/commands.ts
  4. Call the wrapper from your React component/store

Adding a New Dependency

  • Frontend: bun add <package> (runtime) or bun add -d <package> (dev)
  • Rust: Add to src-tauri/Cargo.toml under [dependencies]

Testing Strategy

  • Rust: Unit tests for database logic, connection pool management, and command handlers. Use sqlx::test with a test PostgreSQL instance for integration tests.
  • Frontend: Vitest + React Testing Library for component tests. Focus on store logic, command wrappers, and critical UI flows (connection form, query execution).
  • E2E: (Future) Tauri WebDriver or Playwright for critical paths.

Constraints & Guardrails

  • Do NOT implement pg_dump file format parsing — always shell out to system binaries
  • Do NOT store passwords in SQLite or local files — use OS keychain APIs exclusively
  • Do NOT render large query results in raw DOM — always use the virtualized grid component
  • Do NOT log credentials, connection strings, or query data
  • Do NOT introduce Electron, Node.js server processes, or Docker dependencies
  • DO keep Tauri commands thin — business logic lives in db/ and store/ modules
  • DO type all IPC boundaries explicitly
  • DO validate and sanitize all user-provided SQL and connection parameters before execution


This file is read by AI coding agents (Claude, Cursor, Copilot, etc.) to understand project conventions and architecture before making changes. Keep it current as the project evolves.