plugin

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 6, 2026 License: MIT Imports: 26 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// Invoice events
	EventInvoiceCreated = "invoice.created"
	EventInvoiceSent    = "invoice.sent"
	EventInvoicePaid    = "invoice.paid"
	EventInvoiceVoided  = "invoice.voided"

	// Payment events
	EventPaymentReceived  = "payment.received"
	EventPaymentAllocated = "payment.allocated"

	// Contact events
	EventContactCreated = "contact.created"
	EventContactUpdated = "contact.updated"
	EventContactDeleted = "contact.deleted"

	// Journal entry events
	EventJournalEntryCreated = "journal_entry.created"
	EventJournalEntryPosted  = "journal_entry.posted"
	EventJournalEntryVoided  = "journal_entry.voided"

	// Expense events
	EventExpenseCreated   = "expense.created"
	EventExpenseSubmitted = "expense.submitted"
	EventExpenseApproved  = "expense.approved"
	EventExpenseRejected  = "expense.rejected"
	EventExpensePosted    = "expense.posted"

	// Recurring invoice events
	EventRecurringCreated   = "recurring.created"
	EventRecurringGenerated = "recurring.generated"
	EventRecurringStopped   = "recurring.stopped"

	// Banking events
	EventBankTransactionImported = "bank_transaction.imported"
	EventBankTransactionMatched  = "bank_transaction.matched"
	EventReconciliationCompleted = "reconciliation.completed"

	// Payroll events
	EventPayrollCalculated = "payroll.calculated"
	EventPayrollApproved   = "payroll.approved"
	EventEmployeeCreated   = "employee.created"

	// Tenant events
	EventTenantCreated = "tenant.created"
	EventTenantUpdated = "tenant.updated"

	// Email events
	EventEmailSent   = "email.sent"
	EventEmailFailed = "email.failed"

	// Webhook events
	EventWebhookTest = "webhook.test"
)

Event types for the hook system

View Source
const (
	BackendRuntimeHTTP = "http"
)
View Source
const BackendRuntimePackage = "package"
View Source
const (
	// DemoInstallFixtureRepositoryURL is an exact demo-mode fixture URL used by
	// local and CI E2E tests to exercise plugin installation without network IO.
	DemoInstallFixtureRepositoryURL = "https://github.com/HMB-research/open-accounting-demo-admin-plugin"
)

Variables

View Source
var (
	ErrPluginRuntimeUnsupported = errors.New("plugin backend runtime is unsupported")
	ErrPluginRouteNotFound      = errors.New("plugin route is not registered")
	ErrPluginNotEnabled         = errors.New("plugin is not enabled")
)

AllEventTypes returns all available event types

View Source
var AllPermissions = map[string]Permission{

	"contacts:read": {
		Name:        "contacts:read",
		Category:    CategoryDataAccess,
		Risk:        RiskLow,
		Description: "Read contact information",
	},
	"contacts:write": {
		Name:        "contacts:write",
		Category:    CategoryDataAccess,
		Risk:        RiskLow,
		Description: "Create and modify contacts",
	},
	"invoices:read": {
		Name:        "invoices:read",
		Category:    CategoryDataAccess,
		Risk:        RiskLow,
		Description: "Read invoices",
	},
	"invoices:write": {
		Name:        "invoices:write",
		Category:    CategoryDataAccess,
		Risk:        RiskMedium,
		Description: "Create and modify invoices",
	},
	"payments:read": {
		Name:        "payments:read",
		Category:    CategoryDataAccess,
		Risk:        RiskLow,
		Description: "Read payment records",
	},
	"payments:write": {
		Name:        "payments:write",
		Category:    CategoryDataAccess,
		Risk:        RiskMedium,
		Description: "Record payments",
	},
	"accounts:read": {
		Name:        "accounts:read",
		Category:    CategoryDataAccess,
		Risk:        RiskLow,
		Description: "Read chart of accounts",
	},
	"accounts:write": {
		Name:        "accounts:write",
		Category:    CategoryDataAccess,
		Risk:        RiskMedium,
		Description: "Modify chart of accounts",
	},
	"employees:read": {
		Name:        "employees:read",
		Category:    CategoryDataAccess,
		Risk:        RiskLow,
		Description: "Read employee information",
	},
	"employees:write": {
		Name:        "employees:write",
		Category:    CategoryDataAccess,
		Risk:        RiskMedium,
		Description: "Manage employees",
	},
	"payroll:read": {
		Name:        "payroll:read",
		Category:    CategoryDataAccess,
		Risk:        RiskMedium,
		Description: "Read payroll data",
	},
	"payroll:write": {
		Name:        "payroll:write",
		Category:    CategoryDataAccess,
		Risk:        RiskHigh,
		Description: "Manage payroll",
	},
	"banking:read": {
		Name:        "banking:read",
		Category:    CategoryDataAccess,
		Risk:        RiskMedium,
		Description: "Read bank account data",
	},
	"banking:write": {
		Name:        "banking:write",
		Category:    CategoryDataAccess,
		Risk:        RiskHigh,
		Description: "Manage bank transactions",
	},

	"email:send": {
		Name:        "email:send",
		Category:    CategorySystem,
		Risk:        RiskMedium,
		Description: "Send emails on behalf of tenant",
	},
	"storage:read": {
		Name:        "storage:read",
		Category:    CategorySystem,
		Risk:        RiskLow,
		Description: "Read stored files",
	},
	"storage:write": {
		Name:        "storage:write",
		Category:    CategorySystem,
		Risk:        RiskMedium,
		Description: "Upload and store files",
	},
	"pdf:generate": {
		Name:        "pdf:generate",
		Category:    CategorySystem,
		Risk:        RiskLow,
		Description: "Generate PDF documents",
	},
	"settings:read": {
		Name:        "settings:read",
		Category:    CategorySystem,
		Risk:        RiskLow,
		Description: "Read tenant settings",
	},
	"settings:write": {
		Name:        "settings:write",
		Category:    CategorySystem,
		Risk:        RiskMedium,
		Description: "Modify tenant settings",
	},

	"database:migrate": {
		Name:        "database:migrate",
		Category:    CategoryDatabase,
		Risk:        RiskHigh,
		Description: "Run database migrations in tenant schema",
	},
	"database:query": {
		Name:        "database:query",
		Category:    CategoryDatabase,
		Risk:        RiskHigh,
		Description: "Execute SQL queries in tenant schema",
	},

	"hooks:register": {
		Name:        "hooks:register",
		Category:    CategoryDangerous,
		Risk:        RiskCritical,
		Description: "Listen to system events",
	},
	"routes:register": {
		Name:        "routes:register",
		Category:    CategoryDangerous,
		Risk:        RiskCritical,
		Description: "Add custom API endpoints",
	},
	"admin:access": {
		Name:        "admin:access",
		Category:    CategoryDangerous,
		Risk:        RiskCritical,
		Description: "Access admin functions",
	},
}

