Extension Troubleshooting
Use this when a package extension does not appear, does not run, or behaves differently between admin and public requests. Start with the smallest check that proves whether Capell can see the package, then move toward the specific runtime.
For focused debugging paths, use:
| Problem | Runbook |
|---|---|
| Composer, manifest, or provider discovery | Debugging package discovery |
| Admin pages, fields, actions, widgets, settings | Debugging admin extensions |
| Public output, cache bypasses, unsafe HTML | Debugging public output |
| Marketplace connection, verification, heartbeat | Debugging Marketplace |
First Checks
Section titled “First Checks”Run these before changing code:
composer dump-autoloadphp artisan optimize:clearphp artisan list capellphp artisan capell:package-cache:clearIf the package contributes admin configurators or widgets, also run:
php artisan capell:admin-clear-cachephp artisan capell:admin-cache-configuratorsphp artisan capell:admin-cache-widgetsConfirm the package service provider is loaded through Composer discovery, the host app’s provider list, or the package’s capell.json provider entries. A missing provider is the most common reason every downstream extension point appears broken.
Package Not Discovered
Section titled “Package Not Discovered”| Symptom | Likely cause | Check | Fix |
|---|---|---|---|
php artisan list capell does not show package commands | Composer autoload or provider discovery is stale | composer show capell-app/<package> and composer dump-autoload -o | Reinstall/update the package, fix composer.json autoload, then clear Laravel and Capell package caches. |
| Package appears in Composer but not in Capell package state | capell.json is missing, invalid, or not loaded | Inspect capell.json; run package manifest tests when available | Fix manifest name, providers, surfaces, and version constraints, then run php artisan capell:package-cache:clear. |
| Install/setup runs but package data is missing | Install command skipped settings migrations or package setup actions | Check package install command output and php artisan migrate:status | Register settings migrations and run setup through Actions rather than writing from providers. |
Admin Surface Missing
Section titled “Admin Surface Missing”| Symptom | Likely cause | Check | Fix |
|---|---|---|---|
| Resource/page/widget does not show in navigation | Contribution was not registered, permission denies access, or navigation is intentionally suppressed | Check the package admin provider, AdminBridge::register(), and the user’s permissions | Prefer AdminBridgeRegistrar::resource(), page(), widget(), or dashboardWidget(). Re-run capell:admin-install when permissions changed. |
| An Extensions page edit action is missing | The page was registered as a normal page instead of an extension page | Search for registerExtensionPage(...) | Register the package control page with CapellAdmin::registerExtensionPage($packageName, PageClass::class). |
| Dashboard widget is registered but disabled | Widgets are available but admin settings hide them | Check Admin settings and widget defaults | Use registerOverviewStat() for small metrics or enable the widget through Admin settings or setEnabledWidgets(). |
| Form fields are missing | Wrong extender tag, wrong hook enum, or configurator cache is stale | Check tags such as PageSchemaExtender::TAG and SiteSchemaExtender::TAG | Tag the extender in the provider or AdminBridgeRegistrar::schemaExtender(), then clear/cache admin configurators. |
| Header/table actions are missing | Extender targets the wrong surface | Check whether the target is page, site, resource, or Extensions page | Use the matching extender tag: PageHeaderActionExtender, SiteHeaderActionExtender, ResourceHeaderActionExtender, PageTableExtender, or ExtensionsPageActionRegistry. |
| User fields or relation managers are missing | User schema bridge/extender does not support the current context | Check UserSchemaExtender::supports() or the package UserResourceBridge::isEnabled() logic | Use AbstractUserSchemaExtender for no-op defaults, and test the resolver with the same user model/context used by the resource. |
| Publish panel content is missing | The package used a page schema extender instead of PublishPanelExtender | Search for PublishPanelExtender::TAG | Tag a PublishPanelExtender and return a View, HTML string, or null from extendPanel(). |
| Admin route works on one host but not another | CAPELL_ADMIN_PATH or CAPELL_ADMIN_DOMAIN is cached | php artisan config:show capell-admin.path and php artisan config:show capell-admin.domain | Update env/config and run php artisan optimize:clear. Signed preview URLs must be regenerated after host/path changes. |
Settings Page Missing
Section titled “Settings Page Missing”| Symptom | Likely cause | Check | Fix |
|---|---|---|---|
| Settings group is absent | Settings class or schema was not registered | Search for SettingsSchemaRegistry::registerSettingsClass() and register() | Register both the settings class and schema, or use AdminBridgeRegistrar::settingsClass() and settingsSchema(). |
| Settings page label/icon is generic | Metadata is missing | Search for registerMetadata(new SettingsGroupMetadata(...)) | Register metadata with translated labels and the correct group key. |
| Settings save fails on fresh installs | Settings migration did not run or is not idempotent | Check database/settings/ and install/setup command registration | Add guarded settings migrations and cover fresh install plus upgrade paths. |
| Settings appear in tests but not browser | Config/package cache is stale or provider boot order differs | Clear caches and inspect provider registration timing | Register settings in boot() or after resolving SettingsSchemaRegistry when package load order matters. |
Frontend Output Missing Or Unsafe
Section titled “Frontend Output Missing Or Unsafe”| Symptom | Likely cause | Check | Fix |
| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| Render hook output is absent | Wrong location, scenario, target, or provider timing | Search for RenderHookRegistry::register(...); compare location/scenario/target with the Blade call | Register in boot() and match the exact RenderHookLocation, scenario, and target used by the component. |
| Public page route catches package/admin URLs | Path was not reserved before the frontend fallback route | Inspect ReservedFrontendPathRegistry registrations and route order | Reserve exact paths or prefixes from the package provider, then clear route/config cache. |
| Public package route returns 404 | Route file/provider was not loaded or frontend fallback owns the path first | php artisan route:list | grep <path> | Load the package route provider and reserve the path if it should not fall through to page rendering. |
| Public page middleware runs in the wrong order | Package middleware was appended/prepended without considering frontend resolution | Inspect FrontendRouteMiddlewareRegistry::all() in a focused test | Use insertAfter() or insertBefore() around a known middleware instead of broad prepend/append. |
| Component alias resolves to a raw Blade name | Component was registered with Blade/Livewire but not FrontendComponentRegistry | Check FrontendComponentRegistryInterface::has() and hasReference() | Register a stable key and aliases through FrontendComponentRegistryInterface. |
| Frontend rule condition never matches | Condition key differs from the stored settings/runtime rule | Search for FrontendRuleCondition::key() and the stored rule key | Register the condition class and keep the key stable; cover it with a direct condition test. |
| HTML cache bypasses a page | Public output contains authoring markers, field paths, model IDs, package internals, or signed admin URLs | Check response headers for X-Frontend-Cache: BYPASS; inspect rendered HTML as anonymous user | Remove authoring state from public Blade. Frontend authoring must load after page load from an authenticated admin beacon. |
| Tailwind classes are missing | Package sources/imports were not registered or Vite cannot resolve a symlinked dependency | Run the frontend asset report command when installed; inspect TailwindAssetsRegistry::toReport() in tests | Register sources/imports through TailwindAssetsRegistry, install missing npm packages, or add a narrow Vite alias. |
| Page shows old content | Static HTML or fragment cache is stale | Check queue workers, public/page-cache, and cache invalidation registrations | Run php artisan capell:html-cache:clear; if using the HTML cache package, run php artisan capell:static-site; keep queue workers running. |
Cache Invalidation Not Running
Section titled “Cache Invalidation Not Running”| Symptom | Likely cause | Check | Fix |
|---|---|---|---|
| Model changes do not clear package output | The model was not registered with CacheInvalidationRegistry | Search for registerDependency(Model::class, ...) | Register exact cache keys where possible. Wildcard patterns intentionally flush the whole capell-frontend tag. |
| Invalidation works locally but not production | Queue worker, cache driver, or tag support differs | Check QUEUE_CONNECTION, cache driver, and worker logs | Use a supported cache driver for tagged cache behavior and run workers for async invalidation. |
| Fragment output remains stale | Fragment uses a different key/surrogate key than invalidation code | Compare @cache(...) keys with invalidation calls | Align surrogate keys and avoid ad hoc cache key construction in Blade. |
Marketplace Or Remote Package Issues
Section titled “Marketplace Or Remote Package Issues”| Symptom | Likely cause | Check | Fix |
|---|---|---|---|
| Package does not appear in browser installer | Composer cannot resolve it or manifest metadata is incomplete | composer show capell-app/<package> --available; inspect capell.json provider/scopes/kind | Fix Composer auth/repositories and manifest metadata, then clear package/config cache. |
| Package appears but cannot be selected with a theme | Theme key/package metadata is missing or requirements are unmet | Check kind, themeKey, extends, and requirements in capell.json | Keep theme metadata in the manifest and make the package installable before opening /install. |
| Install guide patch is missing | Patch was not registered in PatchRegistry or probe() says it is not applicable | Search registerPatches() and inspect the patch reason() | Register the patch, keep probe() idempotent, and cover the host-file state with a patch test. |
| Catalogue loads but install is blocked | Site is not connected or install authorization is denied by Capell App | Open Marketplace diagnostics and heartbeat state | Connect a Capell account, resolve diagnostics, then request authorization again. |
api/registration-sessions route is missing | Marketplace API URL uses the old unversioned path | php artisan config:show capell-marketplace.marketplace.base_url | Use https://capell.app/api/v1, then run php artisan config:clear. |
| Domain verification fails | Exact host mismatch, expired challenge, or public .well-known path blocked | Fetch the challenge URL from outside the server | Verify the exact production host, remove auth/CDN blocks, and restart verification. |
| Account linking callback fails | Stale approval URL, expired session, invalid state, or missing APP_URL host | Latest marketplace_account_connection_sessions.last_error | Set APP_URL, clear config, and start a fresh account connection from the same browser session. |
| Heartbeat fails after account linking | No public webhook URL, no instance, or Marketplace API unreachable | PhoneHomeAction::lastFailureMessage() and latest marketplace_instances row | Set CAPELL_MARKETPLACE_WEBHOOK_URL when needed, confirm network access, and run heartbeat again. |
When To Add A Test
Section titled “When To Add A Test”Add or update a focused test when the issue crossed one of these boundaries:
- package discovery, manifest validation, or install/setup behavior;
- admin resources, settings, widgets, extenders, permissions, or navigation;
- public rendering, route fallback, render hooks, cache output, or Tailwind assets;
- marketplace authorization, account linking, diagnostics, or domain verification.
For public output, test anonymous and non-admin responses directly. Cached/static HTML must match the same safe output and must not contain authoring markers, model IDs, field paths, selectors, signed admin URLs, or package internals.