Charity and Admin UI
Modules/Charity/
├── app/Http/Controllers/{CharityController,PluginController,ThemeController}.php
├── resources/views/index.blade.php
├── resources/views/plugins/{index,show}.blade.php
├── resources/views/themes/index.blade.php
└── routes/web.php
Modules/Admin/
├── app/Http/Controllers/{AdminController,OrganizationController,PluginCatalogController}.php
├── resources/views/index.blade.php
├── resources/views/organizations/index.blade.php
├── resources/views/plugins/index.blade.php
└── routes/web.php
Charity plugin index synchronizes catalog, computes compatibility, lists driver dashboards, tenant assignments, and global state. Show merges defaults/settings. Update/toggle call PluginManager::configure() and return compatibility/definition/availability errors.
Appearance ensures default assignment, loads per-theme settings, and activates enum themes. Incompatible switches return form errors and preserve state.
The organization layout uses PluginDashboardResolver::groupsForOrganization(). Contributions from one plugin render beneath one expandable sidebar parent, with children ordered by PluginDashboard::$order. Index/overview and useful fixed-path shortcuts may be contributed—Events includes create-event. Parameterized show/edit/delete screens remain contextual.
The organization home receives pluginWidgets from PluginDashboardWidgetResolver and pluginDashboardGroups for its package cards. Widgets render in global order; each group card links to its first ordered dashboard. Widgets summarize and link to package dashboards; they must not duplicate full CRUD.
Plugin settings and package management are distinct surfaces. Settings stay at /charity/{organization}/plugins/{slug}. A package dashboard uses a non-colliding path such as /plugins/{slug}/manage; definition validation rejects a dashboard route ending at the settings URL.
Fundraising demonstrates the complete pattern: one sidebar group with overview, projects, donations, review queue, channels, supporters, and reports; organization-home metrics; contextual project/donation details; and a separate manifest-driven settings page.
For area="admin", the shared layout appends groups from PluginSuperAdminPageResolver::groupsForPlatform() and generates links without organization parameters. AdminController resolves ordered PluginSuperAdminWidget views for the platform home. Only globally installed and active plugins contribute.
Global /admin/plugins remains the read-only source/catalog comparison. It does not install, purge, enable, or configure packages. Operational Super Admin feature pages live on plugin-owned /admin/plugins/{slug}/manage routes; package lifecycle remains CLI-only and tenant configuration remains Charity-only.
Fundraising provides the reference global surface: aggregate widget, overview, all projects, and all donations. These pages are read-only and show organization identity; review actions and private proofs stay in the tenant dashboard.
Use contributed enum-icon named routes; keep catalog cards about identity/version/compatibility/states/settings/management links; authorize direct routes; show installed, active, enabled, and compatible separately.