liberusoftware/activity-comments
Add threaded comments to any Laravel activity log record. This package provides a lightweight comment model, migrations, and relationships so you can attach, nest, and retrieve discussions on logged events with minimal setup.
This is a low-adoption package (0 stars, 0 dependents), so treat the README and src/ as the source of truth rather than assuming Laravel-ecosystem conventions. The names below are illustrative; confirm namespaces, config keys, and method signatures against the repo before shipping.
Minimal setup
composer require liberusoftware/activity-comments
php artisan vendor:publish --provider="Liberu\ActivityComments\ActivityCommentsServiceProvider"
php artisan migrate
Then add the package trait to the models that author or receive activity:
use Liberu\ActivityComments\Traits\HasActivityComments;
class Post extends Model
{
use HasActivityComments;
}
class User extends Authenticatable
{
use HasActivityComments; // or the author/mentionable trait
}
Where to look first
README.md — install order, required traits, published config.config/activity-comments.php — model bindings, morph aliases, mention/notification drivers, visibility defaults.database/migrations/ — table names and polymorphic columns; run these before writing queries.src/Contracts/ — interfaces you can rebind (mention parser, visibility resolver, subscription manager).src/Traits/ — which trait belongs on the author vs. the commentable model.routes/ and src/Http/ — whether the package ships controllers/routes or expects you to wire your own.First use case
Attach a comment to a Post and render a timeline:
$post->comment(auth()->user(), 'Looks good — cc @jane');
$post->comments()->latest()->paginate(20);
If those methods don't exist verbatim, look for a service or action class (e.g. CommentService, ActivityManager) — this package family typically favors actions over model magic.
Commentable + author separation
Keep two concerns distinct: the model that owns a timeline (Post, Ticket, Project) and the model that acts (User). Apply the commentable trait to the former and the author/mentionable trait to the latter. Mixing them causes ambiguous morph targets.
Morph map early
Register stable aliases before the first insert. Changing them later orphans polymorphic rows:
// AppServiceProvider::boot()
Relation::morphMap([
'post' => \App\Models\Post::class,
'user' => \App\Models\User::class,
'ticket' => \App\Models\Ticket::class,
]);
Timeline queries
Treat timelines as read models. Scope by visibility, eager-load author and attachments, and paginate at the query level:
$timeline = $post->activityFeed()
->with(['author', 'attachments', 'mentions.user'])
->visibleTo(auth()->user())
->latest()
->cursorPaginate(25);
If visibleTo isn't provided, implement it as a local scope that delegates to the package's visibility contract.
Mentions
Parse on write, resolve on read. Store mention rows (user_id + comment_id) rather than re-parsing text on every render — it makes notification fan-out and permission checks tractable. If the package exposes a parser contract, bind your own for handles like @jane vs @jane@instance.
Subscriptions
Subscribe the author and all mentioned users on creation; unsubscribe on explicit user action only. Avoid subscribing on every edit — it produces duplicate rows and surprise notifications. De-duplicate with a unique index on (user_id, subscribable_type, subscribable_id).
Attachments
Decide early whether attachments use the package's storage abstraction or Laravel's filesystem/Media Library. If it's configurable, pin the disk in config ('disk' => 's3') rather than relying on the default. Store metadata (size, mime, original name) alongside the path.
Authorization
Wire policies per commentable model, and let the package's gate checks call them. Do not rely on middleware alone — comment visibility often needs to be enforced inside the query for list endpoints:
Gate::define('comment-on', fn (User $u, Post $p) => $u->can('update', $p));
Notifications
Push mention and reply notifications onto a queue. Synchronous fan-out on a comment with 50 mentions will block the request. Use an event listener on the package's comment-created event rather than overriding the service.
API surface
Expose comments as resources with stable shapes, and keep visibility filtering server-side. Returning a visibility field to the client is fine; trusting a client-supplied one is not.
composer.json and read the diff before upgrading. The last release date (2026-10-27) is a future-dated signal — verify the tag actually exists and matches composer.lock.HasComments/HasMentions traits may define comments(), mentions(), or subscribe(). Resolve with insteadof or rename in your wrapper.php artisan config:clear. Package configs read at boot won't reflect edits otherwise.->visibleTo() applied to the paginated query but not to counts, exports, or search endpoints. Centralize it in a repository or scope.[email protected]), and trailing punctuation will all produce false positives. Unit-test the parser with a fixture set.author, mentions.user, and attachments by default in a base query scope; a 25-item page without eager loading can easily become 100+ queries.CommentCreated, Mentioned, Subscribed. If it doesn't, wrap creation in your own action class so you have a hook.DB::listen() around a single comment creation is the fastest way to see what the package actually writes. php artisan tinker against the trait methods beats guessing from the README.CommentService so swapping implementations later is a one-file change.How can I help you explore Laravel packages today?