Customer feedback, reviews and testimonials for Laravel. A triage and sentiment
layer built on top of whilesmart/eloquent-forms:
your app collects submissions through any feedback form it likes, and this
package turns the ones you care about into owner-scoped feedback with a
lifecycle you can act on.
- Forms collect, feedback interprets. You define feedback forms with
eloquent-forms(a bug report, an NPS prompt, a "leave a testimonial" box). A submission is raw input; a feedback record is a triageable item with a type, a status, a rating and a sentiment. - A form key maps to a feedback type.
config('feedback.forms')maps each form key to the kind of feedback its submissions become. When a mapped form is submitted, a listener creates aFeedbackrecord owned by the form's owner. Unmapped submissions are ignored (a plain contact form stays a submission, not feedback). - Ownership is polymorphic. Feedback belongs to an
ownermorph (a workspace, a product, a page) exactly like the rest of the WhileSmart packages. Access is enforced throughwhilesmart/eloquent-owner-access.
composer require whilesmart/eloquent-feedbackPublish the config to set up your form map:
php artisan vendor:publish --tag=feedback-config// config/feedback.php
'forms' => [
'bug-report' => 'bug',
'nps' => 'nps',
'testimonials' => 'testimonial',
],Owner-scoped (behind route_middleware):
GET /api/feedback— triage list, filter bytype,status,sentiment,is_public,qGET /api/feedback/summary— totals, average rating, NPS, breakdownsGET /api/feedback/{feedback}PATCH /api/feedback/{feedback}— move status, set sentiment/rating, publishDELETE /api/feedback/{feedback}
Public (behind public_middleware):
GET /api/testimonials?owner_type=&owner_id=— feedback the owner marked public
Sentiment is a seam. Out of the box nothing is inferred (NullSentimentAnalyzer).
Bind your own to classify feedback text as it arrives:
$this->app->bind(
\Whilesmart\Feedback\Contracts\SentimentAnalyzer::class,
\App\Feedback\LlmSentimentAnalyzer::class,
);FeedbackReceived— a submission became feedback. Bridge to notifications, CRM, Slack.FeedbackStatusChanged— the lifecycle moved. Carries the previous and new status.
Add the trait to any model that should own feedback:
use Whilesmart\Feedback\Traits\HasFeedback;
class Workspace extends Model
{
use HasFeedback; // $workspace->feedback
}