Skip to main content
Version: v1 (Current)

Plugin System

Overview

All plugins follow the same pattern: definition → versioned releases → project instances → portal bindings. A team creates a plugin, publishes versions, and projects install instances pinned to specific versions.

PluginPage (template, owned by team)
└── PluginPageVersion (versioned releases: code, deps, settings)
└── ProjectPage (instance per project, with resolved config)
└── ProjectPortalPage (bound to portal with URL + token)

This pattern repeats across all four plugin types.

The Four Plugin Types

Plugin Pages (Apps)

The core building block. Plugin pages are self-contained applications with HTML, CSS, and JavaScript that render as portal pages. Each version contains:

  • body_template — HTML/Vue template code
  • style — CSS stylesheet
  • javascript — JavaScript code or compiled bundle
  • dependencies — data and permission declarations (the security model)
  • settings — configurable options exposed to project admins

Examples: Registration forms, social feeds, agendas, leaderboards, speaker directories, live polling, drawing walls, photo booths.

Plugin pages are Vue 3 applications compiled through Vite. The final build excludes Vue itself (it's provided by the platform), keeping bundles compact.

Plugin Widgets

Global components injected into every portal page. Widgets don't have their own URL — they're embedded in the portal layout.

  • Head scripts — injected into <head> (analytics, tag managers)
  • Global Vue components — floating overlays, persistent UI elements

Examples: Google Analytics trackers, chat widgets (Intercom, Drift), cookie consent banners, notification bells, help buttons.

Each widget gets its own Sanctum token and can declare its own dependencies, independent of any page.

Plugin Themes

Portal layout and styling packages. A theme provides the visual shell that wraps all portal content.

  • Public template — layout for unauthenticated pages
  • Private template — layout for authenticated pages
  • System template — layout for system pages (errors, access codes)
  • CSS and JS libraries — global styles and scripts

Themes control branding, colors, fonts, and the overall look and feel of the attendee experience.

Plugin Tiles

Dashboard analytics displays for project administrators. Tiles render custom data visualizations on the admin dashboard.

Examples: Attendance counters, registration charts, revenue breakdowns, real-time check-in maps.

Tiles follow the same versioning model but are admin-facing rather than attendee-facing.

Comparison

AspectPagesWidgetsThemesTiles
AudienceAttendeesAttendeesAttendeesAdmins
Has URLYes (/schedule)No (embedded)No (layout)No (dashboard)
ScopeFull page contentSmall UI elementPortal-wide layoutDashboard panel
Own API tokenYesYesNoYes
DependenciesFull declarationsFull declarationsN/AFull declarations

Versioning

Plugins use independent version management:

  • Publishing creates a new version snapshot. The published version becomes immutable.
  • Projects pin to a specific version via plugin_page_version_id (or equivalent).
  • Upgrading is explicit — changing the pinned version on each project instance.
  • Deprecation marks a version as outdated, but it continues working for projects that haven't upgraded.

Version Lifecycle

Draft (v3)        ← active development
Published (v2) ← installed by projects, immutable
Published (v1) ← older version, still in use
Deprecated (v0) ← marked outdated, still functional

When a version is published:

  1. The current draft is marked as published
  2. A new draft version is created with an incremented version number
  3. All assets are copied to the new draft
  4. The plugin's current_version_id updates

Version Pinning

Different projects can run different versions of the same plugin. This means:

  • Updating a plugin template doesn't automatically affect existing installations
  • A deprecated version keeps working for projects that haven't upgraded
  • Security scope is locked to the pinned version's dependencies

Dependencies and Security Model

The dependency system is the core of plugin security. Each plugin version declares what data and permissions it needs. At runtime, the platform enforces these declarations.

How It Works

Step 1: Plugin developer declares dependencies

Each version includes a dependencies array specifying the models, permissions, and events the plugin needs:

[
{
"identifier": "attendee_profile",
"model": "Attendee",
"key": "id",
"permissions": [
"Attendee:view",
"Attendee:viewAny",
"Attendee:update"
],
"events": {
"onUpdate": "attendee.updated"
}
}
]

Step 2: Project admin resolves dependencies

When installing the plugin, the admin maps each dependency to a concrete value:

{ "attendee_profile": 123 }

Step 3: Runtime authorization

When the plugin makes an API call, the platform:

  1. Resolves the bearer token to the specific portal page
  2. Checks the requested model and ability against the version's declared dependencies
  3. For instance-specific permissions (without Any suffix), verifies the model's key matches the resolved value
  4. Denies access if any check fails

Permission Format

Permissions follow the Model:ability pattern:

PermissionMeaning
Attendee:viewView a specific attendee (requires instance match)
Attendee:viewAnyView any attendee (broad access)
Attendee:updateUpdate a specific attendee (requires instance match)
Attendee:createCreate new attendee records

The Any suffix grants broad access without instance-level matching. Without it, the authorization check verifies the specific model instance matches the resolved dependency value.

Security Properties

  • Least privilege — plugins can only access what their dependencies declare
  • Version-locked — permission scope is tied to the pinned version, not the latest
  • Instance-scoped — specific permissions require model key matching
  • Token isolation — each page and widget gets a unique, non-transferable API token
  • Team-scoped — all access operates within multi-tenant boundaries

Plugin Plans (Experience Templates)

Plugin plans are JSON-driven templates that provision entire project structures from a single template. When applied to a project, a plan creates portals, pages, widgets, forms, and configurations automatically.

What Plans Do

A plan template defines:

  • Objects to create — pages, widgets, forms, saved searches, groups, and other project resources
  • Dependencies between objects — child objects created after parents, with references resolved
  • Settings and configuration — pre-configured values for each created object
  • Navigation shortcuts — dashboard quick-access links

Template Structure

[
{
"type": "savedSearches",
"identifier": "all_attendees",
"data": [
{ "column": "name", "value": "All Attendees" },
{ "column": "searchable_type", "value": "App\\Models\\Attendee" }
]
},
{
"type": "pages",
"data": [
{ "column": "name", "value": "Registration" },
{
"column": "plugin_page_id",
"type": "lookup",
"value": {
"slug": "attendee-registration",
"model": "PluginPage",
"return": "id"
}
}
],
"dependencies": [...]
}
]

Key Behaviors

  • Objects are created in array order — use identifier to reference earlier objects
  • Slug-based resolution makes plans portable across environments (references by slug, not ID)
  • Recursive dependencies — child objects are processed after parents
  • Conditional creation — objects can include conditions that must be met
  • Service methods — plans can call service classes for complex operations beyond model creation

Plans enable repeatable event setups — create a "Conference" plan once, apply it to every new conference project.

Development Workflow

1. Create plugin
└── DashboardDeveloperPages/Widgets/Themes/TilesNew

2. Develop with DevKit
└── Build Vue 3 app with Vite, using GxP Store for platform data

3. Upload & configure
└── Upload compiled JS/CSS to the plugin version
└── Define dependencies, settings, and configuration forms

4. Publish version
└── Mark as published → creates new draft for continued development

5. Add to project
└── Project admin installs plugin instance, resolves dependencies

6. Configure in portal
└── Bind to portal page with URL slug, auth settings, access codes

7. Attendees use it
└── Portal serves the plugin on custom domain

Next Steps