AdminPlugin
The administration panel of a Milpa app — the surface where a human leaves the house ready for the agent. Add it to `config/plugins.php` and `/milpa/admin` exists: a shell of Milpa Components whose sidebar lists every section the booted plugins declared through {@see AdminSectionProvider}. This plugin's own sections — the plugins the app boots, the routes they declare, what the app declared about the panel itself, the backing services the plugins need, and the ledgers the agent writes (Dev tools, read-only) — enter through that same contract, so the panel has no privileged path and names no plugin. What the app declares (`admin.*` in its config): `route` (default `/milpa/admin`), `locale` (`en`|`es`), `middleware` (PSR-15 classes attached to every panel route; default {@see LoopbackOnlyMiddleware}), `secret` (state signing; falls back to `live.secret`, then a derived one), `title`. Only a literally empty `middleware` list opens the panel; any misdeclaration — a non-string entry, a map, a value that is not a list, a class that does not exist or is not PSR-15 — makes every panel route fall back to loopback-only, and the Settings section and the topbar chip say so (greenhouse decisions/0204).
AdminPlugin::__construct()
public function __construct(Milpa\Interfaces\Di\DIContainerInterface $container):Parameters
| Name | Type | Description |
|---|---|---|
| $container | Milpa\Interfaces\Di\DIContainerInterface |
AdminPlugin::boot()
public function boot(): voidWires the panel's collaborators from the declared settings and registers its controllers.
AdminPlugin::routes()
public function routes(): arrayThe panel's routes, each carrying the EFFECTIVE middleware stack — the declared one when every entry names a PSR-15 middleware class (an empty list included), loopback-only the moment the declaration is anything else ({@see AdminSettings::effectiveMiddleware()}). The live wire (`POST {route}/live`) carries that same stack, deliberately: it is the door every component of the page — the panel's own and every guest's — takes its actions through, and a wire outside the gate would be a hole (greenhouse decisions/0211).
AdminPlugin::adminSections()
public function adminSections(): arrayThe panel's own sections — Plugins, Routes, Settings, Stack and Dev tools — through the same contract every plugin uses.
AdminPlugin::sectionStates()
public function sectionStates(): arrayThe same sections, offered to the terminal — every section in the catalogue, this plugin's and every guest's (greenhouse decisions/0220). The panel implements this ONCE, for everyone. `milpa/console` discovers terminal state from booted plugins implementing {@see SectionStateSource}; if each plugin implemented it, every plugin would declare its section twice — once for the panel, once for the terminal — which is the thing 0220 refuses. A plugin declares an {@see AdminSection} and gains a surface it never mentioned. Empty before boot: there is no codec to mount with and no catalogue to read.
AdminPlugin::settings()
public function settings(): Milpa\Admin\AdminSettingsThe settings the panel booted with, or the defaults before boot.
AdminPlugin::install()
public function install(): voidNothing to install: the panel keeps no data of its own.
AdminPlugin::uninstall()
public function uninstall(): voidNothing to uninstall: removing the panel touches nothing it administers.
AdminPlugin::enable()
public function enable(): voidNothing to enable: sections exist because the panel discovered them.
AdminPlugin::disable()
public function disable(): voidNothing to disable.