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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,5 @@ jobs:
run: cd frontend && npm install
- name: Install Playwright Browsers
run: cd frontend && npx playwright install --with-deps
- name: Start Docker Databases
run: cd frontend && docker compose up -d --wait
- name: Run E2E Tests
run: cd frontend && xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" npm run test:e2e
run: cd frontend && npm run test:e2e
41 changes: 23 additions & 18 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ jobs:
build:
name: Build and Release
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest]
include:
- os: macos-latest
- os: windows-latest
runs-on: ${{ matrix.os }}
permissions:
contents: write
Expand All @@ -28,25 +31,27 @@ jobs:
uses: actions/setup-go@v5
with:
go-version: '1.24'
cache-dependency-path: backend/go.sum

- name: Install dependencies
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable

- name: Rust cache
uses: swatinem/rust-cache@v2
with:
workspaces: frontend/tauri -> target

- name: Install frontend dependencies
run: cd frontend && npm install

- name: Build Go Engine
run: |
mkdir -p frontend/engine
cd backend
if [ "$RUNNER_OS" == "Windows" ]; then
go build -o ../frontend/engine/vstable-engine.exe main.go
else
go build -o ../frontend/engine/vstable-engine main.go
fi
shell: bash

- name: Build and Publish
- name: Build and Release
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cd frontend
npm run build
npx electron-builder --publish always
with:
tagName: v__VERSION__ # tauri-action will replace this with package.json version if needed, or use the tag
releaseName: "vstable v__VERSION__"
releaseBody: "See the assets below to download."
releaseDraft: true
prerelease: false
projectPath: frontend
19 changes: 9 additions & 10 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,27 @@ yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
backend/log.txt
tmp.prompt
.engine.pid

# --- Environment ---
.env*
!.env.example

