Documentation
¶
Overview ¶
Package plugin defines the unified interface for GoatKit plugins.
Plugins can be implemented as either:
- WASM modules (portable, sandboxed, via wazero)
- gRPC services (native, for I/O-heavy workloads, via go-plugin)
The host doesn't care which runtime backs a plugin - both implement this interface and are managed uniformly by the plugin manager.
Index ¶
- type CascadeSpec
- type CustomFieldFilter
- type CustomFieldSpec
- type ErrorCodeSpec
- type GKRegistration
- type GroupSpec
- type HostAPI
- type I18nSpec
- type JobSpec
- type MenuItemSpec
- type Permission
- type Plugin
- type PluginManifest
- type ResourcePolicy
- type ResourceRequest
- type RouteSpec
- type TemplateSpec
- type UIAuthSpec
- type UIBrandingSpec
- type UINavItem
- type UINavSpec
- type UIPWASpec
- type UIRouteSpec
- type UISpec
- type WidgetSpec
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CascadeSpec ¶ added in v0.8.0
type CascadeSpec struct {
EntityType string `json:"entity_type"` // ticket, contact, agent, organisation, etc.
OnSoftDelete string `json:"on_soft_delete,omitempty"` // plugin function for soft delete
OnHardDelete string `json:"on_hard_delete,omitempty"` // plugin function for hard delete
}
CascadeSpec declares a plugin's cascade handler for entity deletion.
type CustomFieldFilter ¶ added in v0.8.0
type CustomFieldFilter struct {
Field string `json:"field"` // field name (plugin prefix stripped)
Operator string `json:"operator"` // eq, neq, gt, lt, gte, lte, like, in, between, near
Value any `json:"value"` // comparison value
Value2 any `json:"value2,omitempty"` // second value for between (upper bound) and near (radius km)
}
CustomFieldFilter is a query filter used by CustomFieldsQuery.
type CustomFieldSpec ¶ added in v0.8.0
type CustomFieldSpec struct {
Name string `json:"name"` // machine name (auto-prefixed with plugin name)
Label string `json:"label"` // display label (can be i18n key)
EntityType string `json:"entity_type"` // "contact", "agent", "organisation", etc.
FieldType string `json:"field_type"` // "text", "select", "point", etc.
Section string `json:"section,omitempty"` // UI section grouping (default: "custom")
Order int `json:"order,omitempty"` // sort within section
Required bool `json:"required,omitempty"`
Description string `json:"description,omitempty"` // help text below input
Placeholder string `json:"placeholder,omitempty"`
Config json.RawMessage `json:"config,omitempty"` // type-specific config (options, regex, etc.)
}
CustomFieldSpec declares a custom field a plugin needs on a GoatKit entity. The platform creates, stores, validates, indexes, and renders these fields.
type ErrorCodeSpec ¶
type ErrorCodeSpec struct {
Code string `json:"code"` // error code without prefix, e.g. "export_failed"
Message string `json:"message"` // default English message
HTTPStatus int `json:"http_status"` // suggested HTTP status code
}
ErrorCodeSpec defines an API error code provided by the plugin. The plugin name is automatically prefixed to the code by the host (e.g., code "export_failed" in plugin "stats" becomes "stats:export_failed").
type GKRegistration ¶
type GKRegistration struct {
// Identity
Name string `json:"name"` // unique identifier, e.g. "stats"
Version string `json:"version"` // semver, e.g. "1.0.0"
Description string `json:"description"` // human-readable description
Author string `json:"author"` // author or organization
License string `json:"license"` // SPDX identifier, e.g. "Apache-2.0"
Homepage string `json:"homepage"` // URL to plugin docs/repo
// Capabilities - what the plugin exposes to the host
Routes []RouteSpec `json:"routes,omitempty"` // HTTP routes to register
MenuItems []MenuItemSpec `json:"menu_items,omitempty"` // navigation menu entries
Widgets []WidgetSpec `json:"widgets,omitempty"` // dashboard widgets
Jobs []JobSpec `json:"jobs,omitempty"` // scheduled/cron tasks
Templates []TemplateSpec `json:"templates,omitempty"` // template overrides/additions
I18n *I18nSpec `json:"i18n,omitempty"` // translations provided by plugin
ErrorCodes []ErrorCodeSpec `json:"error_codes,omitempty"` // API error codes provided by plugin
// Navigation control
HideMenuItems []string `json:"hide_menu_items,omitempty"` // IDs of default menu items to hide (dashboard, tickets, queues, phone_ticket, email_ticket, admin)
LandingPage string `json:"landing_page,omitempty"` // URL path to redirect to after login (e.g. "/fictus")
// Access control — groups the plugin needs, auto-created on load
Groups []GroupSpec `json:"groups,omitempty"` // groups for RBAC (use "group:<name>" in route middleware)
// Custom fields the plugin needs on GoatKit entities.
// Field names are auto-prefixed with the plugin name to prevent collisions.
CustomFields []CustomFieldSpec `json:"custom_fields,omitempty"`
// UIs the plugin provides. Each UI is an independent application
// with its own routes, branding, navigation, and auth.
UIs []UISpec `json:"uis,omitempty"`
// Cascade handlers for entity deletion.
// Called when platform entities are soft/hard deleted.
Cascades []CascadeSpec `json:"cascades,omitempty"`
// Requirements
MinHostVersion string `json:"min_host_version,omitempty"` // minimum GoatFlow version
Permissions []string `json:"permissions,omitempty"` // required host permissions (legacy, use ResourceRequest)
Resources *ResourceRequest `json:"resources,omitempty"` // requested resource limits
}
GKRegistration describes what a plugin provides to the host. This is returned by GKRegister() - the self-describing plugin protocol.
type GroupSpec ¶
type GroupSpec struct {
Name string `json:"name"` // group name, e.g. "fictus-users"
Description string `json:"description"` // human-readable description for admin UI
}
GroupSpec defines a group that a plugin requires for access control. Groups are auto-created in the GoatFlow groups table when the plugin loads. Routes can reference them via middleware: ["auth", "group:fictus-users"].
type HostAPI ¶
type HostAPI interface {
// Database
DBQuery(ctx context.Context, query string, args ...any) ([]map[string]any, error)
DBExec(ctx context.Context, query string, args ...any) (int64, error)
// Cache
CacheGet(ctx context.Context, key string) ([]byte, bool, error)
CacheSet(ctx context.Context, key string, value []byte, ttlSeconds int) error
CacheDelete(ctx context.Context, key string) error
// HTTP (outbound)
HTTPRequest(ctx context.Context, method, url string, headers map[string]string, body []byte) (int, []byte, error)
// Email
SendEmail(ctx context.Context, to, subject, body string, html bool) error
// Logging
Log(ctx context.Context, level, message string, fields map[string]any)
// Config
ConfigGet(ctx context.Context, key string) (string, error)
// i18n
Translate(ctx context.Context, key string, args ...any) string
// Plugin-to-plugin calls
// Allows one plugin to call functions in another plugin
CallPlugin(ctx context.Context, pluginName, fn string, args json.RawMessage) (json.RawMessage, error)
// SSE (Server-Sent Events)
// Publishes an event to all connected browser clients.
// eventType is the SSE event name (e.g. "device-table"); data is the payload (typically HTML).
PublishEvent(ctx context.Context, eventType string, data string) error
// Entity Deletion
// EntitySoftDelete soft-deletes an entity (recycle bin + PII anonymisation).
EntitySoftDelete(ctx context.Context, entityType string, entityID int64, reason string) error
// EntityRestore restores a soft-deleted entity from the recycle bin.
EntityRestore(ctx context.Context, entityType string, entityID int64) error
// EntityHardDelete permanently removes an entity and all linked data.
EntityHardDelete(ctx context.Context, entityType string, entityID int64, reason string) error
// RecycleBinList lists soft-deleted entities in the recycle bin.
RecycleBinList(ctx context.Context, entityType string) (json.RawMessage, error)
// Secure Config
// SecureConfigGet retrieves a decrypted secret value for this plugin.
SecureConfigGet(ctx context.Context, key string) (string, error)
// SecureConfigSet stores an encrypted secret value for this plugin.
SecureConfigSet(ctx context.Context, key string, value string) error
// Organisation
// OrgID returns the active organisation ID for the current request.
// Returns 0 if no organisation context (single-org mode).
OrgID(ctx context.Context) int64
// Custom Fields
// Get retrieves custom field values for an entity. Plugin prefix is auto-stripped.
// Pass nil for fields to get all fields; pass specific names to filter.
CustomFieldsGet(ctx context.Context, entityType string, objectID int64, fields []string) (map[string]any, error)
// Set stores custom field values for an entity. Plugin prefix is auto-stripped.
// Validates types and constraints before storing.
CustomFieldsSet(ctx context.Context, entityType string, objectID int64, values map[string]any) error
// Query finds entities by custom field values. Returns matching object IDs.
CustomFieldsQuery(ctx context.Context, entityType string, filters []CustomFieldFilter) ([]int64, error)
}
HostAPI is the interface plugins use to access host services. Passed to Plugin.Init() - plugins store this for later use.
type I18nSpec ¶
type I18nSpec struct {
// Namespace prefix for plugin translations (e.g., "stats" -> "stats.dashboard.title")
Namespace string `json:"namespace,omitempty"`
// Languages supported by this plugin
Languages []string `json:"languages,omitempty"`
// Inline translations (language -> key -> value)
// For small plugins, translations can be embedded in the manifest
Translations map[string]map[string]string `json:"translations,omitempty"`
}
I18nSpec defines internationalization resources provided by the plugin.
type JobSpec ¶
type JobSpec struct {
ID string `json:"id"` // unique identifier
Handler string `json:"handler"` // plugin function to call
Schedule string `json:"schedule"` // cron expression, e.g. "0 * * * *"
Description string `json:"description,omitempty"` // human-readable description
Enabled bool `json:"enabled"` // whether job runs by default
Timeout string `json:"timeout,omitempty"` // max execution time, e.g. "5m"
}
JobSpec defines a scheduled/cron task.
type MenuItemSpec ¶
type MenuItemSpec struct {
ID string `json:"id"` // unique identifier
Label string `json:"label"` // display text (can be i18n key)
Icon string `json:"icon,omitempty"` // icon name or SVG
Path string `json:"path"` // URL path when clicked
Location string `json:"location"` // where to insert: "admin", "agent", "customer"
Parent string `json:"parent,omitempty"` // parent menu ID for submenus
Order int `json:"order,omitempty"` // sort order within location
Children []MenuItemSpec `json:"children,omitempty"` // nested menu items
}
MenuItemSpec defines a navigation menu entry.
type Permission ¶
type Permission struct {
// Type is the permission category: "db", "cache", "http", "email", "config", "plugin_call"
Type string `json:"type" yaml:"type"`
// Access level: "read", "write", "readwrite" (for db/cache)
Access string `json:"access,omitempty" yaml:"access,omitempty"`
// Scope constrains the permission. Meaning depends on type:
// db: table allowlist, e.g. ["fictus_*", "ticket"]
// http: URL patterns, e.g. ["*.tenor.com", "api.giphy.com"]
// cache: key prefix (auto-namespaced if empty)
// plugin_call: plugin names allowed to call, e.g. ["stats"]
Scope []string `json:"scope,omitempty" yaml:"scope,omitempty"`
}
Permission declares a specific capability a plugin requests.
type Plugin ¶
type Plugin interface {
// GKRegister returns plugin metadata. Called once at load time.
// This is how plugins self-describe their capabilities per the GoatKit spec.
GKRegister() GKRegistration
// Init is called after loading, before the plugin serves requests.
// The HostAPI provides access to host services (db, cache, http, etc).
Init(ctx context.Context, host HostAPI) error
// Call invokes a plugin function by name with JSON-encoded arguments.
// Returns JSON-encoded response or error.
// This is the primary communication channel between host and plugin.
Call(ctx context.Context, fn string, args json.RawMessage) (json.RawMessage, error)
// Shutdown is called before unloading the plugin.
// Plugins should clean up resources and finish pending work.
Shutdown(ctx context.Context) error
}
Plugin is the unified interface for WASM and gRPC plugins. Both runtime implementations must satisfy this interface.
type PluginManifest ¶
type PluginManifest struct {
Name string `yaml:"name" json:"name"`
Version string `yaml:"version" json:"version"`
Runtime string `yaml:"runtime" json:"runtime"` // "wasm", "grpc", "template", or "theme"
Binary string `yaml:"binary" json:"binary,omitempty"` // For grpc runtime: relative path to executable
WASMFile string `yaml:"wasm,omitempty" json:"wasm,omitempty"` // For wasm runtime: defaults to name.wasm
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Author string `yaml:"author,omitempty" json:"author,omitempty"`
License string `yaml:"license,omitempty" json:"license,omitempty"`
Homepage string `yaml:"homepage,omitempty" json:"homepage,omitempty"`
Resources *ResourceRequest `yaml:"resources,omitempty" json:"resources,omitempty"`
Dependencies []string `yaml:"dependencies,omitempty" json:"dependencies,omitempty"` // Plugin names this depends on
PluginType string `yaml:"type,omitempty" json:"type,omitempty"` // "plugin" (default), "theme"
}
PluginManifest represents a plugin.yaml manifest file. This is the universal plugin descriptor used by both the loader and packaging systems.
type ResourcePolicy ¶
type ResourcePolicy struct {
// Plugin name this policy applies to
PluginName string `json:"plugin_name"`
// Status: "pending_review", "approved", "restricted", "blocked"
Status string `json:"status"`
// Process limits (overrides plugin request)
MemoryMB int `json:"memory_mb,omitempty"`
CallTimeout string `json:"call_timeout,omitempty"`
InitTimeout string `json:"init_timeout,omitempty"`
ShutdownTimeout string `json:"shutdown_timeout,omitempty"`
// Granted permissions (may be subset of requested)
Permissions []Permission `json:"permissions,omitempty"`
// Rate limits
MaxCallsPerSecond int `json:"max_calls_per_second,omitempty"` // 0 = unlimited
MaxDBQueriesPerMin int `json:"max_db_queries_per_min,omitempty"`
MaxHTTPReqPerMin int `json:"max_http_req_per_min,omitempty"`
}
ResourcePolicy is the platform-enforced limits for a plugin. Set by admin, stored in sysconfig. Overrides ResourceRequest.
func DefaultResourcePolicy ¶
func DefaultResourcePolicy(pluginName string) ResourcePolicy
DefaultResourcePolicy returns a restrictive default policy for new plugins. Plugins start with minimal access until an admin reviews them.
type ResourceRequest ¶
type ResourceRequest struct {
// Process limits (gRPC plugins only, ignored for WASM)
MemoryMB int `json:"memory_mb,omitempty" yaml:"memory_mb,omitempty"` // Requested RSS limit in MB
CallTimeout string `json:"call_timeout,omitempty" yaml:"call_timeout,omitempty"` // Per-call deadline, e.g. "30s"
InitTimeout string `json:"init_timeout,omitempty" yaml:"init_timeout,omitempty"` // Init must complete within, e.g. "10s"
ShutdownTimeout string `json:"shutdown_timeout,omitempty" yaml:"shutdown_timeout,omitempty"` // Shutdown grace period, e.g. "5s"
// HostAPI permissions requested
Permissions []Permission `json:"permissions,omitempty" yaml:"permissions,omitempty"`
}
ResourceRequest describes what a plugin asks for from the platform. These are requests/defaults — the platform may grant less via ResourcePolicy.
type RouteSpec ¶
type RouteSpec struct {
Method string `json:"method"` // GET, POST, PUT, DELETE, etc.
Path string `json:"path"` // URL path, e.g. "/admin/stats"
Handler string `json:"handler"` // plugin function to call
Middleware []string `json:"middleware,omitempty"` // middleware chain, e.g. ["auth", "admin"]
Description string `json:"description,omitempty"` // for documentation
}
RouteSpec defines an HTTP route the plugin wants to handle.
type TemplateSpec ¶
type TemplateSpec struct {
Name string `json:"name"` // template name, e.g. "stats/dashboard.html"
Path string `json:"path"` // path within plugin package
Override bool `json:"override,omitempty"` // if true, overrides host template of same name
}
TemplateSpec defines a template the plugin provides.
type UIAuthSpec ¶ added in v0.8.0
type UIAuthSpec struct {
Method string `json:"method,omitempty"` // session, pin, token, none
Groups []string `json:"groups,omitempty"` // required groups
}
UIAuthSpec holds per-UI auth configuration.
type UIBrandingSpec ¶ added in v0.8.0
type UIBrandingSpec struct {
AppName string `json:"app_name,omitempty"`
Logo string `json:"logo,omitempty"` // URL or base64 data URI
Favicon string `json:"favicon,omitempty"` // URL or base64 data URI
Color string `json:"color,omitempty"` // primary brand colour (hex)
}
UIBrandingSpec holds per-UI branding overrides.
type UINavItem ¶ added in v0.8.0
type UINavItem struct {
}
UINavItem is a navigation entry in a plugin UI.
type UINavSpec ¶ added in v0.8.0
type UINavSpec struct {
}
UINavSpec defines navigation for a plugin UI shell.
type UIPWASpec ¶ added in v0.8.0
type UIPWASpec struct {
Enabled bool `json:"enabled"`
StartURL string `json:"start_url,omitempty"` // defaults to UI root
Display string `json:"display,omitempty"` // standalone, fullscreen, minimal-ui
ThemeColor string `json:"theme_color,omitempty"`
CacheRoutes []string `json:"cache_routes,omitempty"` // routes to pre-cache for offline
}
UIPWASpec holds PWA manifest configuration for a plugin UI.
type UIRouteSpec ¶ added in v0.8.0
type UIRouteSpec struct {
Path string `json:"path"` // relative path, e.g. "/", "/items/:id"
Method string `json:"method,omitempty"` // GET, POST, etc. (default: GET)
Handler string `json:"handler"` // plugin function name
}
UIRouteSpec defines a route within a plugin UI.
type UISpec ¶ added in v0.8.0
type UISpec struct {
ID string `json:"id"` // unique within plugin (auto-prefixed)
Name string `json:"name"` // display name
Description string `json:"description,omitempty"`
Type string `json:"type"` // admin_page, agent_app, customer_app, public_page, kiosk
Icon string `json:"icon,omitempty"` // FontAwesome class or SVG
Shell string `json:"shell,omitempty"` // none, minimal, standard (defaults per type)
Routes []UIRouteSpec `json:"routes"` // routes relative to /ui/{plugin}_{id}/
Branding *UIBrandingSpec `json:"branding,omitempty"` // per-UI branding overrides
Auth *UIAuthSpec `json:"auth,omitempty"` // auth configuration
PWA *UIPWASpec `json:"pwa,omitempty"` // PWA manifest configuration
DataScope string `json:"data_scope,omitempty"` // self, org, all (for customer UIs)
RateLimit int `json:"rate_limit,omitempty"` // requests/min for public UIs (0 = default)
}
UISpec declares an independent UI that a plugin provides. Each UI gets its own routes, shell, branding, auth, and optional PWA support.
type WidgetSpec ¶
type WidgetSpec struct {
ID string `json:"id"` // unique identifier
Title string `json:"title"` // display title (can be i18n key)
Description string `json:"description,omitempty"` // widget description
Handler string `json:"handler"` // plugin function that returns widget HTML
Location string `json:"location"` // dashboard location: "agent_home", "admin_home"
Size string `json:"size,omitempty"` // "small", "medium", "large", "full"
Order int `json:"order,omitempty"` // sort order within location
Refreshable bool `json:"refreshable,omitempty"` // can be refreshed via AJAX
RefreshSec int `json:"refresh_sec,omitempty"` // auto-refresh interval
}
WidgetSpec defines a dashboard widget.