Database & service plugins for Shield CLI
Browser-based Web UI for PostgreSQL, Redis, SQL Server and more — managed through one CLI command.
This monorepo contains all official Shield CLI plugins. Each plugin is an independent Go module that compiles into a single binary (~5–9 MB), providing a browser-based Web UI for managing database or service connections.
Plugins communicate with Shield CLI via a simple stdin/stdout JSON protocol — no shared libraries, no complex IPC.
User runs: shield postgres 10.0.0.20 --db-user admin --db-pass ****
┌──────────────┐ stdin (JSON) ┌────────────────────┐ HTTP ┌──────────────┐
│ Shield CLI │ ──────────────→ │ shield-plugin-xxx │ ←──────→ │ Browser UI │
│ │ ←────────────── │ (standalone bin) │ │ (embedded) │
└──────────────┘ stdout (JSON) └────────────────────┘ └──────────────┘
│ │
│ WebSocket Tunnel │
└────────────────────────────────────┘
Public HTTPS URL generated
- SQL Editor — Multi-tab SQL editor with syntax highlighting, result sorting, CSV export
- Schema Explorer — Sidebar tree: Schema → Table → Columns / Indexes
- Table Management — Create, rename, drop tables; add, edit, delete columns and indexes
- ER Diagram — Interactive entity-relationship diagram:
- 5 layout modes — Grid, Horizontal (LR), Vertical (TB), Radial, FK-aligned (default, minimizes line crossings)
- Focus mode — Double-click a table to isolate its N-degree neighbors with FK-aligned relayout
- Display modes — Compact (default, max 8 columns) and Minimal (header only), per-table expandable
- Hover highlight — Hovering a table dims unrelated relation lines
- Table search —
Cmd/Ctrl+Ffuzzy search with keyboard navigation and viewport animation - Drag-and-drop FK creation between tables
- Right-click context menus for table/column operations
- Responsive layout adapts to canvas size, auto-fits on window resize
- Export to SVG
- Real-time Collaboration — Multiple users can view and edit the same ER diagram simultaneously via WebSocket:
- Live cursor tracking with colored name labels
- Real-time table drag synchronization
- Schema change notifications (FK/table/column CRUD auto-refreshes for all users)
- Online presence indicator with avatar bar
- Auto-reconnect on connection loss
- Read-Only Mode — Frontend + backend enforced read-only access
- Docker Support — Standalone ~9 MB image, no runtime dependencies
| Plugin | Service | Protocols | Default Port | Docker Image | Status |
|---|---|---|---|---|---|
| shield-plugin-postgres | PostgreSQL | postgres pg postgresql |
5432 | fengyily/shield-postgres |
Development |
| shield-plugin-redis | Redis | redis |
6379 | — | Planned |
| shield-plugin-sqlserver | SQL Server | sqlserver mssql |
1433 | — | Planned |
The MySQL plugin is built into the main Shield CLI repo.
# From GitHub release (auto-detected platform)
shield plugin add postgres
# From local binary
shield plugin add postgres --from ./shield-plugin-postgres/shield-plugin-postgres# CLI mode — one command, browser opens
shield postgres 10.0.0.20 --db-user admin --db-pass mypass --database mydb
# Or via Web UI
shield start
# → http://localhost:8181, add PostgreSQL app, click Connectshield plugin list # List installed plugins
shield plugin upgrade postgres # Upgrade to latest release
shield plugin remove postgres # UninstallEach plugin also ships as a lightweight Docker image (~9 MB), providing a standalone Web UI for database management — similar to phpMyAdmin / pgAdmin, but much smaller.
docker run -d --name shield-postgres \
-e DB_HOST=10.0.0.20 \
-e DB_PORT=5432 \
-e DB_USER=postgres \
-e DB_PASS=mypass \
-e DB_NAME=mydb \
-p 8080:8080 \
fengyily/shield-postgresOpen http://localhost:8080 to manage your PostgreSQL database.
Docker 容器默认无法直接访问宿主机网络,根据场景选择合适的方式:
连接宿主机上的数据库(Linux) — 使用 host 网络模式:
docker run -d --network host \
-e DB_HOST=10.0.0.20 \
-e DB_USER=postgres \
-e DB_PASS=mypass \
fengyily/shield-postgres
--network host模式下无需-p端口映射,Web UI 直接监听宿主机 8080 端口。
连接宿主机上的数据库(macOS / Windows Docker Desktop) — 使用 host.docker.internal:
docker run -d \
-e DB_HOST=host.docker.internal \
-e DB_USER=postgres \
-e DB_PASS=mypass \
-p 8080:8080 \
fengyily/shield-postgres连接其他 Docker 容器中的数据库 — 使用同一 Docker 网络:
docker run -d --network my-net \
-e DB_HOST=my-postgres-container \
-e DB_USER=postgres \
-e DB_PASS=mypass \
-p 8080:8080 \
fengyily/shield-postgres| Variable | Default | Description |
|---|---|---|
DB_HOST |
127.0.0.1 |
Database host |
DB_PORT |
5432 / 3306 |
Database port |
DB_USER |
postgres / root |
Database user |
DB_PASS |
— | Database password |
DB_NAME |
postgres / — |
Default database |
DB_READONLY |
false |
Enable read-only mode (true or 1) |
WEB_PORT |
8080 |
Web UI listen port |
services:
postgres-web:
image: fengyily/shield-postgres
ports:
- "8080:8080"
environment:
DB_HOST: postgres
DB_USER: postgres
DB_PASS: mypass
DB_NAME: mydb
depends_on:
- postgres
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: mypass
POSTGRES_DB: mydbEach plugin is an independent Go module:
cd shield-plugin-postgres
go build -ldflags="-s -w" -o shield-plugin-postgres .Build all plugins:
for d in shield-plugin-*/; do
echo "Building $d..."
(cd "$d" && go build -ldflags="-s -w" -o "${d%/}" .)
donecd shield-plugin-postgres
# Linux amd64
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o shield-plugin-postgres .
# Windows
GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o shield-plugin-postgres.exe .
# Linux arm64
GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -o shield-plugin-postgres .You can test a plugin without Shield CLI by piping JSON to stdin:
cd shield-plugin-postgres
# Interactive mode (keeps running)
(echo '{"action":"start","config":{"host":"127.0.0.1","port":5432,"user":"appshield","pass":"appshield123","database":"casdoor","readonly":false}}'; cat) | ./shield-plugin-postgres
# Plugin responds:
# {"status":"ready","web_port":54321,"name":"PostgreSQL Web Client","version":"0.1.0"}
#
# Open http://127.0.0.1:54321 in your browserPlugins are standalone binaries that communicate with Shield CLI via single-line JSON on stdin/stdout. The protocol has only two messages:
{
"action": "start",
"config": {
"host": "127.0.0.1",
"port": 5432,
"user": "postgres",
"pass": "secret",
"database": "mydb",
"readonly": false
}
}Success:
{
"status": "ready",
"web_port": 54321,
"name": "PostgreSQL Web Client",
"version": "0.1.0"
}Error:
{
"status": "error",
"message": "cannot connect to PostgreSQL at 127.0.0.1:5432: connection refused"
}{"action": "stop"}| Rule | Detail |
|---|---|
| Encoding | Single-line JSON, one message per line (json.Encoder / json.Decoder) |
| Startup timeout | 15 seconds — plugin must respond within this window |
| Stop timeout | 5 seconds — graceful shutdown, then force kill |
| Web server | Plugin listens on 127.0.0.1:0 (random port), reports via web_port |
| Logging | stderr is forwarded to Shield CLI's log output |
| Lifecycle | Plugin runs until stdin closes, stop is received, or SIGINT/SIGTERM |
| Field | Type | Description |
|---|---|---|
host |
string | Target service IP/hostname |
port |
int | Target service port |
user |
string | Database/service username |
pass |
string | Database/service password |
database |
string | Database/schema name (optional) |
readonly |
bool | Enable read-only mode (block write SQL) |
-
Create directory:
mkdir shield-plugin-xxx && cd shield-plugin-xxx -
Init Go module:
go mod init shield-plugin-xxx -
Implement the protocol — read JSON from stdin, start HTTP server, respond with
web_port:
package main
import (
"database/sql"
"embed"
"encoding/json"
"net"
"net/http"
"os"
// import your driver
)
//go:embed static/*
var staticFS embed.FS
func main() {
decoder := json.NewDecoder(os.Stdin)
for {
var req StartRequest
if err := decoder.Decode(&req); err != nil {
return
}
switch req.Action {
case "start":
handleStart(req.Config)
case "stop":
os.Exit(0)
}
}
}
func handleStart(cfg PluginConfig) {
// 1. Connect to the target service
db, err := sql.Open("yourdriver", buildDSN(cfg))
// ...
// 2. Find available port
listener, _ := net.Listen("tcp", "127.0.0.1:0")
webPort := listener.Addr().(*net.TCPAddr).Port
// 3. Setup HTTP handlers + static files
mux := http.NewServeMux()
mux.HandleFunc("/api/query", queryHandler(db))
// ...
// 4. Respond ready
json.NewEncoder(os.Stdout).Encode(StartResponse{
Status: "ready",
WebPort: webPort,
Name: "Your Service Web Client",
Version: "0.1.0",
})
// 5. Serve and wait
go http.Serve(listener, mux)
// wait for signal...
}-
Add Web UI: Create
static/index.htmlwith your management interface. It will be embedded via//go:embed static/*. -
Register in Shield CLI: Add an entry to
KnownPluginsin plugin/install.go.
Plugins are distributed as platform-specific binaries via GitHub Releases.
shield-plugin-{name}_{os}_{arch}.tar.gz # Linux / macOS
shield-plugin-{name}_{os}_{arch}.zip # Windows
Examples:
shield-plugin-postgres_linux_amd64.tar.gz
shield-plugin-postgres_darwin_arm64.tar.gz
shield-plugin-postgres_windows_amd64.zip
Shield CLI's shield plugin add command fetches the latest release from the plugin's GitHub repo, selects the correct platform asset, and extracts it to ~/.shield-cli/plugins/.
~/.shield-cli/plugins/
├── registry.json # Installed plugin metadata
├── shield-plugin-mysql # Binary
├── shield-plugin-postgres # Binary
└── ...
shield-plugins/
├── README.md
├── .gitignore
├── shield-plugin-postgres/ ← PostgreSQL Web Client
│ ├── go.mod
│ ├── go.sum
│ ├── main.go Plugin protocol + HTTP server
│ ├── handler.go API endpoints (schemas, tables, query...)
│ ├── collab.go WebSocket hub for ER diagram collaboration
│ ├── static/
│ │ ├── index.html Embedded Web UI
│ │ └── er.js ER diagram with real-time collaboration
│ └── README.md
├── shield-plugin-redis/ ← (planned)
└── shield-plugin-sqlserver/ ← (planned)
Each plugin directory is a self-contained Go module — no shared dependencies between plugins.
Apache 2.0