# --- Frontend (Node.js/Electron) ---
# --- Frontend (Node.js/Tauri) ---
node_modules/
frontend/node_modules/
frontend/out/
frontend/dist/
frontend/release/
frontend/.parcel-cache/
frontend/.eslintcache
frontend/.vite/
frontend/package-lock.json
frontend/out/
frontend/tauri/target/
frontend/tauri/bin/vstable-*
frontend/tauri/gen/
frontend/test-results/
frontend/playwright-report/
frontend/blob-report/
frontend/playwright/.cache/
frontend/*.tsbuildinfo

# --- Backend (Go) ---
backend/engine
backend/vstable
backend/vstable-engine
backend/bin/
backend/vendor/
Expand All @@ -52,3 +50,4 @@ coverage/
docker-data/
*.db
*.sqlite
dist/
38 changes: 19 additions & 19 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

## Quick commands

- `cd frontend && npm run dev` (拉起双端开发环境:Electron + Go Engine)
- `cd frontend && npm run dev` (拉起双端开发环境:Tauri + Go Engine)
- `cd frontend && npm run dev-frontend` (仅启动前端 Vite,不启动 Tauri/Go,适合纯 UI 调试)
- `cd frontend && npm run build` (编译前端与后端二进制)
- `cd frontend && npm run test` (Vitest 单元测试)
- `cd frontend && npm run test:e2e` (Playwright 全链路测试,会先 build)
- `cd frontend && npm run check` (Biome 格式化与静态检查)
- `cd backend && go test -v ./...` (后端集成测试,需 Docker)
- `cd frontend && npm run docker:up` (启动测试所需的 PG/MySQL 容器)
- `cd backend && ./scripts/gen_proto.sh` (生成 gRPC 代码并同步协议文件到前端)
- `cd frontend && npm run docker:down` (停止并清理测试容器)
- `cd backend && go test -v ./...` (后端集成测试,需 Docker)
- `cd backend && ./scripts/gen_proto.sh` (生成 gRPC 代码)

## Project overview

Expand All @@ -18,7 +20,7 @@ vstable 是一款专为开发者设计的现代数据库管理工具,支持可
## Tech stack

- **Frontend**: React 19 (TypeScript), TailwindCSS 4.0, Monaco Editor
- **Desktop Runtime**: Electron 40, electron-vite
- **Desktop Runtime**: Tauri 2.0 (Rust), Vite
- **Backend Engine**: Go 1.24 (vstable-engine)
- **Communication**: gRPC, Protocol Buffers (Strict types)
- **Database Drivers**: `pgx/v5` (PostgreSQL), `go-sql-driver/mysql` (MySQL)
Expand All @@ -29,22 +31,21 @@ vstable 是一款专为开发者设计的现代数据库管理工具,支持可

该项目采用解耦的三层架构:
1. **Frontend (React)**: 基于 React 19、TailwindCSS 4.0 和 Monaco Editor 构建的现代用户界面。负责处理用户交互、SQL 编辑以及可视化的表结构设计。
2. **Desktop Runtime (Electron)**: 作为操作系统与 Web 内容之间的桥梁。主进程(Main process)负责管理 Go 引擎的生命周期、持久化存储、IPC 路由以及原生窗口管理
3. **Backend Engine (Go)**: 一个使用 Go 1.24 编写的高性能守护进程。它在本地运行并向 Electron 主进程暴露 gRPC API(定义于 `vstable.proto`)。它承担繁重的计算任务,包括数据库连接管理、AST 解析,以及基于状态对齐进行 Schema Diff 并生成精确的 DDL 语句。
2. **Desktop Runtime (Tauri)**: 作为操作系统与 Web 内容之间的桥梁。基于 Rust 的核心层负责管理 Go 引擎(Sidecar)的生命周期、处理由前端发起的高性能 IPC 请求,并通过原生的能力(Capabilities)系统提供持久化存储和窗口管理
3. **Backend Engine (Go)**: 一个使用 Go 1.24 编写的高性能守护进程。它在本地作为 Tauri Sidecar 运行并向 Rust 核心暴露 gRPC API(定义于 `vstable.proto`)。它承担繁重的计算任务,包括数据库连接管理、AST 解析,以及基于状态对齐进行 Schema Diff 并生成精确的 DDL 语句。

## Major modules and interfaces

- **Go Engine (`backend/`)**:
- `internal/ast`: 核心 Schema Diff 引擎。提供 AST 类型定义以及特定数据库方言(PostgreSQL/MySQL)的编译器,用于基于状态对齐生成精确的 DDL Diff。
- `internal/db`: 数据库连接管理器和驱动程序抽象。
- `main.go`: 启动 gRPC Server,处理来自 Electron 主进程的远程过程调用。
- `scripts/gen_proto.sh`: 构建脚本,用于从 `.proto` 文件生成 Go 代码,并同步协议定义到前端资源目录供运行时加载。
- **Electron Main (`frontend/src/main/`)**:
- `daemon.ts`: 管理 Go 后端引擎进程的生命周期(启动、日志记录和停止)。
- `grpcClient.ts`: 封装 gRPC 客户端,通过严格类型的 Protobuf 协议与后端引擎通信。
- `index.ts`: 处理 IPC 路由(如 `db:connect`, `db:query`,并通过 `grpcClient` 调用 Go 引擎)以及窗口管理。
- `store.ts`: 处理应用程序配置、加密凭据以及工作区状态(标签页、会话)的持久化。
- **React Renderer (`frontend/src/renderer/`)**:
- `main.go`: 启动 gRPC Server,处理来自 Tauri Rust 核心的远程过程调用。
- `scripts/gen_proto.sh`: 构建脚本,用于从 `.proto` 文件生成 Go 代码。
- **Tauri Core (`frontend/tauri/`)**:
- `src/lib.rs`: Tauri 应用的核心库。初始化 gRPC 客户端池以通过严格类型的 Protobuf 协议与后端引擎通信;处理前端的 IPC 路由(如 `db_connect`, `db_query`),以及原生窗口控制和日志捕获。
- `src/main.rs`: 桌面应用启动入口。
- `tauri.conf.json`: 应用配置,包括构建指令、窗口属性以及 Sidecar (Go 引擎)的绑定声明。
- **React Renderer (`frontend/src/`)**:
- `features/`: 包含核心功能模块:
- `connection`: 数据库连接表单和管理。
- `navigator`: 数据库和数据表树形视图。
Expand All @@ -58,11 +59,10 @@ vstable 是一款专为开发者设计的现代数据库管理工具,支持可
- `backend/`: Go 后端引擎源码。
- `internal/ast/`: AST 类型、Diff 逻辑以及数据库方言编译器。
- `internal/db/`: 数据库驱动实现。
- `frontend/`: Electron 应用与 React 前端。
- `frontend/`: Tauri 应用与 React 前端。
- `e2e/`: 用于全链路验证的 Playwright E2E 测试。
- `src/main/`: Electron 主进程 (Node.js)。
- `src/preload/`: 用于上下文隔离的 IPC 桥接脚本。
- `src/renderer/`: React Web 应用。
- `tauri/`: Tauri 胶水代码,将 frontend 和 backend 粘合在一起。
- `src/`: React Web 应用。
- `components/`: 可复用的通用 UI 组件。
- `features/`: 特定领域的业务逻辑与视图。
- `hooks/`, `stores/`: 全局状态管理 (Zustand) 和自定义 React Hooks。
Expand Down Expand Up @@ -115,4 +115,4 @@ Allowed types:
7. 建立标签并推送:
- `git tag v1.2.0`
- `git push --tags`
8. GitHub Actions 或相关 CI/CD 流程在检测到 tag 推送后,自动构建双端产物(Electron Mac/Windows/Linux 与 Go Engine 二进制)并执行发布。
8. GitHub Actions 或相关 CI/CD 流程在检测到 tag 推送后,自动构建双端产物(Tauri Mac/Windows/Linux 与 Go Engine 二进制)并执行发布。
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<p align="center">
<img src="frontend/resources/icons/128.png" width="96" alt="VSTable Logo" style="border-radius: 20%;" />
<img src="frontend/tauri/icons/128x128.png" width="96" alt="VSTable Logo" style="border-radius: 20%;" />
</p>

<h1 align="center">VSTable</h1>
Expand Down
2 changes: 1 addition & 1 deletion backend/api/vstable.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import "google/protobuf/wrappers.proto";

service EngineService {
rpc Ping(PingRequest) returns (PingResponse);
rpc Connect(ConnectRequest) returns (ConnectResponse);
rpc DbConnect(ConnectRequest) returns (ConnectResponse);
rpc Disconnect(DisconnectRequest) returns (DisconnectResponse);
rpc Query(QueryRequest) returns (QueryResponse);
rpc GenerateAlterTable(DiffRequest) returns (GenerateSQLResponse);
Expand Down
5 changes: 3 additions & 2 deletions backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ go 1.24.0

require (
github.com/go-sql-driver/mysql v1.9.3
github.com/golang/protobuf v1.5.4
github.com/jackc/pgx/v5 v5.8.0
google.golang.org/grpc v1.79.2
google.golang.org/protobuf v1.36.11
)

require (
Expand All @@ -17,6 +20,4 @@ require (
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.32.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/grpc v1.79.2 // indirect
google.golang.org/protobuf v1.36.11 // indirect
)
30 changes: 26 additions & 4 deletions backend/go.sum
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
Expand All @@ -20,18 +32,28 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
Expand Down
10 changes: 5 additions & 5 deletions backend/internal/pb/vstable.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading