Skip to content

Package Boot Lifecycle

Capell package boot is deliberately split into metadata, install-time work, admin/runtime registration, and frontend rendering. Most extension bugs happen when code runs in the wrong bucket.

flowchart TD
Composer["Composer install/update"] --> Discovery["Laravel provider discovery"]
Composer --> Manifest["capell.json manifest"]
Manifest --> Registry["Capell package registry"]
Registry --> Context["RuntimeContextResolver chooses bucket"]
Context --> Install["Install/setup context"]
Context --> Runtime["Runtime context"]
Context --> Admin["Admin context"]
Context --> Frontend["Frontend context"]
Install --> InstallActions["Install commands, migrations, setup Actions"]
Runtime --> RuntimeProviders["Settings, models, subscribers, package metadata"]
Admin --> AdminProviders["AdminBridge, resources, pages, widgets, extenders"]
Frontend --> FrontendProviders["Render hooks, routes, assets, cache invalidation"]
RuntimeProviders --> Caches["Package/config caches"]
AdminProviders --> Caches
FrontendProviders --> Caches
Caches --> Request["Request/job/command uses registered contracts"]
PhaseOwnsMust not do
ComposerAutoload, provider discovery, dependency constraintsRuntime writes or package enablement.
ManifestPackage name, provider buckets, scopes, settings ownership, product/Marketplace metadataExecute code.
Install/setupMigrations, settings migrations, one-time setup Actions, optional package install commandsRegister admin UI needed only after install.
RuntimePackage metadata, settings classes, model aliases/interceptors, subscribers, commandsQuery public request data or render Filament.
AdminAdminBridge, Filament pages/resources/widgets, schema/table/action extenders, settings schemasLeak admin state into public output.
FrontendPublic routes, render hooks, component aliases, frontend assets, cache invalidationQuery in Blade or render authoring markers.

Use one provider only when the package is small and safe in every context. Split providers when a package has install-only work, admin UI, or public rendering.

{
"providers": {
"runtime": ["Capell\\Example\\Providers\\ExampleServiceProvider"],
"admin": ["Capell\\Example\\Providers\\ExampleAdminServiceProvider"],
"frontend": [
"Capell\\Example\\Providers\\ExampleFrontendServiceProvider"
],
"install": ["Capell\\Example\\Providers\\ExampleInstallServiceProvider"]
}
}

Install providers should be safe before every package table exists. Admin providers can assume Filament/Admin is present. Frontend providers must be safe for anonymous requests and cached HTML.

CacheClear when
Laravel config/routes/viewsEnv, provider, route, config, or Blade changes.
Capell package cachecapell.json, package install state, provider bucket, or package metadata changes.
Admin configurator/widget cacheAdmin schema/configurator/widget registration changes.
Frontend/page cachePublic render data, route fallback, render hook, or invalidation changes.

Useful commands:

Terminal window
php artisan optimize:clear
php artisan capell:package-cache:clear
php artisan capell:admin-clear-cache
php artisan capell:html-cache:clear

Only use the commands that exist in the installed package set. Check with php artisan list capell.

SymptomLikely bucket mistakeFix
Package exists in Composer but not CapellManifest missing/invalid or package cache staleFix capell.json, run composer dump-autoload, clear package cache.
Admin resource loads on public requestsAdmin provider listed as runtime/frontendMove Filament registration into admin provider or AdminBridge.
Install command fails before tables existRuntime provider queries tables during installMove writes into install Actions and guard migrations.
Public page exposes package internalsFrontend provider/render hook outputs admin statePass only public render data and add safety tests.
Extension works in tests but not browserProvider boot order/cache differsRegister through documented registries/tags and clear relevant caches.
it('loads package metadata from the manifest', function (): void {
$package = CapellCore::getPackage('capell-app/example');
expect($package->name)->toBe('capell-app/example')
->and($package->hasFrontendScope())->toBeTrue();
});
it('does not register admin surfaces when the package is unavailable', function (): void {
CapellCore::forcePackageInstalled('capell-app/example', false);
expect(resolve(ExtensionPageRegistry::class)->get('capell-app/example'))->toBeNull();
});