API reference
pact
Capability interfaces that compiled plugins implement to contribute routes, config, migrations, middleware, commands, admin screens, translations, mail templates, jobs and scheduled commands.
On this page
import "git.golem15.com/golem15/summercms/modules/pact"
Overview#
pact is the contract layer between plugins and the framework. It holds interfaces and plain data types, with no behaviour of its own. A plugin opts into a capability by implementing one of the Has* interfaces, and the framework package that owns the capability discovers it with a type assertion (party for config, surf for routes and middleware, lagoon for migrations, cabana for admin controllers, conga for jobs and schedules). It replaces the register*() methods of a WinterCMS PluginBase (registerPermissions, registerNavigation, registerSettings and so on) with small, separately implementable interfaces.
Features#
- Plugin capability interfaces:
pact.HasRoutes,pact.HasConfig,pact.HasMigrations,pact.HasCommands,pact.HasModels,pact.HasJobs,pact.HasSchedule,pact.HasLang,pact.HasLangOverridesandpact.HasMailTemplates. - HTTP contracts: the
pact.Routergroup builder (implemented by surf), thepact.Middlewaretype, and named, parameterized (name:param) and house-envelope middleware throughpact.HasMiddleware,pact.HasMiddlewareFactoriesandpact.HasHouseMiddleware. - Backend registration data:
pact.Permission,pact.NavigationItemandpact.SettingsItem, exposed throughpact.HasPermissions,pact.HasNavigationandpact.HasSettings. - Admin controller contracts:
pact.AdminController,pact.HasAdminControllers,pact.AdminAssets(embedded Winter-shaped admin YAML),pact.AdminPermissionedandpact.AdminRecordSource. - Admin extension contracts, so a plugin extends the compiled admin SPA without a Node build:
pact.AdminClientAssets(per-controller JS and CSS from the plugin's embeddedassets/tree, Winter'saddJs/addCss),pact.HasAdminActionswithpact.AdminAction,pact.AdminActionInputandpact.AdminActionResult(named toolbar and widget actions whose routes, CSRF check, permissions and record scoping the framework owns), andpact.AdminPartialData(the curated view model a partial template renders). - Optional admin hooks a controller or model can implement: list and form query scoping (
pact.ListExtendQuery,pact.FormExtendQuery), create, update and delete hooks (pact.FormBeforeCreate,pact.FormAfterUpdate,pact.FormBeforeDeleteand their siblings), relation hooks (pact.RelationExtendManageQuery,pact.RelationExtendOptionsQuery,pact.RelationBeforeLink), filter scopes (pact.FilterScope,pact.FilterOptions) and dropdown options (pact.DropdownOptionsProvider). - A background job contract (
pact.Job,pact.JobArgs) that does not depend on any queue library. - A schedule contract:
pact.HasSchedulereturnspact.ScheduledCommandentries (a registered command name, its arguments and apact.Cadencebuilt withpact.Daily,pact.DailyAtorpact.Every), the Go form of WinterCMSregisterSchedule. It does not depend on any queue library either. pact.OptionalMessage, a service an optional plugin can publish so others integrate with it without importing its package.pact.HasModelsandpact.OptionalMessageare declared for plugins to implement, but no framework package consumes them yet.
Usage#
A plugin declares its capabilities by implementing the interfaces and asserting them at compile time:
package blog
import (
"net/http"
"git.golem15.com/golem15/summercms/modules/pact"
)
var (
_ pact.HasRoutes = (*Plugin)(nil)
_ pact.HasPermissions = (*Plugin)(nil)
)
type Plugin struct{}
func (p *Plugin) Routes(r pact.Router) error {
r.Group("/api/blog", []string{"auth"}, func(r pact.Router) {
r.Get("/posts", listPosts)
r.Get("/posts/{id}", showPost)
r.Where("id", "[0-9]+")
})
return nil
}
func (p *Plugin) Permissions() []pact.Permission {
return []pact.Permission{
{Code: "acme.blog.access_posts", Tab: "Blog", Label: "Manage posts"},
}
}
func listPosts(w http.ResponseWriter, r *http.Request) {}
func showPost(w http.ResponseWriter, r *http.Request) {}
A plugin schedules one of its registered commands by implementing pact.HasSchedule:
var _ pact.HasSchedule = (*Plugin)(nil)
func (p *Plugin) Schedule() []pact.ScheduledCommand {
return []pact.ScheduledCommand{
{Command: "blog:prune-drafts", Cadence: pact.Daily()},
{Command: "blog:ping", Args: []string{"--quiet"}, Cadence: pact.Every(15 * time.Minute)},
}
}
API reference#
| Identifier | Description |
|---|---|
pact.Router |
Laravel-style route group builder (pact.Router.Group, pact.Router.GroupRaw, one method per HTTP verb, pact.Router.Where, pact.Router.WhereIn); implemented by surf. |
pact.HasRoutes |
Declares HTTP routes on a pact.Router. |
pact.Middleware |
A named func(http.Handler) http.Handler wrapper. |
pact.HasMiddleware |
Registers named middleware. |
pact.HasMiddlewareFactories |
Registers parameterized middleware resolved from name:param at wrap time. |
pact.HasHouseMiddleware |
Registers middleware tagged as envelope and error handling, which raw groups refuse. |
pact.HasConfig |
Ships default YAML config, merged under the plugin ID. |
pact.HasMigrations |
Ships an ordered gormigrate set, run with a per-plugin history table. |
pact.HasCommands |
Contributes bonfire console commands to the application binary. |
pact.HasModels |
Exposes GORM models. |
pact.Job |
Background unit of work that receives pact.JobArgs. |
pact.HasJobs |
Registers background jobs. |
pact.HasSchedule |
Declares recurring console commands (Schedule() []pact.ScheduledCommand); conga workers run them. |
pact.ScheduledCommand |
One schedule entry: Command, Args and Cadence. |
pact.Cadence |
Opaque run frequency with IsZero, Interval (24h for daily cadences) and At (hour and minute of a daily cadence). |
pact.Daily |
Cadence at 00:00 every day in the app timezone (Laravel ->daily()). |
pact.DailyAt |
Cadence at a given hour and minute every day in the app timezone. |
pact.Every |
Cadence at every multiple of an interval since local midnight; the interval must be at least 1s and divide 24h. |
pact.HasLang |
Ships translation YAML under lang/<locale>/<group>.yaml. |
pact.HasLangOverrides |
Replaces or adds translations of any loaded namespace, including the framework's own. |
pact.HasMailTemplates |
Ships mail templates and layout aliases. |
pact.Permission |
One backend permission entry (code, tab, label, roles). |
pact.NavigationItem |
One backend navigation entry, with an optional side menu. |
pact.SettingsItem |
One settings screen entry. |
pact.AdminController |
Admin controller identity: ID, model name and YAML config directory. |
pact.AdminAssets |
Embedded tree of the plugin's admin YAML. |
pact.AdminRecordSource |
Supplies a new model record for the generic admin handlers. |
pact.AdminClientAssets |
Declares a controller's admin JS (AdminJS) and CSS (AdminCSS) files, paths under the plugin's assets/ directory. |
pact.AdminAction |
One named controller action: name, label, extra permissions and the Go Run function. |
pact.AdminActionInput |
What an action receives: widget field, optional record id and scoped record, and the fill snapshot. |
pact.AdminActionResult |
What an action returns: a message for the toast and the fill write-back values. |
pact.HasAdminActions |
Registers a controller's actions for toolbar.buttons and type: widget fields. |
pact.AdminPartialData |
Supplies the view model a controller partial template renders; never the GORM model. |
pact.FilterScope |
Model scopes a list filter may call, limited to an exact allow list. |
pact.Option |
One dropdown choice (value and label). |
Dependencies#
- SummerCMS modules: bonfire (the command type in
pact.HasCommands). - Third-party:
github.com/go-gormigrate/gormigrate/v2,gorm.io/gorm. - Standard library:
context,io/fs,net/http,time.
Testing#
go test ./modules/pact/...
The tests are compile-time interface checks and need no external services.