# Plugin registration

> Declare a plugin: its ID, the party.Plugin lifecycle, the pact capability interfaces it opts into, its embedded files and the scaffolded layout.

Plugins are the foundation of every SummerCMS application. A plugin adds models, routes, admin screens, console commands, jobs and translations, and it can extend other plugins. This page covers how a plugin tells the framework what it contributes.

## Plugin identifiers

Every plugin has an ID in `vendor.plugin` form: two lower-case parts, each starting with a letter and containing only letters and digits, such as `acme.blog`. The ID is how the manifest lists the plugin, how other plugins require it and how its configuration is namespaced (`acme.blog.posts_per_page`). WinterCMS writes the same identifier as `Acme.Blog`; in SummerCMS it is always lower case.

The scaffolder derives the package and directory name from the second part, so `summer make:plugin acme.blog` creates `plugins/blog` with `package blog`.

## The plugin type

A plugin is a Go type that implements `party.Plugin`. Its package registers it from `init` with `party.Register`, so importing the package is enough to make the plugin available; the generated `plugins.gen.go` does that import for every plugin in `summer.yaml`.

| Method | Purpose |
|--------|---------|
| `party.Plugin.ID` | Returns the plugin ID. |
| `party.Plugin.Requires` | Lists the IDs of plugins that must register and boot before this one, like `$require` in WinterCMS. |
| `party.Plugin.Register` | Runs before any plugin boots. Publish services on the container here. |
| `party.Plugin.Boot` | Runs after every plugin registered. Listen to events and use other plugins' services here. |

Here is a complete plugin that also declares a backend permission:

```go
package party_test

import (
	"git.golem15.com/golem15/summercms/modules/backpack"
	"git.golem15.com/golem15/summercms/modules/pact"
)

// BlogPlugin is the acme.blog plugin: the Go form of a WinterCMS Plugin.php.
// A real plugin package also registers it from init with
// party.Register(&BlogPlugin{}).
type BlogPlugin struct{}

// The optional capabilities the plugin opts into, checked at compile time.
var _ pact.HasPermissions = (*BlogPlugin)(nil)

// ID is the plugin identifier in vendor.plugin form.
func (p *BlogPlugin) ID() string { return "acme.blog" }

// Requires lists the plugins that must register and boot first ($require).
func (p *BlogPlugin) Requires() []string { return []string{"acme.user"} }

// Register runs before any plugin boots: publish services here.
func (p *BlogPlugin) Register(app *backpack.App) error { return nil }

// Boot runs after every plugin registered: listen to events and look up
// services other plugins published.
func (p *BlogPlugin) Boot(app *backpack.App) error { return nil }

// Permissions replaces registerPermissions().
func (p *BlogPlugin) Permissions() []pact.Permission {
	return []pact.Permission{
		{Code: "acme.blog.access_posts", Tab: "Blog", Label: "Manage posts"},
	}
}
```

The `var _ pact.HasPermissions = (*BlogPlugin)(nil)` line is a compile-time check: if a method is missing or has the wrong signature, the build fails instead of the capability being silently ignored. Add one such line for every capability your plugin implements.

## Capability interfaces

A WinterCMS plugin overrides `register*` methods of `PluginBase`. A SummerCMS plugin implements small interfaces from [pact](/docs/api/pact.md) instead, and the framework discovers each one with a type assertion.

| Interface | Contributes |
|-----------|-------------|
| `pact.HasRoutes` | HTTP routes, declared on a `pact.Router`. |
| `pact.HasMiddleware`, `pact.HasMiddlewareFactories` | Named and parameterized route middleware. |
| `pact.HasConfig` | Default configuration, merged under the plugin ID. |
| `pact.HasMigrations` | An ordered set of database migrations. |
| `pact.HasCommands` | Console commands for the application binary. |
| `pact.HasJobs` | Background jobs. |
| `pact.HasSchedule` | Console commands that run on a schedule; see [Scheduling](/docs/plugins/scheduling.md). |
| `pact.HasLang`, `pact.HasLangOverrides` | Translations, and overrides of other namespaces. |
| `pact.HasMailTemplates` | Mail templates and layouts. |
| `pact.HasPermissions`, `pact.HasNavigation`, `pact.HasSettings` | Backend permissions, navigation and settings screens. |
| `pact.HasAdminControllers` | Admin controllers built from `fields.yaml` and `columns.yaml`. |
| `pact.HasModels` | The plugin's GORM models. No framework package reads it yet. |

## Embedded files

Configuration defaults, translations and mail templates ship inside the binary through Go's `embed` package. The plugin returns an `fs.FS` for each:

- `pact.HasConfig.ConfigFS` returns a tree with `config/config.yaml`. Its keys become `<plugin id>.<key>`, and any other `config/<name>.yaml` becomes `<plugin id>.<name>.<key>`. The application's own `config/` directory and `SUMMER_` variables override them.
- `pact.HasLang.LangFS` returns `lang/<locale>/<group>.yaml` files.
- `pact.HasMailTemplates.MailTemplatesFS` returns the `views/mail` templates, and `pact.HasMailTemplates.MailTemplates` lists their names.

## The scaffolded layout

`summer make:plugin acme.blog` writes a plugin that compiles and follows the WinterCMS directory layout, with each directory as a Go subpackage:

```text
plugins/blog/
├── go.mod              the plugin module, requiring the framework
├── plugin.go           the Plugin type, its capabilities and init registration
├── routes.go           the Routes method
├── registry.gen.go     generated lists of models, migrations, commands, jobs and admin controllers
├── classes/            services and hooks
├── config/config.yaml  default configuration
├── console/            console commands
├── controllers/        HTTP handlers and admin controllers
├── jobs/               background jobs
├── lang/en/lang.yaml   translations
├── middleware/         named middleware
├── models/             GORM models
├── updates/            migrations
└── views/mail/         mail templates
```

The `make:` commands, such as `summer make:model acme.blog Post`, add files to these directories and regenerate `registry.gen.go`, so you do not edit that file by hand. The capability methods in `plugin.go` return the generated lists, so a new model, migration, command, job or admin controller is picked up without editing the plugin type.