AllPermissions is the registry of all available permissions

View Source
var ErrPluginRuntimeUnavailable = errors.New("plugin backend runtime is not available")

ErrPluginRuntimeUnavailable is returned when a plugin hook is invoked without a backend runtime capable of executing plugin code.

Functions

func HasDangerousPermissions

func HasDangerousPermissions(permissions []string) bool

HasDangerousPermissions checks if any permissions are in the dangerous category

func IsValidEventType

func IsValidEventType(eventType string) bool

IsValidEventType checks if an event type is valid

func ValidatePermission

func ValidatePermission(name string) bool

ValidatePermission checks if a permission name is valid

func ValidatePermissions

func ValidatePermissions(names []string) (invalid []string)

ValidatePermissions checks if all permission names are valid

Types

type BackendConfig

type BackendConfig struct {
	Package    string        `yaml:"package" json:"package"`
	Entry      string        `yaml:"entry" json:"entry"`
	Runtime    string        `yaml:"runtime,omitempty" json:"runtime,omitempty"`
	BaseURL    string        `yaml:"base_url,omitempty" json:"base_url,omitempty"`
	Executable string        `yaml:"executable,omitempty" json:"executable,omitempty"`
	Hooks      []HookConfig  `yaml:"hooks,omitempty" json:"hooks,omitempty"`
	Routes     []RouteConfig `yaml:"routes,omitempty" json:"routes,omitempty"`
}

BackendConfig represents the backend section of the manifest

type CreateRegistryRequest

type CreateRegistryRequest struct {
	Name        string `json:"name" validate:"required,min=1,max=255"`
	URL         string `json:"url" validate:"required,url"`
	Description string `json:"description,omitempty"`
}

CreateRegistryRequest represents a request to add a new registry

type DatabaseConfig

type DatabaseConfig struct {
	Migrations string `yaml:"migrations" json:"migrations"`
}

DatabaseConfig represents the database section of the manifest

type EnablePluginRequest

type EnablePluginRequest struct {
	GrantedPermissions []string `json:"granted_permissions"`
}

EnablePluginRequest represents a request to enable a plugin with permissions

type Event

type Event struct {
	Type     string          `json:"type"`
	TenantID uuid.UUID       `json:"tenant_id"`
	Data     json.RawMessage `json:"data"`
	Time     time.Time       `json:"time"`
}

Event represents an event emitted by the system

func NewContactEvent

func NewContactEvent(eventType string, tenantID uuid.UUID, contactData interface{}) Event

NewContactEvent creates a contact-related event

func NewGenericEvent

func NewGenericEvent(eventType string, tenantID uuid.UUID, data interface{}) Event

NewGenericEvent creates a generic event

func NewInvoiceEvent

func NewInvoiceEvent(eventType string, tenantID uuid.UUID, invoiceData interface{}) Event

NewInvoiceEvent creates an invoice-related event

func NewPaymentEvent

func NewPaymentEvent(eventType string, tenantID uuid.UUID, paymentData interface{}) Event

NewPaymentEvent creates a payment-related event

type FrontendConfig

type FrontendConfig struct {
	Components string           `yaml:"components" json:"components"`
	Navigation []NavigationItem `yaml:"navigation,omitempty" json:"navigation,omitempty"`
	Slots      []SlotConfig     `yaml:"slots,omitempty" json:"slots,omitempty"`
}

FrontendConfig represents the frontend section of the manifest

type GORMRepository

type GORMRepository struct {
	// contains filtered or unexported fields
}

GORMRepository implements Repository using GORM

func NewGORMRepository

func NewGORMRepository(db *gorm.DB) *GORMRepository

NewGORMRepository creates a new GORM plugin repository

func (*GORMRepository) CountEnabledTenantsForPlugin

func (r *GORMRepository) CountEnabledTenantsForPlugin(ctx context.Context, pluginID uuid.UUID) (int, error)

CountEnabledTenantsForPlugin counts tenants that have the plugin enabled

func (*GORMRepository) CreatePlugin

func (r *GORMRepository) CreatePlugin(ctx context.Context, p *Plugin) error

CreatePlugin creates a new plugin

func (*GORMRepository) CreateRegistry

func (r *GORMRepository) CreateRegistry(ctx context.Context, name, url, description string) (*Registry, error)

CreateRegistry creates a new registry

func (*GORMRepository) CreateTenantPlugin

func (r *GORMRepository) CreateTenantPlugin(ctx context.Context, tenantID, pluginID uuid.UUID, settings json.RawMessage) error

CreateTenantPlugin enables a plugin for a tenant

func (*GORMRepository) DeletePlugin

func (r *GORMRepository) DeletePlugin(ctx context.Context, id uuid.UUID) (int64, error)

DeletePlugin deletes a plugin

func (*GORMRepository) DeleteRegistry

func (r *GORMRepository) DeleteRegistry(ctx context.Context, id uuid.UUID) (int64, error)

DeleteRegistry deletes a non-official registry

func (*GORMRepository) DeleteTenantPlugin

func (r *GORMRepository) DeleteTenantPlugin(ctx context.Context, tenantID, pluginID uuid.UUID) error

DeleteTenantPlugin removes a plugin from a tenant

func (*GORMRepository) DisableAllTenantsForPlugin

func (r *GORMRepository) DisableAllTenantsForPlugin(ctx context.Context, pluginID uuid.UUID) error

DisableAllTenantsForPlugin disables the plugin for all tenants

func (*GORMRepository) DisableTenantPlugin

func (r *GORMRepository) DisableTenantPlugin(ctx context.Context, tenantID, pluginID uuid.UUID) (int64, error)

DisableTenantPlugin disables a plugin for a tenant

func (*GORMRepository) EnableTenantPlugin

func (r *GORMRepository) EnableTenantPlugin(ctx context.Context, tenantID, pluginID uuid.UUID, settings json.RawMessage) error

EnableTenantPlugin enables a plugin for a tenant (upsert)

func (*GORMRepository) GetPlugin

func (r *GORMRepository) GetPlugin(ctx context.Context, id uuid.UUID) (*Plugin, error)

GetPlugin returns a plugin by ID

func (*GORMRepository) GetPluginByName

func (r *GORMRepository) GetPluginByName(ctx context.Context, name string) (*Plugin, error)

GetPluginByName returns a plugin by name

func (*GORMRepository) GetRegistry

func (r *GORMRepository) GetRegistry(ctx context.Context, id uuid.UUID) (*Registry, error)

GetRegistry returns a registry by ID

func (*GORMRepository) GetTenantPlugin

func (r *GORMRepository) GetTenantPlugin(ctx context.Context, tenantID, pluginID uuid.UUID) (*TenantPlugin, error)

GetTenantPlugin returns a tenant plugin

func (*GORMRepository) GetTenantPluginSettings

func (r *GORMRepository) GetTenantPluginSettings(ctx context.Context, tenantID, pluginID uuid.UUID) (json.RawMessage, error)

GetTenantPluginSettings returns the settings for a tenant plugin

func (*GORMRepository) GetTenantPluginsWithAll

func (r *GORMRepository) GetTenantPluginsWithAll(ctx context.Context, tenantID uuid.UUID) ([]TenantPlugin, error)

GetTenantPluginsWithAll returns all plugins available to a tenant (enabled or not)

func (*GORMRepository) InsertPluginReturning

func (r *GORMRepository) InsertPluginReturning(ctx context.Context, manifest *Manifest, repoURL string, repoType RepositoryType, manifestJSON []byte) (*Plugin, error)

InsertPluginReturning inserts a plugin and returns the created record

func (*GORMRepository) IsPluginEnabledForTenant

func (r *GORMRepository) IsPluginEnabledForTenant(ctx context.Context, tenantID, pluginID uuid.UUID) (bool, error)

IsPluginEnabledForTenant checks if a plugin is enabled for a tenant

func (*GORMRepository) ListEnabledPlugins

func (r *GORMRepository) ListEnabledPlugins(ctx context.Context) ([]Plugin, error)

ListEnabledPlugins returns all enabled plugins

func (*GORMRepository) ListPlugins

func (r *GORMRepository) ListPlugins(ctx context.Context) ([]Plugin, error)

ListPlugins returns all plugins

func (*GORMRepository) ListRegistries

func (r *GORMRepository) ListRegistries(ctx context.Context) ([]Registry, error)

ListRegistries returns all plugin registries

func (*GORMRepository) ListTenantPlugins

func (r *GORMRepository) ListTenantPlugins(ctx context.Context, tenantID uuid.UUID) ([]TenantPlugin, error)

ListTenantPlugins returns all plugins enabled for a tenant

func (*GORMRepository) UpdatePlugin

func (r *GORMRepository) UpdatePlugin(ctx context.Context, p *Plugin) error

UpdatePlugin updates a plugin

func (*GORMRepository) UpdatePluginState

func (r *GORMRepository) UpdatePluginState(ctx context.Context, pluginID uuid.UUID, state PluginState, permissions []string) error

UpdatePluginState updates a plugin's state and permissions

func (*GORMRepository) UpdateRegistryLastSynced

func (r *GORMRepository) UpdateRegistryLastSynced(ctx context.Context, id uuid.UUID) error

UpdateRegistryLastSynced updates the last synced timestamp

func (*GORMRepository) UpdateTenantPluginSettings

func (r *GORMRepository) UpdateTenantPluginSettings(ctx context.Context, tenantID, pluginID uuid.UUID, settings json.RawMessage) error

UpdateTenantPluginSettings updates tenant plugin settings

type HookConfig

type HookConfig struct {
	Event   string `yaml:"event" json:"event"`
	Handler string `yaml:"handler" json:"handler"`
}

HookConfig represents an event hook subscription

type HookHandler

type HookHandler func(ctx context.Context, event Event) error

HookHandler is a function that handles an event

type HookRegistry

type HookRegistry struct {
	// contains filtered or unexported fields
}

HookRegistry manages event subscriptions

func NewHookRegistry

func NewHookRegistry() *HookRegistry

NewHookRegistry creates a new hook registry

func (*HookRegistry) Emit

func (r *HookRegistry) Emit(ctx context.Context, event Event) error

Emit fires an event to all registered handlers

func (*HookRegistry) EmitAsync

func (r *HookRegistry) EmitAsync(event Event)

EmitAsync fires an event asynchronously (fire-and-forget)

func (*HookRegistry) GetEventTypes

func (r *HookRegistry) GetEventTypes() []string

GetEventTypes returns all registered event types

func (*HookRegistry) GetHandlerCount

func (r *HookRegistry) GetHandlerCount(eventType string) int

GetHandlerCount returns the number of handlers for an event type

func (*HookRegistry) HasHandlers

func (r *HookRegistry) HasHandlers(eventType string) bool

HasHandlers checks if there are any handlers for an event type

func (*HookRegistry) Register

func (r *HookRegistry) Register(eventType string, handler HookHandler)

Register registers a handler for an event type

type InstallPluginRequest

type InstallPluginRequest struct {
	RepositoryURL string `json:"repository_url" validate:"required,url"`
}

InstallPluginRequest represents a request to install a plugin

type LoadedPlugin

type LoadedPlugin struct {
	Plugin   *Plugin
	Manifest *Manifest
	Runtime  pluginBackendRuntime
}

LoadedPlugin represents a plugin loaded into memory

type Manifest

type Manifest struct {
	// Plugin Metadata
	Name          string `yaml:"name" json:"name"`
	DisplayName   string `yaml:"display_name" json:"display_name"`
	Version       string `yaml:"version" json:"version"`
	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"`
	MinAppVersion string `yaml:"min_app_version,omitempty" json:"min_app_version,omitempty"`

	// Permissions
	Permissions []string `yaml:"permissions,omitempty" json:"permissions,omitempty"`

	// Backend Configuration
	Backend *BackendConfig `yaml:"backend,omitempty" json:"backend,omitempty"`

	// Frontend Configuration
	Frontend *FrontendConfig `yaml:"frontend,omitempty" json:"frontend,omitempty"`

	// Database Configuration
	Database *DatabaseConfig `yaml:"database,omitempty" json:"database,omitempty"`

	// Dependencies
	Dependencies []string `yaml:"dependencies,omitempty" json:"dependencies,omitempty"`

	// Settings Schema (JSON Schema)
	Settings *SettingsSchema `yaml:"settings,omitempty" json:"settings,omitempty"`
}

Manifest represents the plugin.yaml configuration file

func LoadManifest

func LoadManifest(path string) (*Manifest, error)

LoadManifest loads a plugin manifest from a file path

func ParseManifest

func ParseManifest(data []byte) (*Manifest, error)

ParseManifest parses manifest data from bytes

func (*Manifest) GetBackendPath

func (m *Manifest) GetBackendPath(pluginDir string) string

GetBackendPath returns the full path to the backend package directory

func (*Manifest) GetFrontendPath

func (m *Manifest) GetFrontendPath(pluginDir string) string

GetFrontendPath returns the full path to the frontend components directory

func (*Manifest) GetMigrationPath

func (m *Manifest) GetMigrationPath(pluginDir string) string

GetMigrationPath returns the full path to the migrations directory

func (*Manifest) RequiredPermissions

func (m *Manifest) RequiredPermissions() []string

RequiredPermissions returns a list of permissions that would be required based on the manifest configuration

func (*Manifest) ToJSON

func (m *Manifest) ToJSON() (json.RawMessage, error)

ToJSON converts the manifest to JSON

func (*Manifest) Validate

func (m *Manifest) Validate() error

Validate checks if the manifest is valid

type NavigationItem struct {
	Label    string `yaml:"label" json:"label"`
	Icon     string `yaml:"icon" json:"icon"`
	Path     string `yaml:"path" json:"path"`
	Position string `yaml:"position,omitempty" json:"position,omitempty"`
}

NavigationItem represents a navigation menu item

type Permission

type Permission struct {
	Name        string             `json:"name"`
	Category    PermissionCategory `json:"category"`
	Risk        PermissionRisk     `json:"risk"`
	Description string             `json:"description"`
}

Permission defines a plugin permission

func GetPermission

func GetPermission(name string) (Permission, bool)

GetPermission returns a permission by name

func GetPermissionsByCategory

func GetPermissionsByCategory(category PermissionCategory) []Permission

GetPermissionsByCategory returns all permissions in a category

func GetPermissionsByRisk

func GetPermissionsByRisk(minRisk PermissionRisk) []Permission

GetPermissionsByRisk returns all permissions at or above a risk level

type PermissionCategory

type PermissionCategory string

PermissionCategory represents a category of permissions

const (
	CategoryDataAccess PermissionCategory = "data"
	CategorySystem     PermissionCategory = "system"
	CategoryDatabase   PermissionCategory = "database"
	CategoryDangerous  PermissionCategory = "dangerous"
)

type PermissionRisk

type PermissionRisk string

PermissionRisk represents the risk level of a permission

const (
	RiskLow      PermissionRisk = "low"
	RiskMedium   PermissionRisk = "medium"
	RiskHigh     PermissionRisk = "high"
	RiskCritical PermissionRisk = "critical"
)

func GetHighestRiskLevel

func GetHighestRiskLevel(permissions []string) PermissionRisk

GetHighestRiskLevel returns the highest risk level among the given permissions

type PermissionSummary

type PermissionSummary struct {
	Total        int            `json:"total"`
	ByCategory   map[string]int `json:"by_category"`
	ByRisk       map[string]int `json:"by_risk"`
	HighestRisk  PermissionRisk `json:"highest_risk"`
	HasDangerous bool           `json:"has_dangerous"`
	InvalidCount int            `json:"invalid_count"`
	InvalidNames []string       `json:"invalid_names,omitempty"`
}

PermissionSummary provides a summary of requested permissions

func SummarizePermissions

func SummarizePermissions(permissions []string) PermissionSummary

SummarizePermissions provides a summary of the given permissions

type Plugin

type Plugin struct {
	ID                 uuid.UUID       `json:"id"`
	Name               string          `json:"name"`
	DisplayName        string          `json:"display_name"`
	Description        string          `json:"description,omitempty"`
	Version            string          `json:"version"`
	RepositoryURL      string          `json:"repository_url"`
	RepositoryType     RepositoryType  `json:"repository_type"`
	Author             string          `json:"author,omitempty"`
	License            string          `json:"license,omitempty"`
	HomepageURL        string          `json:"homepage_url,omitempty"`
	State              PluginState     `json:"state"`
	GrantedPermissions []string        `json:"granted_permissions"`
	Manifest           json.RawMessage `json:"manifest"`
	InstalledAt        time.Time       `json:"installed_at"`
	UpdatedAt          time.Time       `json:"updated_at"`
}

Plugin represents an installed plugin

type PluginInfo

type PluginInfo struct {
	Name        string   `yaml:"name" json:"name"`
	DisplayName string   `yaml:"display_name" json:"display_name"`
	Description string   `yaml:"description,omitempty" json:"description,omitempty"`
	Repository  string   `yaml:"repository" json:"repository"`
	Version     string   `yaml:"version" json:"version"`
	Author      string   `yaml:"author,omitempty" json:"author,omitempty"`
	License     string   `yaml:"license,omitempty" json:"license,omitempty"`
	Tags        []string `yaml:"tags,omitempty" json:"tags,omitempty"`
	Downloads   int      `yaml:"downloads,omitempty" json:"downloads,omitempty"`
	Stars       int      `yaml:"stars,omitempty" json:"stars,omitempty"`
}

PluginInfo represents plugin information from a registry

type PluginMigration

type PluginMigration struct {
	ID        uuid.UUID `json:"id"`
	PluginID  uuid.UUID `json:"plugin_id"`
	Version   string    `json:"version"`
	Filename  string    `json:"filename"`
	AppliedAt time.Time `json:"applied_at"`
	Checksum  string    `json:"checksum,omitempty"`
}

PluginMigration tracks applied migrations for a plugin

type PluginRuntimeStatus

type PluginRuntimeStatus struct {
	PluginID          uuid.UUID             `json:"plugin_id"`
	PluginName        string                `json:"plugin_name"`
	DisplayName       string                `json:"display_name,omitempty"`
	Runtime           string                `json:"runtime"`
	State             RuntimeLifecycleState `json:"state"`
	Health            RuntimeHealthState    `json:"health"`
	Message           string                `json:"message,omitempty"`
	BaseURL           string                `json:"base_url,omitempty"`
	PID               *int                  `json:"pid,omitempty"`
	StartedAt         *time.Time            `json:"started_at,omitempty"`
	ReadyAt           *time.Time            `json:"ready_at,omitempty"`
	ExitedAt          *time.Time            `json:"exited_at,omitempty"`
	LastHealthCheckAt *time.Time            `json:"last_health_check_at,omitempty"`
	BackoffUntil      *time.Time            `json:"backoff_until,omitempty"`
	ExitCode          *int                  `json:"exit_code,omitempty"`
	RestartCount      int                   `json:"restart_count"`
	CrashCount        int                   `json:"crash_count"`
	HookCount         int                   `json:"hook_count"`
	RouteCount        int                   `json:"route_count"`
	LastExitError     string                `json:"last_exit_error,omitempty"`
	LastHealthError   string                `json:"last_health_error,omitempty"`
	LastError         string                `json:"last_error,omitempty"`
	LastOutput        string                `json:"last_output,omitempty"`
}

PluginRuntimeStatus is the operator-facing status snapshot for a plugin backend runtime.

type PluginSearchResult

type PluginSearchResult struct {
	Plugin   PluginInfo `json:"plugin"`
	Registry string     `json:"registry"`
}

PluginSearchResult represents search results from registries

type PluginState

type PluginState string

PluginState represents the lifecycle state of a plugin

const (
	StateInstalled PluginState = "installed"
	StateEnabled   PluginState = "enabled"
	StateDisabled  PluginState = "disabled"
	StateFailed    PluginState = "failed"
)

type Registry

type Registry struct {
	ID           uuid.UUID  `json:"id"`
	Name         string     `json:"name"`
	URL          string     `json:"url"`
	Description  string     `json:"description,omitempty"`
	IsOfficial   bool       `json:"is_official"`
	IsActive     bool       `json:"is_active"`
	LastSyncedAt *time.Time `json:"last_synced_at,omitempty"`
	CreatedAt    time.Time  `json:"created_at"`
	UpdatedAt    time.Time  `json:"updated_at"`
}

Registry represents a plugin marketplace source

type RegistryIndex

type RegistryIndex struct {
	Version int          `yaml:"version" json:"version"`
	Plugins []PluginInfo `yaml:"plugins" json:"plugins"`
}

RegistryIndex represents the structure of a registry's plugins.yaml

type Repository

type Repository interface {
	// Registry operations
	ListRegistries(ctx context.Context) ([]Registry, error)
	GetRegistry(ctx context.Context, id uuid.UUID) (*Registry, error)
	CreateRegistry(ctx context.Context, name, url, description string) (*Registry, error)
	DeleteRegistry(ctx context.Context, id uuid.UUID) (int64, error)
	UpdateRegistryLastSynced(ctx context.Context, id uuid.UUID) error

	// Plugin operations
	ListPlugins(ctx context.Context) ([]Plugin, error)
	GetPlugin(ctx context.Context, id uuid.UUID) (*Plugin, error)
	GetPluginByName(ctx context.Context, name string) (*Plugin, error)
	CreatePlugin(ctx context.Context, p *Plugin) error
	UpdatePlugin(ctx context.Context, p *Plugin) error
	DeletePlugin(ctx context.Context, id uuid.UUID) (int64, error)

	// Tenant plugin operations
	ListTenantPlugins(ctx context.Context, tenantID uuid.UUID) ([]TenantPlugin, error)
	GetTenantPlugin(ctx context.Context, tenantID, pluginID uuid.UUID) (*TenantPlugin, error)
	CreateTenantPlugin(ctx context.Context, tenantID, pluginID uuid.UUID, settings json.RawMessage) error
	EnableTenantPlugin(ctx context.Context, tenantID, pluginID uuid.UUID, settings json.RawMessage) error
	DisableTenantPlugin(ctx context.Context, tenantID, pluginID uuid.UUID) (int64, error)
	GetTenantPluginSettings(ctx context.Context, tenantID, pluginID uuid.UUID) (json.RawMessage, error)
	UpdateTenantPluginSettings(ctx context.Context, tenantID, pluginID uuid.UUID, settings json.RawMessage) error
	DeleteTenantPlugin(ctx context.Context, tenantID, pluginID uuid.UUID) error
	IsPluginEnabledForTenant(ctx context.Context, tenantID, pluginID uuid.UUID) (bool, error)

	// Enabled plugins query
	ListEnabledPlugins(ctx context.Context) ([]Plugin, error)

	// Additional operations for service refactoring
	InsertPluginReturning(ctx context.Context, manifest *Manifest, repoURL string, repoType RepositoryType, manifestJSON []byte) (*Plugin, error)
	CountEnabledTenantsForPlugin(ctx context.Context, pluginID uuid.UUID) (int, error)
	UpdatePluginState(ctx context.Context, pluginID uuid.UUID, state PluginState, permissions []string) error
	DisableAllTenantsForPlugin(ctx context.Context, pluginID uuid.UUID) error
	GetTenantPluginsWithAll(ctx context.Context, tenantID uuid.UUID) ([]TenantPlugin, error)
}

Repository defines the interface for plugin data access

type RepositoryType

type RepositoryType string

RepositoryType represents the source control type

const (
	RepoGitHub RepositoryType = "github"
	RepoGitLab RepositoryType = "gitlab"
)

type RouteConfig

type RouteConfig struct {
	Method  string `yaml:"method" json:"method"`
	Path    string `yaml:"path" json:"path"`
	Handler string `yaml:"handler" json:"handler"`
}

RouteConfig represents an API route to register

type RuntimeHealthState

type RuntimeHealthState string

RuntimeHealthState describes the latest known runtime health signal.

const (
	RuntimeHealthNotApplicable RuntimeHealthState = "not_applicable"
	RuntimeHealthUnknown       RuntimeHealthState = "unknown"
	RuntimeHealthHealthy       RuntimeHealthState = "healthy"
	RuntimeHealthUnhealthy     RuntimeHealthState = "unhealthy"
)

type RuntimeLifecycleState

type RuntimeLifecycleState string

RuntimeLifecycleState describes the operator-visible lifecycle of a plugin backend runtime.

const (
	RuntimeStateNotConfigured RuntimeLifecycleState = "not_configured"
	RuntimeStateExternal      RuntimeLifecycleState = "external"
	RuntimeStateNotLoaded     RuntimeLifecycleState = "not_loaded"
	RuntimeStateStarting      RuntimeLifecycleState = "starting"
	RuntimeStateRunning       RuntimeLifecycleState = "running"
	RuntimeStateStopped       RuntimeLifecycleState = "stopped"
	RuntimeStateExited        RuntimeLifecycleState = "exited"
	RuntimeStateBackoff       RuntimeLifecycleState = "backoff"
	RuntimeStateFailed        RuntimeLifecycleState = "failed"
)

type RuntimeRouteResponse

type RuntimeRouteResponse struct {
	StatusCode int
	Header     http.Header
	Body       []byte
}

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service handles plugin lifecycle management

func NewService

func NewService(pool *pgxpool.Pool, pluginDir string) *Service

NewService creates a new plugin service with an ORM-backed repository.

func NewServiceWithRepository

func NewServiceWithRepository(repo Repository, hooks *HookRegistry, pluginDir string) *Service

NewServiceWithRepository creates a new plugin service with a custom repository (for testing)

func (*Service) AddRegistry

func (s *Service) AddRegistry(ctx context.Context, req CreateRegistryRequest) (*Registry, error)

AddRegistry adds a new plugin registry

func (*Service) DisableForTenant

func (s *Service) DisableForTenant(ctx context.Context, tenantID, pluginID uuid.UUID) error

DisableForTenant disables a plugin for a specific tenant

func (*Service) DisablePlugin

func (s *Service) DisablePlugin(ctx context.Context, id uuid.UUID) error

DisablePlugin disables a plugin

func (*Service) EnableForTenant

func (s *Service) EnableForTenant(ctx context.Context, tenantID, pluginID uuid.UUID, settings json.RawMessage) error

EnableForTenant enables a plugin for a specific tenant

func (*Service) EnablePlugin

func (s *Service) EnablePlugin(ctx context.Context, id uuid.UUID, permissions []string) error

EnablePlugin enables a plugin with granted permissions

func (*Service) FetchRegistryIndex

func (s *Service) FetchRegistryIndex(ctx context.Context, registryURL string) (*RegistryIndex, error)

FetchRegistryIndex fetches the plugins.yaml index from a registry

func (*Service) GetHookRegistry

func (s *Service) GetHookRegistry() *HookRegistry

GetHookRegistry returns the hook registry for registering hooks

func (*Service) GetLoadedPlugin

func (s *Service) GetLoadedPlugin(name string) (*LoadedPlugin, bool)

GetLoadedPlugin returns a loaded plugin by name

func (*Service) GetPlugin

func (s *Service) GetPlugin(ctx context.Context, id uuid.UUID) (*Plugin, error)

GetPlugin returns a plugin by ID

func (*Service) GetPluginByName

func (s *Service) GetPluginByName(ctx context.Context, name string) (*Plugin, error)

GetPluginByName returns a plugin by name

func (*Service) GetPluginRuntimeStatus

func (s *Service) GetPluginRuntimeStatus(ctx context.Context, pluginID uuid.UUID) (*PluginRuntimeStatus, error)

GetPluginRuntimeStatus returns the operator-visible backend runtime status for an installed plugin.

func (*Service) GetRegistry

func (s *Service) GetRegistry(ctx context.Context, id uuid.UUID) (*Registry, error)

GetRegistry returns a registry by ID

func (*Service) GetTenantPluginSettings

func (s *Service) GetTenantPluginSettings(ctx context.Context, tenantID, pluginID uuid.UUID) (json.RawMessage, error)

GetTenantPluginSettings returns the settings for a plugin for a tenant

func (*Service) GetTenantPlugins

func (s *Service) GetTenantPlugins(ctx context.Context, tenantID uuid.UUID) ([]TenantPlugin, error)

GetTenantPlugins returns all plugins available to a tenant

func (*Service) InstallPlugin

func (s *Service) InstallPlugin(ctx context.Context, repoURL string) (*Plugin, error)

InstallPlugin installs a plugin from a repository URL

func (*Service) InvokeTenantPluginRoute

