RelWave is a cross-platform desktop database visualizer built with a high-performance bridge architecture. This document provides a deep dive into the system's structure, data flows, and design patterns.
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.
React UI (Renderer)
↕ [Webview Events / Invoke]
Tauri Rust Layer (Host)
↕ [stdin / stdout / stderr]
Node.js Bridge (Sidecar)
↕ [Native Drivers / CLI]
Databases / Git / Filesystem
The bridge is the core engine of RelWave, designed to be fast, extensible, and isolated from the UI.
The communication follows a standard JSON-RPC 2.0 pattern over stdin and stdout.
- Entry Point (
bridge/src/index.ts): Initializes theJsonStdioinstance and registers all handlers. - Protocol (
bridge/src/jsonRpc.ts):JsonStdiohandles framing (newline-delimited JSON) and providessendResponse,sendError, andsendNotification. - Dispatcher (
bridge/src/jsonRpcHandler.ts): TheJsonRpcHandlermaps incoming method names (e.g.,db.list) to specific handler functions.
To add a new command, follow these steps:
- Define the request/response types in
bridge/src/types/. - Implement the logic in a relevant handler (e.g.,
bridge/src/handlers/databaseHandlers.ts) or create a new handler inbridge/src/handlers/. - Register the new handler/method in
bridge/src/jsonRpcHandler.tsinside theregisterDbHandlersfunction. - Add a corresponding method to the frontend service layer in
src/services/bridge/.
The SessionManager tracks active operations, particularly long-running queries.
- Each query runs in a
Session. - Sessions store a
cancelcallback and aconnectionId. - A background sweep timer removes stale sessions (default 30 min idle).
The ConnectionPool manages engine-specific connections.
- Connections are keyed by
dbId. - The
ConnectionPooluses theConnectorRegistryto obtain the correct connector (Postgres, MySQL, etc.). - Idle connections are automatically swept after 10 minutes.
A mapping of DBType to engine implementations. This decoupling allows adding new database support by simply implementing the Connector interface.
The frontend is designed for speed and reliability, using a "local-first" philosophy where possible.
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.
The frontend talks to the bridge through specialized services in src/services/bridge/:
bridgeClient.ts: Low-level wrapper forinvoke('bridge_write')andlisten('bridge-stdout').database.ts,query.ts,git.ts, etc.: High-level methods that wrapbridgeRequest.
- 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).
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.
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).
- 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
- Frontend Logic:
- Add bridge call to
src/services/bridge/[service].ts. - Create a hook in
src/features/[feature]/hooks/usinguseQueryoruseMutation. - Implement UI components in
src/features/[feature]/components/. - Integrate into a page or the main layout.
- Add bridge call to
- UI: User enters credentials and clicks "Connect".
- Frontend:
databaseService.addDatabasecallsbridgeRequest('db.add', params). - Bridge:
DatabaseHandlers.addcallsDatabaseService.addDatabase. - Bridge:
DbStoreencrypts the password and saves meta torelwave.json. - Response: The new
dbIdis returned to the UI.
- UI: User executes SQL in the query editor.
- Frontend:
queryService.runQuerycallsbridgeRequest('query.run', { sql, sessionId, dbId }). - Bridge:
QueryHandlers.runinitializes aSession. - Bridge:
QueryExecutoruses the specific connector (e.g.,postgres.ts) to stream results. - Streaming: The bridge sends
query.startedand multiplequery.batchnotifications viastdout. - Frontend:
bridgeClientlistens for these events and dispatches them to the UI.
- UI: User selects a pending migration and clicks "Apply".
- Frontend:
migrationService.applycallsbridgeRequest('migration.apply', { connectionId, filename }). - Bridge:
MigrationHandlers.applycallsDatabaseServiceto get the connection and then callsapplyMigrationin the engine connector (e.g.,postgres.ts). - Connector: Reads the
.sqlfile, executes the+upsection in a transaction, and records the version inschema_migrations.
- UI: User opens the "Monitoring" tab for a database.
- Frontend: Opens a WebSocket connection to the bridge via
MonitoringWebSocketServer. - Bridge:
MonitoringServicestarts a ticker that periodically queries the DB for metrics (health, active queries, throughput). - Streaming: The bridge pushes these snapshots over the WebSocket.
- UI: React components (e.g., in
src/features/monitoring/) subscribe to these events and update charts in real-time.
- Bridge Unit Tests: Located in
bridge/__tests__/. Focus on services and utils. - Bridge Integration Tests: Located in
bridge/__tests__/connectors/. Test actual DB connectivity.
npm test: Runs all bridge tests.npm run test:watch: Runs tests in watch mode.
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.