Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Feedback Board Laravel Package

yousef-aman/laravel-feedback-board

yousef-aman/laravel-feedback-board provides a ready-to-use feedback and feature-request board for Laravel. Users can submit posts, upvote ideas, and comment, while admins moderate submissions and update statuses. Includes migrations, routes, controllers, and Blade views for quick setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and scaffold in two commands:

composer require yousefaman/laravel-feedback-board
php artisan feedback-board:install

The install command publishes the config (config/feedback-board.php) and the migrations for reports, comments, attachments and activity. Run php artisan migrate next. Nothing is enabled until you wire two things: a place to launch the form from, and a definition of who counts as a developer.

The first use case is the launcher. Drop the component into whatever layout renders for signed-in users:

{{-- resources/views/layouts/app.blade.php --}}
@auth
    <x-feedback-board::launcher />
@endauth

Guests render nothing at all, so it is safe to leave in a layout that also serves a login page — you don't need the @auth wrapper, but keeping it makes intent obvious.

Then decide who sees the board. Out of the box the package checks the feedback-board.manage gate, so the smallest working setup is a policy or a Gate::define in a service provider:

Gate::define('feedback-board.manage', fn (User $user) => $user->isStaff());

First thing to try after that: submit a report as a normal user, then open the board as a developer. Without Filament that is /feedback-board/feedback/board (route name feedback-board.board.page); the reporter's own list is /feedback-board/feedback (feedback-board.page). If you use Filament 4 or 5, register the plugin instead and skip the standalone routes entirely.

Files worth reading in the package before you customise anything: the published config (authorization, auth guards, destinations), the FeedbackBoard facade, and the migration stubs for the report table — the technical context column is what you'll be querying later if you build your own reporting.

Implementation Patterns

Filament panels as the default surface. Register the plugin in each panel provider where you want the board:

->plugin(FeedbackBoardPlugin::make()->myReports(false))

Inside a panel the package uses that panel's guard and primary colour, and its pages become panel pages in the navigation. ->myReports(false) is the usual choice for an internal-staff panel where everyone is a developer and the reporter page would just be noise. Reports are app-wide even on tenanted panels — do not expect tenant scoping.

Resolvers over gates for anything non-trivial. Two hooks do most of the work day to day:

FeedbackBoard::resolveDevelopersUsing(fn (User $u) => $u->hasRole('support'));
FeedbackBoard::resolveReportersUsing(fn (User $u) => $u->hasRole('client'));

Resolvers return booleans (or a gate Response); anything else denies. They run on every launcher render and every gate check, so keep them cheap — a role column, not a query per permission. Cache the result on the model if you must hit the database.

Multiple user populations. The common real-world shape is staff on web and customers on a client panel's own guard. Configure both lists and let the package resolve across them:

'auth' => [
    'guards' => ['web', 'clients'],
    'developer_guards' => ['web'],
],

FeedbackBoard::user() is the accessor to use in your own code, not auth()->user(), which only sees the default guard.

Destinations as an observability layer. Webhook, Slack and GitHub destinations are configured in the same file and delivered on a queue. The pattern that pays off is pointing the webhook at your existing ops pipeline (a signed endpoint that files into your own tracker) and using GitHub issue creation from the report dialog for the subset of reports that need engineering. Because deliveries are isolated per destination, a broken Slack token does not block GitHub issues.

Ingest for CI and bots. The HMAC-signed ingest endpoint is the clean way to close the loop: a deploy job comments "shipped in v2.3.1" on the report, or an agent runner posts analysis back. It is off by default; turn it on, then send signed JSON with no query string and a JSON content type. Set ingest.nonce_store to a shared cache store the moment you run more than one web node, otherwise signature replay protection is per-server.

AI triage as a triage aid, not a decision. Enable a provider, let the job suggest type and priority, and apply the fields one at a time from the card. Keep ai.queue set to a dedicated queue so a slow provider call never queues behind your transactional mail.

Gotchas and Tips

  • A Gate::before() hook can silently disable everything. The launcher and report creation both pass through the feedback-board.report gate, and a before hook that returns false for abilities it doesn't recognise hides the button with no error. If the launcher vanishes after you add a global gate hook, that's the cause.
  • Developer guards are restrictive, not additive. Once auth.developer_guards is set, nobody outside those guards is a developer regardless of what your resolver returns — the only escape hatch is Gate::before(). Guards whose providers share the same model class cannot be distinguished, so don't try to use two guards over one User model to separate staff from customers.
  • Config caching is supported, closures are not. The gate, resolver and destination settings are explicitly safe under php artisan config:cache, but a closure placed directly in the config file will not survive. Register resolvers in a service provider instead.
  • Resolvers that throw fail closed and are reported once. That is deliberate, but it means a typo in a resolver looks like "nobody can report" rather than an exception page. If the launcher disappears for everyone after a deploy, check the log for the one-time report before you check anything else.
  • Unread markers start at zero on first board visit. Only activity after a developer's first visit counts, so don't treat the bell as a historical backlog metric. The sidebar badge turns red off the same counter.
  • Image-only replies behave differently per destination. They produce a mail that says "a reply with images was added", post no GitHub comment (GitHub rejects empty bodies) and send body: "" on the webhook. If your webhook consumer assumes a non-empty body, it will break on exactly these.
  • Reporter content is quoted as code on GitHub to prevent mentions and /command injection. That is a feature — don't try to unescape it in your own integration. destinations.github.reporter_replies turns reporter replies off entirely if the noise outweighs the value.
  • Destination failure surfacing is split by Filament. Developers who are user models get a Filament bell entry; everyone else gets mail capped at one per destination and reason per day. If you are running without Filament and expect real-time alerting on a revoked token, the daily cap will disappoint you — monitor the failure state on the report instead.
  • Queue everything. Destinations retry at 30 s, 2 min and 5 min; triage jobs cap the provider call at 40 s with a 60 s job timeout. Without a running worker, reports still save but nothing is delivered, and it looks like a misconfiguration rather than a missing queue:work.
  • The board URL is the deep link. Notifications open the board for developers and "My reports" for reporters. If your reports live in a non-standard place — a helpdesk, an external tracker — set FeedbackBoard::linkReportsUsing() once rather than patching notification templates.
  • Renamed package, unchanged internals. The move to yousefaman/laravel-feedback-board left the namespace, config keys, routes and tables untouched. If you installed under an earlier name, swap the composer.json requirement; no migration or namespace rewrite is required.

Extension points worth knowing before you fork anything: FeedbackBoard::extendTriage() for a custom AI driver, destinations.* for delivery, and the gate/resolver pair for all authorisation. Most customisation requests land on one of those three.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource