Skip to main content
Version: 0.1.x

Introduction​

The plugin system is LinaPro's core extension mechanism for business capabilities. Each plugin is a self-contained module that can declare API routes, database resources, frontend pages, menu permissions, language packs, scheduled tasks, and lifecycle callbacks.

LinaPro supports two delivery modes simultaneously:

  • Source plugins: Participate in core framework compilation as Go source code, suited for long-term business capabilities.
  • Dynamic plugins: Uploaded and loaded as .wasm runtime artifacts, suited for binary distribution, hot-loading, and temporary extensions.

The two modes differ in runtime form, but share the same plugin governance plane. The admin side sees the same plugin lifecycle, dependencies, permissions, status, and multi-tenant policies.

Why Two Modes?​

A single plugin form cannot simultaneously satisfy development efficiency, runtime performance, hot-loading, and commercial distribution.

NeedBetter ModeReason
Long-term business modulesSource pluginsNative Go performance, complete toolchain, easy to test and maintain
Urgent fixes or temporary capabilitiesDynamic pluginsCan be uploaded and enabled at runtime, reducing deployment impact
Commercial plugin distributionDynamic pluginsCan distribute only binary artifacts without exposing source
Deep core framework collaborationSource pluginsCan use core framework capabilities through stable pluginhost contracts

In most business development, source plugins are the default choice. Choose dynamic plugins when hot-loading, source code protection, or end-user plugin uploads are hard requirements.

Governance Pipeline​

The plugin system is not a simple "scan directory and register routes" — it is a full governance pipeline from discovery to runtime:

ComponentResponsibility
catalogReads plugin.yaml or WASM custom sections and generates an auditable release snapshot
dependencyChecks framework version range, plugin dependencies, and circular dependencies
lifecycleOrchestrates install, enable, disable, uninstall, and runtime upgrade
integrationProjects menus, permissions, routes, hooks, and scheduled tasks into the core framework runtime
plugin-runtime cacheProvides low-latency plugin status, route, and resource snapshots for request paths

Key Public Contracts​

plugin.yaml​

Every plugin must provide a plugin.yaml. It is the unified entry point for plugin identity, dependencies, menus, multi-tenant policy, and dynamic plugin core framework service authorization.

id: content-article
name: 文įĢ įŽĄį†
version: v0.1.0
type: source
scope_nature: tenant_aware
supports_multi_tenant: true
default_install_mode: tenant_scoped
description: 提䞛文įĢ å†…åŽšįš„åĸžåˆ æ”šæŸĨįŽĄį†åŠŸčƒŊ
author: linapro
license: Apache-2.0
menus:
- key: plugin:content-article:list
name: 文įĢ įŽĄį†
path: content-article-list
component: system/plugin/dynamic-page
perms: content-article:article:view
type: M

Dynamic plugins can also declare hostServices to request access to core framework capabilities:

hostServices:
- service: data
methods: [list, get, create, update, delete]
resources:
tables:
- plugin_demo_dynamic_record
- service: storage
methods: [put, get, delete, list]
resources:
paths:
- plugin-demo-dynamic/

pluginhost​

pluginhost is the stable extension seam used by source plugins. Source plugins register through it:

InterfaceCapability
Assets()Embeds plugin manifest, language packs, SQL, and frontend resources
HTTP()Registers plugin HTTP routes
Hooks()Subscribes to core framework events
Cron()Registers plugin task handlers
Lifecycle()Registers install, upgrade, disable, uninstall, and other lifecycle callbacks
Governance()Declares menu and permission filtering logic

Source plugins cannot directly import the core framework's internal/ directory. They can only use stable contracts published by the core framework.

pluginbridge​

pluginbridge is the sandbox communication layer for dynamic plugins. The core framework encapsulates request, identity, tenant, and permission snapshots into a BridgeRequestEnvelopeV1 and passes it into the WASM module. The plugin returns a BridgeResponseEnvelopeV1.

When a dynamic plugin accesses core framework capabilities, it issues a host_call. The core framework validates the service, method, and resource boundaries against the hostServices authorization snapshot confirmed at installation time.

Lifecycle States​

The plugin lifecycle covers discovery, installation, enablement, disablement, uninstallation, and upgrade:

Plugin file updates do not automatically switch the active version. After the core framework starts or scans and finds a higher version, it marks the plugin as pending_upgrade. The administrator previews and explicitly executes the runtime upgrade in the plugin management page. The upgrade flow runs dependency pre-checks, lifecycle callbacks, upgrade SQL, governance resource synchronization, active release switching, cache invalidation, and cluster notification.

Isolation Mechanisms​

Database namespace​

Plugin-owned tables must use a snake_case prefix derived from the plugin ID:

Core framework tables: sys_user, sys_role, sys_menu
Plugin tables: content_notice_notice, org_center_dept, plugin_demo_dynamic_record

System tables use the sys_ prefix. Plugin tables use the <plugin_id>_ prefix. Core framework and plugin data are fully isolated, avoiding naming conflicts and permission misuse.

Plugins that need multi-tenant support should design their tables to include a tenant_id column and use the core framework-published tenant filtering capability to append filter conditions.

File namespace​

Plugin file storage should use the plugin ID as the path namespace:

temp/upload/content-notice/
temp/upload/plugin-demo-dynamic/

Sandbox isolation​

WASM dynamic plugins cannot directly access the core framework filesystem, network, or database. All access goes through hostServices bridging, constrained by authorization snapshots.

Multi-Tenant Fields​

Plugins declare multi-tenant boundaries through three fields:

FieldValuesDescription
scope_natureplatform_only / tenant_awareWhether the plugin is a platform-level governance capability or can enter tenant contexts
supports_multi_tenanttrue / falseWhether it supports tenant-scoped installation, provisioning, and data isolation
default_install_modeglobal / tenant_scopedWhether it is enabled globally by default or independently per tenant

For example, the multi-tenant plugin itself is a platform-level governance plugin using platform_only and global. Content, organization, and audit plugins are typically tenant_aware.

Core Framework and Plugin Boundaries​

RuleReason
Plugins must not depend on the core framework's internal/ packagesCore framework internals can evolve; stable contracts are provided by pkg/
Plugin menus use the plugin:<plugin-id>:<key> formatAvoids conflicts with the core framework or other plugins
Installation SQL must be idempotentSupports repeated execution, reinstallation with data retention, and upgrade recovery
Plugin service logic goes in backend/internal/service/Keeps plugin backend structure consistent, avoiding package naming confusion
Plugin uninstallation distinguishes retained vs. cleaned dataReduces accidental deletion risk and allows data reuse on reinstallation