func (s *Service) InvokeTenantPluginRoute(
	ctx context.Context,
	tenantID uuid.UUID,
	pluginID uuid.UUID,
	method string,
	path string,
	rawQuery string,
	headers http.Header,
	body io.Reader,
) (*RuntimeRouteResponse, error)

func (*Service) IsPluginEnabledForTenant

func (s *Service) IsPluginEnabledForTenant(ctx context.Context, tenantID, pluginID uuid.UUID) (bool, error)

IsPluginEnabledForTenant checks if a plugin is enabled for a tenant

func (*Service) ListPlugins

func (s *Service) ListPlugins(ctx context.Context) ([]Plugin, error)

ListPlugins returns all installed plugins

func (*Service) ListRegistries

func (s *Service) ListRegistries(ctx context.Context) ([]Registry, error)

ListRegistries returns all plugin registries

func (*Service) LoadEnabledPlugins

func (s *Service) LoadEnabledPlugins(ctx context.Context) error

LoadEnabledPlugins loads all enabled plugins into memory on startup

func (*Service) RemoveRegistry

func (s *Service) RemoveRegistry(ctx context.Context, id uuid.UUID) error

RemoveRegistry removes a plugin registry

func (*Service) RestartPluginRuntime

func (s *Service) RestartPluginRuntime(ctx context.Context, pluginID uuid.UUID) (*PluginRuntimeStatus, error)

RestartPluginRuntime manually restarts a supervised package runtime.

func (*Service) SearchPlugins

func (s *Service) SearchPlugins(ctx context.Context, query string) ([]PluginSearchResult, error)

SearchPlugins searches for plugins across all active registries

func (*Service) SyncRegistry

func (s *Service) SyncRegistry(ctx context.Context, registryID uuid.UUID) error

SyncRegistry fetches and caches the plugin list from a registry

func (*Service) UninstallPlugin

func (s *Service) UninstallPlugin(ctx context.Context, id uuid.UUID) error

UninstallPlugin removes a plugin

func (*Service) UpdateRegistryLastSynced

func (s *Service) UpdateRegistryLastSynced(ctx context.Context, id uuid.UUID) error

UpdateRegistryLastSynced updates the last synced timestamp

func (*Service) UpdateTenantPluginSettings

func (s *Service) UpdateTenantPluginSettings(ctx context.Context, tenantID, pluginID uuid.UUID, settings json.RawMessage) error

UpdateTenantPluginSettings updates the settings for a plugin for a tenant

type SettingProperty

type SettingProperty struct {
	Type        string      `yaml:"type" json:"type"`
	Default     interface{} `yaml:"default,omitempty" json:"default,omitempty"`
	Description string      `yaml:"description,omitempty" json:"description,omitempty"`
	Minimum     *float64    `yaml:"minimum,omitempty" json:"minimum,omitempty"`
	Maximum     *float64    `yaml:"maximum,omitempty" json:"maximum,omitempty"`
	MinLength   *int        `yaml:"minLength,omitempty" json:"minLength,omitempty"`
	MaxLength   *int        `yaml:"maxLength,omitempty" json:"maxLength,omitempty"`
	Enum        []string    `yaml:"enum,omitempty" json:"enum,omitempty"`
}

SettingProperty represents a single setting property

type SettingsSchema

type SettingsSchema struct {
	Type       string                     `yaml:"type" json:"type"`
	Properties map[string]SettingProperty `yaml:"properties,omitempty" json:"properties,omitempty"`
	Required   []string                   `yaml:"required,omitempty" json:"required,omitempty"`
}

SettingsSchema represents a JSON Schema for plugin settings

type SlotConfig

type SlotConfig struct {
	Name        string `yaml:"name" json:"name"`
	Component   string `yaml:"component" json:"component"`
	Label       string `yaml:"label,omitempty" json:"label,omitempty"`
	Description string `yaml:"description,omitempty" json:"description,omitempty"`
	Path        string `yaml:"path,omitempty" json:"path,omitempty"`
	Kind        string `yaml:"kind,omitempty" json:"kind,omitempty"`
	Badge       string `yaml:"badge,omitempty" json:"badge,omitempty"`
	Order       *int   `yaml:"order,omitempty" json:"order,omitempty"`
}

SlotConfig represents a UI slot injection

type TenantPlugin

type TenantPlugin struct {
	ID        uuid.UUID       `json:"id"`
	TenantID  uuid.UUID       `json:"tenant_id"`
	PluginID  uuid.UUID       `json:"plugin_id"`
	IsEnabled bool            `json:"is_enabled"`
	Settings  json.RawMessage `json:"settings,omitempty"`
	EnabledAt *time.Time      `json:"enabled_at,omitempty"`
	CreatedAt time.Time       `json:"created_at"`
	UpdatedAt time.Time       `json:"updated_at"`

	// Joined fields
	Plugin *Plugin `json:"plugin,omitempty"`
}

TenantPlugin represents a plugin enabled for a specific tenant

type TenantPluginSettingsRequest

type TenantPluginSettingsRequest struct {
	Settings json.RawMessage `json:"settings"`
}

TenantPluginSettingsRequest represents a request to update tenant plugin settings

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL