ConnectionService owns the complete lifecycle of database connections. It stores metadata in SQLite, delegates credential storage to CredManager, and emits Wails events for reactive frontend updates.
Location: services/connection.go
API
The ConnectionService exposes these methods via Wails bindings:| Method | Signature | Description |
|---|---|---|
ListConnections | (ctx) → ([]Connection, error) | All connections, newest first |
CreateConnection | (ctx, name, driverType, credential) → (Connection, error) | Store secret via CredManager; persist metadata; emit connection:created |
GetConnection | (ctx, id) → (Connection, error) | Fetch single connection by UUID |
GetCredential | (ctx, id) → (string, error) | Raw credential JSON for building plugin requests |
DeleteConnection | (ctx, id) → error | Remove metadata + credential; emit connection:deleted |
All mutations emit Wails events after successful database writes, enabling reactive frontend state updates without polling.
Connection Structure
Connections are represented with this structure:Connection Lifecycle
Create Flow
Step-by-step:- Frontend calls
CreateConnection(name, driver, credentialJSON) - ConnectionService generates a UUID v4
- Derives
credential_key = "connection:<uuid>" - Calls
CredManager.Store(credential_key, credentialJSON)- Tries OS keyring first
- Falls back to SQLite file
- Last resort: in-memory storage
- Inserts metadata +
credential_keyintodata/connections.db - Emits
connection:createdevent with the Connection object - Frontend receives event and updates list reactively (no re-fetch needed)
Credentials are stored before metadata. If credential storage fails, the connection is not created.
Delete Flow
Step-by-step:- Frontend calls
DeleteConnection(id) - ConnectionService queries
credential_keyfor the connection - Calls
CredManager.Delete(credential_key)to remove from all storage tiers - Deletes metadata row from
data/connections.db - Emits
connection:deletedevent with the connection ID - Frontend receives event and removes entry from state
Credential Retrieval (for plugin execution)
Step-by-step:- Frontend calls
GetCredential(id)when preparing a plugin request - ConnectionService queries
credential_keyfrom metadata - Calls
CredManager.Get(credential_key)to retrieve the secret - Returns raw credential JSON string
- Frontend passes this JSON as the
connectionparameter to plugin commands
GetCredential is intentionally a separate call so the frontend can defer credential fetch until plugin execution time. Credentials are never cached in the UI.Event-Driven Updates
ConnectionService emits Wails events for all mutations:connection:created
Emitted after successful connection creation:connection:deleted
Emitted after successful connection deletion:Storage Details
Metadata Storage
Connection metadata is stored indata/connections.db:
- Engine: SQLite
- Pool size: Max 1 connection
- Connection lifetime: 5 minutes
- Schema: Auto-created on startup
Credential Storage
Credentials are never stored inconnections.db. They are managed by CredManager using a 3-tier fallback system:
- OS Keyring (primary)
- SQLite file (
data/credentials.db) (fallback) - In-memory map (last resort)
Implementation Notes
Credential Key Format
Credential keys use the format"connection:<uuid>" where the UUID matches the connection ID. This provides:
- Namespace isolation — Won’t conflict with other keyring entries
- Deterministic lookup — Can reconstruct key from connection ID
- Audit trail — Key format is self-documenting
Concurrent Access
ConnectionService is safe for concurrent access:- SQLite connections use
database/sqlwhich is goroutine-safe - Pool size of 1 serializes writes naturally
- Reads can happen concurrently via the connection pool
Error Handling
Creation Errors
If credential storage fails:- Connection is not created
- No metadata row inserted
- No event emitted
- Error returned to frontend
- Credential remains in CredManager (orphaned)
- Error returned to frontend
- Manual cleanup may be needed
Orphaned credentials are rare and harmless. They consume minimal space and can be manually deleted from the keyring if needed.
Deletion Errors
Credential deletion is best-effort:- Keyring deletion errors are logged but not fatal
- Metadata is always deleted
- Event is always emitted
Testing Connections
Connection testing is handled byPluginManager.TestConnection, not ConnectionService:
- Frontend collects connection parameters from the form
- Calls
PluginManager.TestConnection(driver, params)directly - Plugin validates and returns
{ok, message} - Frontend shows inline indicator
- No persistence until user clicks Save
Best Practices
Frontend Integration
Error Display
Show user-friendly errors:"credential storage failed"→ “Unable to securely store credentials. Try restarting.”"connection not found"→ “This connection no longer exists.”"credential not found"→ “Credentials not available. You may need to recreate this connection.”
Connection Naming
Encourage descriptive names:- Good: “Production MySQL”, “Dev PostgreSQL”, “Analytics Redis”
- Bad: “Connection 1”, “db”, “test”