mydnic/volet-feedback-messages-filament-plugin
A Filament plugin for managing and displaying feedback messages in Laravel admin panels. Add feedback workflows to your Filament resources with a simple, configurable interface.
Because this is a thin Filament wrapper around the Volet feedback API, you can have it rendering data in under five minutes if you already have Volet credentials.
composer require mydnic/volet-feedback-messages-filament-plugin
php artisan vendor:publish --tag="volet-feedback-messages-filament-plugin-config"
Grab an API token from your Volet workspace (Settings → API / Integrations), then add it to .env:
VOLEL_API_TOKEN=your-token-here
Register the plugin on the panel that should see feedback — usually your admin panel, not a customer-facing one:
// app/Providers/Filament/AdminPanelProvider.php
use Mydnic\VoletFeedbackMessagesFilamentPlugin\VoletFeedbackMessagesFilamentPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugin(VoletFeedbackMessagesFilamentPlugin::make());
}
Clear caches (php artisan config:clear && php artisan filament:optimize-clear if you've optimized) and log in. Look first at the navigation item the plugin registers (likely "Feedback" or "Volet Messages"). If you don't see it, check the plugin's README for the exact navigationGroup/navigationLabel methods — small plugins like this usually expose them as chainable plugin methods. The first real use case is almost always "show the latest N messages so support/product can triage without leaving the admin panel," so verify the default sort (usually newest-first) and date range before handing it to a team.
Register on one panel, expose to many. Treat the plugin as an admin-only surface. If you have a separate support or ops panel, register the plugin there too, but gate visibility with ->authorize() or the canView closure the plugin exposes so only staff with a view_feedback ability see it.
Tune navigation as plugin config, not code edits. The common chainable pattern lets you do:
VoletFeedbackMessagesFilamentPlugin::make()
->navigationGroup('Customer Voice')
->navigationLabel('Feedback Inbox')
->navigationIcon('heroicon-o-chat-bubble-left-right')
->navigationSort(20)
->navigationBadge(fn () => /* count of unread */ null);
Use the badge as a lightweight "new since last check" indicator rather than a live counter — hitting the Volet API on every page render is the classic mistake.
Widget on the dashboard for pulse, page for depth. If the plugin ships both a widget and a page, put the widget (latest 3–5 messages) on the dashboard for visibility, and use the full page for reading/responding. If it only ships a page, wrap its table in a custom widget with ->table() or link out to the page from your own dashboard widget.
Cache aggressively at the service layer. Volet won't thank you for a request per filter change. If the plugin doesn't cache by default, wrap the API call:
Cache::remember("volet.feedback.{$tenantId}.{$page}", now()->addMinutes(5), fn () => $client->messages(...));
Invalidate on a schedule (php artisan schedule:run job) rather than on every view.
Multi-tenant / multi-workspace. If you run Filament tenancy, the plugin needs the correct Volet workspace per tenant. Check whether it reads a tenant relationship or a global config key — if global, you'll need to instantiate the plugin per-panel or override the service binding so the token resolves from Filament::getTenant().
Extend the table rather than fork the page. Publish the view (vendor:publish --tag=...-views) and add columns or filters via the published table class or ->modifyQueryUsing(). Keep customisations in your app, not in vendor/.
composer.json require constraints before composer update in a live app; Filament minor bumps do break plugin pages. Lock the plugin version in composer.json explicitly.config:cache and env tokens. If you publish config and it reads env('VOLEL_API_TOKEN') at runtime, remember php artisan config:cache bakes it in. On deploy, ensure the env is present before caching, or store the token in a DB/secret manager and resolve at runtime.try/catch to null and render an empty list. Wrap the page action or add a health check: hit the Volet API from a scheduled command and alert if 401/403. A 401 almost always means an expired/rotated token, not a code bug.take() cap and a "load more" action.canView()/canAccess() exist on the plugin/page; if not, register the plugin conditionally (if (Auth::user()?->can('view_feedback'))) or wrap the page's mount in an abort_unless. Filament's panel-level auth doesn't automatically protect a third-party page.navigationSort collisions. If your admin panel already has many items, the plugin's default sort may bury it or push it to the top unexpectedly. Always set an explicit navigationSort.config(), plugin registered on the current panel (php artisan filament:about or Filament::getCurrentPanel()->getPlugin('...')), authorization closure, and network response from storage/logs/laravel.log (enable debug logging around the API call if it swallows exceptions).Http::withToken(...) call inside a stock Filament Resource or custom page is ~80 lines and gives you full control over caching, tenancy, and auth — worth weighing against the maintenance overhead of adding a dependency for this.How can I help you explore Laravel packages today?