Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
52 changes: 52 additions & 0 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Format

on:
pull_request:
branches:
- master
- develop
paths:
- "src/**"
- "public/**"
- "scripts/**"
- "*.json"
- "*.js"
- "*.ts"
- "*.tsx"
- "*.css"
- "pnpm-lock.yaml"
- ".prettierignore"
- ".prettierrc.json"
- ".github/workflows/format.yml"

concurrency:
group: format-${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true

permissions:
contents: read

jobs:
format:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 22
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Check formatting
run: pnpm format:check
51 changes: 51 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Lint

on:
pull_request:
branches:
- master
- develop
paths:
- "src/**"
- "public/**"
- "scripts/**"
- "*.json"
- "*.js"
- "*.ts"
- "*.tsx"
- "*.css"
- "pnpm-lock.yaml"
- "eslint.config.js"
- ".github/workflows/lint.yml"

concurrency:
group: lint-${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true

permissions:
contents: read

jobs:
lint:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 22
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run lint
run: pnpm lint
5 changes: 2 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,12 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10 # aligned with release workflow
version: 10 # aligned with release workflow

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 22 # aligned with release workflow, not lts/*
node-version: 22 # aligned with release workflow, not lts/*
cache: "pnpm"

- name: Install bridge dependencies
Expand All @@ -137,4 +137,3 @@ jobs:
run: |
cd bridge
pnpm test

10 changes: 10 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
node_modules
dist
coverage
.git
.turbo
src-tauri/target
src-tauri/gen
src-tauri/resources
*.lock
pnpm-lock.yaml
6 changes: 6 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"semi": true,
"singleQuote": false,
"trailingComma": "all",
"printWidth": 100
}
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ RelWave uses a **Bridge Architecture** to balance performance, security, and dev
## 🛠️ Tech Stack

### Frontend

- **Framework:** React 19
- **Build Tool:** Vite
- **Styling:** Tailwind CSS 4, shadcn/ui (Radix UI)
Expand All @@ -21,13 +22,15 @@ RelWave uses a **Bridge Architecture** to balance performance, security, and dev
- **Editor:** CodeMirror 6 (SQL editing)

### Bridge (Node.js)

- **Runtime:** Node.js (bundled via `pkg`)
- **Database Drivers:** `pg` (PostgreSQL), `mysql2` (MySQL/MariaDB), `better-sqlite3` (SQLite)
- **Version Control:** `simple-git`
- **Logging:** `pino`
- **Security:** `@napi-rs/keyring` for encrypted credential storage

### Desktop Layer

- **Framework:** Tauri 2 (Rust)

## 📂 Key Directories
Expand Down
101 changes: 62 additions & 39 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ RelWave is a cross-platform desktop database visualizer built with a high-perfor

RelWave consists of three distinct layers that communicate over a JSON-RPC protocol:

* **Frontend (React/TypeScript):** A modern, responsive UI built with Vite, Tailwind CSS (optional), and Lucide icons. It manages state using TanStack Query and coordinates with the bridge via a service layer.
* **Bridge (Node.js):** A standalone backend bundled with `pkg`. It handles all heavy-lifting tasks: database connectivity (PostgreSQL, MySQL, MariaDB, SQLite), Git version control, and file system operations.
* **Tauri (Rust):** The native shell that hosts the web view and manages the bridge as a sidecar process. It acts as a secure pipe, forwarding standard I/O between the Frontend and the Bridge.
- **Frontend (React/TypeScript):** A modern, responsive UI built with Vite, Tailwind CSS (optional), and Lucide icons. It manages state using TanStack Query and coordinates with the bridge via a service layer.
- **Bridge (Node.js):** A standalone backend bundled with `pkg`. It handles all heavy-lifting tasks: database connectivity (PostgreSQL, MySQL, MariaDB, SQLite), Git version control, and file system operations.
- **Tauri (Rust):** The native shell that hosts the web view and manages the bridge as a sidecar process. It acts as a secure pipe, forwarding standard I/O between the Frontend and the Bridge.

### Data Flow Diagram

Expand All @@ -29,31 +29,40 @@ Databases / Git / Filesystem
The bridge is the core engine of RelWave, designed to be fast, extensible, and isolated from the UI.

### JSON-RPC Dispatcher

The communication follows a standard JSON-RPC 2.0 pattern over `stdin` and `stdout`.

1. **Entry Point (`bridge/src/index.ts`):** Initializes the `JsonStdio` instance and registers all handlers.
2. **Protocol (`bridge/src/jsonRpc.ts`):** `JsonStdio` handles framing (newline-delimited JSON) and provides `sendResponse`, `sendError`, and `sendNotification`.
3. **Dispatcher (`bridge/src/jsonRpcHandler.ts`):** The `JsonRpcHandler` maps incoming method names (e.g., `db.list`) to specific handler functions.

### Adding a New Command

To add a new command, follow these steps:

1. Define the request/response types in `bridge/src/types/`.
2. Implement the logic in a relevant handler (e.g., `bridge/src/handlers/databaseHandlers.ts`) or create a new handler in `bridge/src/handlers/`.
3. Register the new handler/method in `bridge/src/jsonRpcHandler.ts` inside the `registerDbHandlers` function.
4. Add a corresponding method to the frontend service layer in `src/services/bridge/`.

### Session Management (`bridge/src/sessionManager.ts`)

The `SessionManager` tracks active operations, particularly long-running queries.
* Each query runs in a `Session`.
* Sessions store a `cancel` callback and a `connectionId`.
* A background sweep timer removes stale sessions (default 30 min idle).

- Each query runs in a `Session`.
- Sessions store a `cancel` callback and a `connectionId`.
- A background sweep timer removes stale sessions (default 30 min idle).

### Connection Pooling (`bridge/src/services/connectionPool.ts`)

The `ConnectionPool` manages engine-specific connections.
* Connections are keyed by `dbId`.
* The `ConnectionPool` uses the `ConnectorRegistry` to obtain the correct connector (Postgres, MySQL, etc.).
* Idle connections are automatically swept after 10 minutes.

- Connections are keyed by `dbId`.
- The `ConnectionPool` uses the `ConnectorRegistry` to obtain the correct connector (Postgres, MySQL, etc.).
- Idle connections are automatically swept after 10 minutes.

### Connector Registry (`bridge/src/services/connectorRegistry.ts`)

A mapping of `DBType` to engine implementations. This decoupling allows adding new database support by simply implementing the `Connector` interface.

---
Expand All @@ -63,31 +72,37 @@ A mapping of `DBType` to engine implementations. This decoupling allows adding n
The frontend is designed for speed and reliability, using a "local-first" philosophy where possible.

### Feature Structure

Features are modularly organized under `src/features/[feature-name]/`:
* `types.ts`: TypeScript definitions for the feature.
* `hooks/`: Feature-specific hooks (often wrapping TanStack Query).
* `components/`: UI components.
* `index.ts`: Public API for the feature.

- `types.ts`: TypeScript definitions for the feature.
- `hooks/`: Feature-specific hooks (often wrapping TanStack Query).
- `components/`: UI components.
- `index.ts`: Public API for the feature.

### Bridge Service Layer

The frontend talks to the bridge through specialized services in `src/services/bridge/`:
* `bridgeClient.ts`: Low-level wrapper for `invoke('bridge_write')` and `listen('bridge-stdout')`.
* `database.ts`, `query.ts`, `git.ts`, etc.: High-level methods that wrap `bridgeRequest`.

- `bridgeClient.ts`: Low-level wrapper for `invoke('bridge_write')` and `listen('bridge-stdout')`.
- `database.ts`, `query.ts`, `git.ts`, etc.: High-level methods that wrap `bridgeRequest`.

### State Management
* **TanStack Query:** Used for almost all bridge-related state. It handles caching, loading states, and automatic refetching.
* **React Context:** Used for global UI state (themes, active connection).

- **TanStack Query:** Used for almost all bridge-related state. It handles caching, loading states, and automatic refetching.
- **React Context:** Used for global UI state (themes, active connection).

---

## 4. Database Query Organization

Queries are organized by engine under `bridge/src/queries/`:
* **`constraints.ts`:** Introspection for PKs, FKs, and indexes.
* **`schema.ts`:** Listing tables, schemas, and databases.
* **`stats.ts`:** Database size, row counts, and performance metrics.
* **`crud.ts`:** Row-level operations (Insert, Update, Delete, Search).
* **`migrations.ts`:** Schema migration management.

- **`constraints.ts`:** Introspection for PKs, FKs, and indexes.
- **`schema.ts`:** Listing tables, schemas, and databases.
- **`stats.ts`:** Database size, row counts, and performance metrics.
- **`crud.ts`:** Row-level operations (Insert, Update, Delete, Search).
- **`migrations.ts`:** Schema migration management.

This engine-specific organization avoids the "leaky abstraction" problem of generic ORMs and allows RelWave to use powerful native features (like Postgres' `pg_query_stream` or MySQL's `KILL QUERY`).

Expand All @@ -96,29 +111,31 @@ This engine-specific organization avoids the "leaky abstraction" problem of gene
## 5. Adding a New Feature (End-to-End Checklist)

1. **Bridge Logic:**
* [ ] Add types to `bridge/src/types/`.
* [ ] (If needed) Add SQL queries to `bridge/src/queries/[engine]/`.
* [ ] Add method to a service in `bridge/src/services/`.
* [ ] Implement RPC method in `bridge/src/handlers/`.
* [ ] Register in `bridge/src/jsonRpcHandler.ts`.
- [ ] Add types to `bridge/src/types/`.
- [ ] (If needed) Add SQL queries to `bridge/src/queries/[engine]/`.
- [ ] Add method to a service in `bridge/src/services/`.
- [ ] Implement RPC method in `bridge/src/handlers/`.
- [ ] Register in `bridge/src/jsonRpcHandler.ts`.
2. **Frontend Logic:**
* [ ] Add bridge call to `src/services/bridge/[service].ts`.
* [ ] Create a hook in `src/features/[feature]/hooks/` using `useQuery` or `useMutation`.
* [ ] Implement UI components in `src/features/[feature]/components/`.
* [ ] Integrate into a page or the main layout.
- [ ] Add bridge call to `src/services/bridge/[service].ts`.
- [ ] Create a hook in `src/features/[feature]/hooks/` using `useQuery` or `useMutation`.
- [ ] Implement UI components in `src/features/[feature]/components/`.
- [ ] Integrate into a page or the main layout.

---

## 6. Key Data Flows

### Connect to a Database

1. **UI:** User enters credentials and clicks "Connect".
2. **Frontend:** `databaseService.addDatabase` calls `bridgeRequest('db.add', params)`.
3. **Bridge:** `DatabaseHandlers.add` calls `DatabaseService.addDatabase`.
4. **Bridge:** `DbStore` encrypts the password and saves meta to `relwave.json`.
5. **Response:** The new `dbId` is returned to the UI.

### Execute a SQL Query and Stream Results

1. **UI:** User executes SQL in the query editor.
2. **Frontend:** `queryService.runQuery` calls `bridgeRequest('query.run', { sql, sessionId, dbId })`.
3. **Bridge:** `QueryHandlers.run` initializes a `Session`.
Expand All @@ -127,12 +144,14 @@ This engine-specific organization avoids the "leaky abstraction" problem of gene
6. **Frontend:** `bridgeClient` listens for these events and dispatches them to the UI.

### Run a Migration

1. **UI:** User selects a pending migration and clicks "Apply".
2. **Frontend:** `migrationService.apply` calls `bridgeRequest('migration.apply', { connectionId, filename })`.
3. **Bridge:** `MigrationHandlers.apply` calls `DatabaseService` to get the connection and then calls `applyMigration` in the engine connector (e.g., `postgres.ts`).
4. **Connector:** Reads the `.sql` file, executes the `+up` section in a transaction, and records the version in `schema_migrations`.

### Monitor a live database metric

1. **UI:** User opens the "Monitoring" tab for a database.
2. **Frontend:** Opens a WebSocket connection to the bridge via `MonitoringWebSocketServer`.
3. **Bridge:** `MonitoringService` starts a ticker that periodically queries the DB for metrics (health, active queries, throughput).
Expand All @@ -144,16 +163,20 @@ This engine-specific organization avoids the "leaky abstraction" problem of gene
## 7. Testing

### Organization
* **Bridge Unit Tests:** Located in `bridge/__tests__/`. Focus on services and utils.
* **Bridge Integration Tests:** Located in `bridge/__tests__/connectors/`. Test actual DB connectivity.

- **Bridge Unit Tests:** Located in `bridge/__tests__/`. Focus on services and utils.
- **Bridge Integration Tests:** Located in `bridge/__tests__/connectors/`. Test actual DB connectivity.

### Running Tests
* `npm test`: Runs all bridge tests.
* `npm run test:watch`: Runs tests in watch mode.

- `npm test`: Runs all bridge tests.
- `npm run test:watch`: Runs tests in watch mode.

### Docker Compose Test Setup

`bridge/docker-compose.test.yml` provides a standard environment with:
* PostgreSQL 16
* MySQL 8.0
* MariaDB 11.2
Used for end-to-end connector validation.

- PostgreSQL 16
- MySQL 8.0
- MariaDB 11.2
Used for end-to-end connector validation.
6 changes: 4 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
Welcome, Claude. This document outlines project-specific instructions and preferences to help you provide the best possible assistance.

## 🎯 High-Level Goals

RelWave is a modern, high-performance database management tool. Our priority is a seamless developer experience, visual clarity, and rock-solid reliability.

## 🛠️ Code Style & Preferences

- **React:**
- **React:**
- Use functional components with hooks.
- Prefer TanStack Query for data fetching and state synchronization.
- Use `lucide-react` for icons.
Expand All @@ -25,6 +26,7 @@ RelWave is a modern, high-performance database management tool. Our priority is
## 🌉 The Bridge Protocol

When implementing a new feature that requires the Bridge:

1. **Define the Interface:** Decide on the JSON-RPC method name and parameters.
2. **Bridge Handler:** Add a handler in `bridge/src/handlers/`.
3. **Bridge Service:** Implement the logic in a service within `bridge/src/services/`.
Expand All @@ -46,4 +48,4 @@ When implementing a new feature that requires the Bridge:

- **No browser-only APIs:** Remember this runs in a desktop environment.
- **No heavy logic in handlers:** Handlers should just route requests to services.
- **No direct DB calls from Frontend:** All database interaction *must* go through the bridge.
- **No direct DB calls from Frontend:** All database interaction _must_ go through the bridge.
Loading
Loading