diff --git a/.gitignore b/.gitignore
index e7b81ec..c275dcb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,14 @@
-/vendor
-/node_modules
-/.phpunit.cache
+.DS_Store
+.idea
+.vscode
+.claude
+.phpunit.cache
.phpunit.result.cache
+build
composer.lock
+coverage
+node_modules
+phpunit.xml
+phpstan.neon
+testbench.yaml
+vendor
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..eb1625e
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d8d551c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,175 @@
+# Comments
+
+
+
+A full-featured commenting system for Filament panels with threaded replies, @mentions, emoji reactions, and real-time updates.
+
+[](https://packagist.org/packages/relaticle/comments)
+[](https://packagist.org/packages/relaticle/comments)
+[](https://php.net)
+[](https://laravel.com)
+[](https://github.com/relaticle/comments/actions)
+
+
+## Features
+
+- **Threaded Replies** - Nested comment threads with configurable depth limits
+- **@Mentions** - Autocomplete user mentions with customizable resolver
+- **Emoji Reactions** - 6 built-in reactions with configurable emoji sets
+- **File Attachments** - Image and document uploads with validation
+- **Notifications & Subscriptions** - Database and mail notifications with auto-subscribe
+- **3 Filament Integrations** - Slide-over action, table action, and infolist entry
+
+
+## Requirements
+
+- **PHP:** 8.2+
+- **Laravel:** 12+
+- **Livewire:** 3.5+ / 4.x
+- **Filament:** 4.x / 5.x
+
+
+## Installation
+
+```bash
+composer require relaticle/comments
+```
+
+Publish and run migrations:
+
+```bash
+php artisan vendor:publish --tag=comments-migrations
+php artisan migrate
+```
+
+## Usage
+
+### Set Up Your Models
+
+Add the commenting traits to your models:
+
+```php
+use Relaticle\Comments\Concerns\HasComments;
+use Relaticle\Comments\Contracts\Commentable;
+
+class Project extends Model implements Commentable
+{
+ use HasComments;
+}
+```
+
+Add the commenter trait to your User model:
+
+```php
+use Relaticle\Comments\Concerns\IsCommenter;
+use Relaticle\Comments\Contracts\Commenter;
+
+class User extends Authenticatable implements Commenter
+{
+ use IsCommenter;
+}
+```
+
+### Register the Filament Plugin
+
+```php
+use Relaticle\Comments\CommentsPlugin;
+
+public function panel(Panel $panel): Panel
+{
+ return $panel
+ ->plugins([
+ CommentsPlugin::make(),
+ ]);
+}
+```
+
+### Add Comments to Your Resources
+
+Use the slide-over action on view/edit pages:
+
+```php
+use Relaticle\Comments\Filament\Actions\CommentsAction;
+
+protected function getHeaderActions(): array
+{
+ return [
+ CommentsAction::make(),
+ ];
+}
+```
+
+Or add as a table action:
+
+```php
+use Relaticle\Comments\Filament\Actions\CommentsTableAction;
+
+public static function table(Table $table): Table
+{
+ return $table
+ ->actions([
+ CommentsTableAction::make(),
+ ]);
+}
+```
+
+Or embed in an infolist:
+
+```php
+use Relaticle\Comments\Filament\Infolists\Components\CommentsEntry;
+
+public static function infolist(Infolist $infolist): Infolist
+{
+ return $infolist->schema([
+ CommentsEntry::make('comments'),
+ ]);
+}
+```
+
+**[View Complete Documentation ->](https://relaticle.github.io/comments/)**
+
+## Our Ecosystem
+
+
+
+
+
+### FilaForms
+[ ](https://filaforms.app/)
+
+Visual form builder for all your public-facing forms.
+[Learn more ->](https://filaforms.app)
+
+ |
+
+
+### Custom Fields
+[ ](https://relaticle.github.io/custom-fields)
+
+Let users add custom fields to any model without code changes.
+[Learn more ->](https://relaticle.github.io/custom-fields)
+
+ |
+
+
+
+
+### Flowforge
+[ ](https://relaticle.github.io/flowforge)
+
+Transform any Laravel model into a drag-and-drop Kanban board.
+[Learn more ->](https://relaticle.github.io/flowforge)
+
+ |
+
+ |
+
+
+
+## Contributing
+
+Contributions are welcome! Please feel free to submit a Pull Request.
+
+## License
+
+MIT License. See [LICENSE](LICENSE) for details.
diff --git a/art/preview.png b/art/preview.png
new file mode 100644
index 0000000..0095c5c
Binary files /dev/null and b/art/preview.png differ
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 0000000..35867a1
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,5 @@
+node_modules
+.output
+.nuxt
+dist
+.env
diff --git a/docs/app.config.ts b/docs/app.config.ts
new file mode 100644
index 0000000..fdce6bc
--- /dev/null
+++ b/docs/app.config.ts
@@ -0,0 +1,64 @@
+export default defineAppConfig({
+ docus: {
+ title: 'Comments',
+ description: 'A full-featured commenting system for Filament panels with threaded replies, @mentions, emoji reactions, and real-time updates.',
+ header: {
+ logo: {
+ alt: 'Comments Logo',
+ }
+ }
+ },
+ seo: {
+ title: 'Comments',
+ description: 'A full-featured commenting system for Filament panels with threaded replies, @mentions, emoji reactions, and real-time updates.',
+ },
+ github: {
+ repo: 'comments',
+ owner: 'Relaticle',
+ edit: true,
+ rootDir: 'docs'
+ },
+ socials: {
+ discord: 'https://discord.gg/b9WxzUce4Q'
+ },
+ ui: {
+ colors: {
+ primary: 'violet',
+ neutral: 'zinc'
+ }
+ },
+ uiPro: {
+ pageHero: {
+ slots: {
+ container: 'flex flex-col lg:grid py-16 sm:py-20 lg:py-24 gap-16 sm:gap-y-2'
+ }
+ }
+ },
+ toc: {
+ title: 'On this page',
+ bottom: {
+ title: 'Ecosystem',
+ edit: 'https://github.com/Relaticle/comments',
+ links: [
+ {
+ icon: 'i-simple-icons-laravel',
+ label: 'FilaForms',
+ to: 'https://filaforms.app',
+ target: '_blank'
+ },
+ {
+ icon: 'i-lucide-sliders',
+ label: 'Custom Fields',
+ to: 'https://relaticle.github.io/custom-fields',
+ target: '_blank'
+ },
+ {
+ icon: 'i-lucide-kanban',
+ label: 'Flowforge',
+ to: 'https://relaticle.github.io/flowforge',
+ target: '_blank'
+ }
+ ]
+ }
+ }
+})
diff --git a/docs/content/1.getting-started/.navigation.yml b/docs/content/1.getting-started/.navigation.yml
new file mode 100644
index 0000000..6dca48e
--- /dev/null
+++ b/docs/content/1.getting-started/.navigation.yml
@@ -0,0 +1,2 @@
+title: Getting Started
+icon: false
diff --git a/docs/content/1.getting-started/1.introduction.md b/docs/content/1.getting-started/1.introduction.md
new file mode 100644
index 0000000..eac9e41
--- /dev/null
+++ b/docs/content/1.getting-started/1.introduction.md
@@ -0,0 +1,52 @@
+---
+title: Introduction
+description: A full-featured commenting system for Filament panels.
+navigation:
+ icon: i-lucide-home
+seo:
+ title: Introduction
+ description: Learn about Comments - a full-featured commenting system for Filament panels with threaded replies, @mentions, emoji reactions, and real-time updates.
+ ogImage: /preview.png
+---
+
+Welcome to **Comments**, a powerful Laravel package that adds a full-featured commenting system to any Filament panel.
+
+## What is Comments?
+
+Comments provides polymorphic commenting on any Eloquent model with deep Filament integration. Add threaded discussions, @mentions, emoji reactions, file attachments, and real-time notifications to your admin panel with minimal setup.
+
+## Why Choose Comments?
+
+::card-group
+ :::card
+ ---
+ icon: i-lucide-messages-square
+ title: Threaded Discussions
+ ---
+ Nested replies with configurable depth limits keep conversations organized and easy to follow.
+ :::
+
+ :::card
+ ---
+ icon: i-lucide-clock
+ title: Quick Setup
+ ---
+ Add traits to your models, register the plugin, and you have a working comment system in minutes.
+ :::
+
+ :::card
+ ---
+ icon: i-lucide-puzzle
+ title: 3 Integration Patterns
+ ---
+ Use as a slide-over action, table row action, or inline infolist entry - whatever fits your resource.
+ :::
+
+ :::card
+ ---
+ icon: i-lucide-bell
+ title: Built-in Notifications
+ ---
+ Database and mail notifications with subscription management and auto-subscribe for authors and mentioned users.
+ :::
+::
diff --git a/docs/content/1.getting-started/2.installation.md b/docs/content/1.getting-started/2.installation.md
new file mode 100644
index 0000000..d30479c
--- /dev/null
+++ b/docs/content/1.getting-started/2.installation.md
@@ -0,0 +1,112 @@
+---
+title: Installation
+description: Get started with Comments in minutes.
+navigation:
+ icon: i-lucide-download
+seo:
+ description: Install Comments and add commenting to your Filament resources.
+ ogImage: /preview.png
+---
+
+## Requirements
+
+- **PHP:** 8.2+
+- **Laravel:** 12+
+- **Filament:** 4.x / 5.x
+- **Livewire:** 3.5+ / 4.x
+
+## Quick Setup
+
+::steps
+### Install Package
+
+```bash [Terminal]
+composer require relaticle/comments
+```
+
+### Publish and Run Migrations
+
+```bash [Terminal]
+php artisan vendor:publish --tag=comments-migrations
+php artisan migrate
+```
+
+### Include CSS Assets
+
+Prerequisite: You need a custom Filament theme to include the Comments styles.
+
+::alert{type="warning"}
+If you haven't set up a custom theme for Filament, follow the [Filament Docs](https://filamentphp.com/docs/5.x/styling/overview#creating-a-custom-theme) first.
+::
+
+Add the plugin's views to your theme CSS file:
+
+```css [resources/css/filament/admin/theme.css]
+@source "../../../../vendor/relaticle/comments/resources/views/**/*.blade.php";
+```
+
+### Register the Plugin
+
+```php [AdminPanelProvider.php]
+use Relaticle\Comments\CommentsPlugin;
+
+public function panel(Panel $panel): Panel
+{
+ return $panel
+ ->plugins([
+ CommentsPlugin::make(),
+ ]);
+}
+```
+
+### Set Up Your Models
+
+Add the `HasComments` trait to any model you want to comment on:
+
+```php [app/Models/Project.php]
+use Relaticle\Comments\Concerns\HasComments;
+use Relaticle\Comments\Contracts\Commentable;
+
+class Project extends Model implements Commentable
+{
+ use HasComments;
+}
+```
+
+Add the `IsCommenter` trait to your User model:
+
+```php [app/Models/User.php]
+use Relaticle\Comments\Concerns\IsCommenter;
+use Relaticle\Comments\Contracts\Commenter;
+
+class User extends Authenticatable implements Commenter
+{
+ use IsCommenter;
+}
+```
+
+### Add to Your Resources
+
+Use the slide-over action on view or edit pages:
+
+```php [app/Filament/Resources/ProjectResource/Pages/ViewProject.php]
+use Relaticle\Comments\Filament\Actions\CommentsAction;
+
+protected function getHeaderActions(): array
+{
+ return [
+ CommentsAction::make(),
+ ];
+}
+```
+::
+
+**Done!** Visit your Filament panel to see comments in action.
+
+## Optional Configuration
+
+| Command | Action |
+|---------|--------|
+| `php artisan vendor:publish --tag=comments-config` | Publish the configuration file |
+| `php artisan vendor:publish --tag=comments-views` | Publish the Blade views for customization |
+| `php artisan vendor:publish --tag=comments-translations` | Publish the translation files |
diff --git a/docs/content/1.getting-started/3.upgrading.md b/docs/content/1.getting-started/3.upgrading.md
new file mode 100644
index 0000000..a816168
--- /dev/null
+++ b/docs/content/1.getting-started/3.upgrading.md
@@ -0,0 +1,12 @@
+---
+title: Upgrading
+description: Upgrade guide for Comments.
+navigation:
+ icon: i-lucide-arrow-up-circle
+seo:
+ description: How to upgrade Comments between versions.
+---
+
+## 1.x
+
+This is the initial release of Comments. Future upgrade guides will be documented here as new versions are released.
diff --git a/docs/content/2.essentials/.navigation.yml b/docs/content/2.essentials/.navigation.yml
new file mode 100644
index 0000000..b82ae3f
--- /dev/null
+++ b/docs/content/2.essentials/.navigation.yml
@@ -0,0 +1 @@
+title: Essentials
diff --git a/docs/content/2.essentials/1.configuration.md b/docs/content/2.essentials/1.configuration.md
new file mode 100644
index 0000000..1e8dc8e
--- /dev/null
+++ b/docs/content/2.essentials/1.configuration.md
@@ -0,0 +1,189 @@
+---
+title: Configuration
+description: Configure threading, reactions, mentions, attachments, notifications, and more.
+navigation:
+ icon: i-lucide-settings
+seo:
+ description: Complete configuration reference for the Comments package.
+---
+
+Publish the configuration file:
+
+```bash
+php artisan vendor:publish --tag=comments-config
+```
+
+This creates `config/comments.php` with all available options.
+
+## Table Name
+
+```php
+'tables' => [
+ 'comments' => 'comments',
+],
+```
+
+Change the table name if it conflicts with your application.
+
+## Models
+
+```php
+'models' => [
+ 'comment' => \Relaticle\Comments\Comment::class,
+],
+
+'commenter' => [
+ 'model' => \App\Models\User::class,
+],
+```
+
+Override the Comment model to add custom behavior. The commenter model defines which class represents the user who comments.
+
+## Policy
+
+```php
+'policy' => \Relaticle\Comments\Policies\CommentPolicy::class,
+```
+
+See the [Authorization](/essentials/authorization) page for customization details.
+
+## Threading
+
+```php
+'threading' => [
+ 'max_depth' => 2,
+],
+```
+
+Controls how many levels of nested replies are allowed. A depth of `2` means top-level comments and one level of replies. Set to `1` to disable replies entirely.
+
+## Pagination
+
+```php
+'pagination' => [
+ 'per_page' => 10,
+],
+```
+
+Number of comments loaded initially and per "Load More" click.
+
+## Reactions
+
+```php
+'reactions' => [
+ 'emoji_set' => [
+ 'thumbs_up' => "\u{1F44D}",
+ 'heart' => "\u{2764}\u{FE0F}",
+ 'celebrate' => "\u{1F389}",
+ 'laugh' => "\u{1F604}",
+ 'thinking' => "\u{1F914}",
+ 'sad' => "\u{1F622}",
+ ],
+],
+```
+
+Customize the available emoji reactions. Keys are used as identifiers in the database, values are the displayed emoji characters.
+
+## Mentions
+
+```php
+'mentions' => [
+ 'resolver' => \Relaticle\Comments\Mentions\DefaultMentionResolver::class,
+ 'max_results' => 5,
+],
+```
+
+The resolver handles searching for users during @mention autocomplete. See the [Mentions](/essentials/mentions) page for creating a custom resolver.
+
+## Editor Toolbar
+
+```php
+'editor' => [
+ 'toolbar' => [
+ ['bold', 'italic', 'strike', 'link'],
+ ['bulletList', 'orderedList'],
+ ['codeBlock'],
+ ],
+],
+```
+
+Defines which formatting buttons appear in the comment editor. Groups create visual separators in the toolbar.
+
+## Notifications
+
+```php
+'notifications' => [
+ 'channels' => ['database'],
+ 'enabled' => true,
+],
+```
+
+Add `'mail'` to the channels array to send email notifications. Set `enabled` to `false` to disable all notifications.
+
+## Subscriptions
+
+```php
+'subscriptions' => [
+ 'auto_subscribe' => true,
+],
+```
+
+When enabled, users are automatically subscribed to a thread when they create a comment or are mentioned. They receive notifications for subsequent replies.
+
+## Attachments
+
+```php
+'attachments' => [
+ 'enabled' => true,
+ 'disk' => 'public',
+ 'max_size' => 10240, // KB
+ 'allowed_types' => [
+ 'image/jpeg',
+ 'image/png',
+ 'image/gif',
+ 'image/webp',
+ 'application/pdf',
+ 'text/plain',
+ 'application/msword',
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ ],
+],
+```
+
+Controls file upload behavior. Set `enabled` to `false` to remove the attachment UI entirely. The `max_size` is in kilobytes (default 10 MB).
+
+## Broadcasting
+
+```php
+'broadcasting' => [
+ 'enabled' => false,
+ 'channel_prefix' => 'comments',
+],
+```
+
+When enabled, comment events are broadcast on private channels using the format `{prefix}.{commentable_type}.{commentable_id}`. Requires Laravel Echo and a broadcasting driver.
+
+## Polling
+
+```php
+'polling' => [
+ 'interval' => '10s',
+],
+```
+
+When broadcasting is disabled, the Livewire component polls for new comments at this interval. Set to `null` to disable polling.
+
+## Custom User Resolution
+
+Override how the authenticated user is resolved:
+
+```php
+use Relaticle\Comments\Config;
+
+// In AppServiceProvider::boot()
+Config::resolveAuthenticatedUserUsing(function () {
+ return auth()->user();
+});
+```
+
+This is useful for multi-guard applications or custom authentication flows.
diff --git a/docs/content/2.essentials/2.authorization.md b/docs/content/2.essentials/2.authorization.md
new file mode 100644
index 0000000..551f289
--- /dev/null
+++ b/docs/content/2.essentials/2.authorization.md
@@ -0,0 +1,74 @@
+---
+title: Authorization
+description: Control who can create, edit, delete, and reply to comments.
+navigation:
+ icon: i-lucide-shield
+seo:
+ description: Configure comment authorization policies.
+---
+
+## Default Policy
+
+The built-in `CommentPolicy` provides sensible defaults:
+
+| Method | Default | Description |
+|--------|---------|-------------|
+| `viewAny()` | `true` | Everyone can view comments |
+| `create()` | `true` | Everyone can create comments |
+| `update()` | Owner only | Only the comment author can edit |
+| `delete()` | Owner only | Only the comment author can delete |
+| `reply()` | Depth check | Can reply if `max_depth` not exceeded |
+
+## Custom Policy
+
+Create your own policy to customize authorization:
+
+```php
+namespace App\Policies;
+
+use Relaticle\Comments\Comment;
+use Relaticle\Comments\Contracts\Commenter;
+
+class CustomCommentPolicy
+{
+ public function viewAny(Commenter $user): bool
+ {
+ return true;
+ }
+
+ public function create(Commenter $user): bool
+ {
+ return true;
+ }
+
+ public function update(Commenter $user, Comment $comment): bool
+ {
+ return $comment->user_id === $user->getKey()
+ && $comment->user_type === $user->getMorphClass();
+ }
+
+ public function delete(Commenter $user, Comment $comment): bool
+ {
+ return $comment->user_id === $user->getKey()
+ || $user->hasRole('admin');
+ }
+
+ public function reply(Commenter $user, Comment $comment): bool
+ {
+ return $comment->canReply();
+ }
+}
+```
+
+Register it in your config:
+
+```php
+// config/comments.php
+'policy' => App\Policies\CustomCommentPolicy::class,
+```
+
+## How Authorization Works
+
+The Livewire components check the policy before rendering action buttons. Edit and delete buttons only appear for authorized users. Reply buttons are hidden when the thread has reached the configured `max_depth`.
+
+The policy is registered automatically by the service provider using Laravel's Gate system.
diff --git a/docs/content/2.essentials/3.mentions.md b/docs/content/2.essentials/3.mentions.md
new file mode 100644
index 0000000..e6d851c
--- /dev/null
+++ b/docs/content/2.essentials/3.mentions.md
@@ -0,0 +1,74 @@
+---
+title: Mentions
+description: User @mentions with autocomplete and notification support.
+navigation:
+ icon: i-lucide-at-sign
+seo:
+ description: Configure @mention autocomplete and create custom mention resolvers.
+---
+
+## How Mentions Work
+
+Type `@` in the comment editor to trigger user autocomplete. Select a user to insert a mention. When the comment is saved, the `MentionParser` extracts mentions and:
+
+1. Syncs mention records in the `comment_mentions` table
+2. Dispatches a `UserMentioned` event for each newly mentioned user
+3. The `SendUserMentionedNotification` listener sends notifications
+4. If auto-subscribe is enabled, mentioned users are subscribed to the thread
+
+## Default Resolver
+
+The `DefaultMentionResolver` searches the commenter model by name:
+
+```php
+// Searches: User::where('name', 'like', "{$query}%")
+// Limited to: config('comments.mentions.max_results') results
+```
+
+## Custom Mention Resolver
+
+Implement the `MentionResolver` interface to customize user search behavior:
+
+```php
+namespace App\Comments;
+
+use Illuminate\Support\Collection;
+use Relaticle\Comments\Contracts\MentionResolver;
+
+class TeamMentionResolver implements MentionResolver
+{
+ public function search(string $query): Collection
+ {
+ return User::query()
+ ->where('team_id', auth()->user()->team_id)
+ ->where('name', 'like', "{$query}%")
+ ->limit(config('comments.mentions.max_results'))
+ ->get();
+ }
+
+ public function resolveByNames(array $names): Collection
+ {
+ return User::query()
+ ->where('team_id', auth()->user()->team_id)
+ ->whereIn('name', $names)
+ ->get();
+ }
+}
+```
+
+Register it in your config:
+
+```php
+// config/comments.php
+'mentions' => [
+ 'resolver' => App\Comments\TeamMentionResolver::class,
+ 'max_results' => 5,
+],
+```
+
+## Configuration
+
+| Key | Default | Description |
+|-----|---------|-------------|
+| `mentions.resolver` | `DefaultMentionResolver::class` | User search implementation |
+| `mentions.max_results` | `5` | Maximum autocomplete results |
diff --git a/docs/content/2.essentials/4.reactions.md b/docs/content/2.essentials/4.reactions.md
new file mode 100644
index 0000000..c972179
--- /dev/null
+++ b/docs/content/2.essentials/4.reactions.md
@@ -0,0 +1,51 @@
+---
+title: Reactions
+description: Emoji reactions on comments.
+navigation:
+ icon: i-lucide-smile
+seo:
+ description: Configure emoji reactions for comments.
+---
+
+## Default Reactions
+
+Six emoji reactions are available out of the box:
+
+| Key | Emoji | Label |
+|-----|-------|-------|
+| `thumbs_up` | :thumbsup: | Like |
+| `heart` | :heart: | Love |
+| `celebrate` | :tada: | Celebrate |
+| `laugh` | :smile: | Laugh |
+| `thinking` | :thinking: | Thinking |
+| `sad` | :cry: | Sad |
+
+## How Reactions Work
+
+- Each user can add one reaction of each type per comment
+- Clicking the same reaction again removes it (toggle behavior)
+- The reaction summary shows which users reacted with each emoji
+- A `CommentReacted` event is dispatched with `action: 'added'` or `'removed'`
+
+## Customizing Reactions
+
+Override the emoji set in your config:
+
+```php
+// config/comments.php
+'reactions' => [
+ 'emoji_set' => [
+ 'thumbs_up' => "\u{1F44D}",
+ 'thumbs_down' => "\u{1F44E}",
+ 'heart' => "\u{2764}\u{FE0F}",
+ 'fire' => "\u{1F525}",
+ 'eyes' => "\u{1F440}",
+ ],
+],
+```
+
+Keys are stored in the database. If you change a key, existing reactions with the old key will no longer display.
+
+## Storage
+
+Reactions are stored in the `comment_reactions` table with a unique constraint on `(comment_id, user_id, user_type, reaction)`, ensuring one reaction of each type per user per comment.
diff --git a/docs/content/2.essentials/5.attachments.md b/docs/content/2.essentials/5.attachments.md
new file mode 100644
index 0000000..04005d7
--- /dev/null
+++ b/docs/content/2.essentials/5.attachments.md
@@ -0,0 +1,72 @@
+---
+title: Attachments
+description: File uploads for comments.
+navigation:
+ icon: i-lucide-paperclip
+seo:
+ description: Configure file attachments for comments.
+---
+
+## Overview
+
+Comments support file attachments for both images and documents. Images are displayed inline within the comment body, while documents appear as downloadable links.
+
+## Configuration
+
+```php
+// config/comments.php
+'attachments' => [
+ 'enabled' => true,
+ 'disk' => 'public',
+ 'max_size' => 10240, // KB (10 MB)
+ 'allowed_types' => [
+ 'image/jpeg',
+ 'image/png',
+ 'image/gif',
+ 'image/webp',
+ 'application/pdf',
+ 'text/plain',
+ 'application/msword',
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ ],
+],
+```
+
+| Key | Default | Description |
+|-----|---------|-------------|
+| `enabled` | `true` | Show/hide the attachment upload UI |
+| `disk` | `'public'` | Laravel filesystem disk for storage |
+| `max_size` | `10240` | Maximum file size in kilobytes |
+| `allowed_types` | images, pdf, text, word | Array of allowed MIME types |
+
+## Disabling Attachments
+
+```php
+'attachments' => [
+ 'enabled' => false,
+],
+```
+
+This removes the file upload UI from the comment form entirely.
+
+## Storage
+
+Attachments are stored via Livewire's file upload mechanism. Each attachment record tracks:
+
+- `file_path` -- Path on the configured disk
+- `original_name` -- Original filename for display
+- `mime_type` -- MIME type for rendering decisions
+- `size` -- File size in bytes
+- `disk` -- Storage disk name
+
+When a comment is deleted, its attachments are cascade deleted from the database. The physical files are removed from the disk.
+
+## Helper Methods
+
+The `CommentAttachment` model provides:
+
+```php
+$attachment->isImage(); // Check if attachment is an image
+$attachment->url(); // Get the storage URL
+$attachment->formattedSize(); // Human-readable size (e.g., "2.5 MB")
+```
diff --git a/docs/content/2.essentials/6.notifications.md b/docs/content/2.essentials/6.notifications.md
new file mode 100644
index 0000000..4f0700f
--- /dev/null
+++ b/docs/content/2.essentials/6.notifications.md
@@ -0,0 +1,125 @@
+---
+title: Notifications
+description: Comment notifications, subscriptions, and real-time updates.
+navigation:
+ icon: i-lucide-bell
+seo:
+ description: Configure comment notifications, subscriptions, broadcasting, and polling.
+---
+
+## Notification Types
+
+Two notification classes are included:
+
+### CommentRepliedNotification
+
+Sent to all thread subscribers when a new comment or reply is posted. The comment author is excluded from receiving their own notification.
+
+### UserMentionedNotification
+
+Sent to a user when they are @mentioned in a comment. Self-mentions are ignored.
+
+## Channels
+
+```php
+// config/comments.php
+'notifications' => [
+ 'channels' => ['database'],
+ 'enabled' => true,
+],
+```
+
+Available channels: `'database'` and `'mail'`. Add both to send email notifications alongside database notifications:
+
+```php
+'notifications' => [
+ 'channels' => ['database', 'mail'],
+ 'enabled' => true,
+],
+```
+
+## Subscriptions
+
+Users can subscribe to comment threads on any commentable model. Subscribers receive notifications when new comments are posted.
+
+### Auto-Subscribe
+
+```php
+'subscriptions' => [
+ 'auto_subscribe' => true,
+],
+```
+
+When enabled:
+- Users are auto-subscribed when they post a comment
+- Users are auto-subscribed when they are @mentioned
+
+### Manual Subscription
+
+Users can toggle their subscription using the subscribe/unsubscribe button in the comments UI.
+
+### Programmatic Access
+
+```php
+use Relaticle\Comments\CommentSubscription;
+
+// Check subscription status
+CommentSubscription::isSubscribed($commentable, $user);
+
+// Subscribe/unsubscribe
+CommentSubscription::subscribe($commentable, $user);
+CommentSubscription::unsubscribe($commentable, $user);
+
+// Get all subscribers for a commentable
+$subscribers = CommentSubscription::subscribersFor($commentable);
+```
+
+## Events
+
+| Event | Trigger | Broadcasts |
+|-------|---------|------------|
+| `CommentCreated` | New comment or reply | Yes |
+| `CommentUpdated` | Comment edited | Yes |
+| `CommentDeleted` | Comment soft-deleted | Yes |
+| `CommentReacted` | Reaction added/removed | Yes |
+| `UserMentioned` | User @mentioned | No |
+
+## Real-time Updates
+
+### Broadcasting
+
+Enable broadcasting for instant updates across browser sessions:
+
+```php
+// config/comments.php
+'broadcasting' => [
+ 'enabled' => true,
+ 'channel_prefix' => 'comments',
+],
+```
+
+Events are broadcast on private channels: `{prefix}.{commentable_type}.{commentable_id}`
+
+This requires Laravel Echo and a broadcasting driver (Pusher, Ably, etc.) configured in your application.
+
+### Polling Fallback
+
+When broadcasting is disabled, the Livewire component polls for updates:
+
+```php
+'polling' => [
+ 'interval' => '10s',
+],
+```
+
+Set to `null` to disable polling entirely.
+
+## Disabling Notifications
+
+```php
+'notifications' => [
+ 'enabled' => false,
+],
+```
+
+This disables all notification dispatching. Subscriptions and events still work, but no notifications are sent.
diff --git a/docs/content/2.essentials/7.database-schema.md b/docs/content/2.essentials/7.database-schema.md
new file mode 100644
index 0000000..ece9978
--- /dev/null
+++ b/docs/content/2.essentials/7.database-schema.md
@@ -0,0 +1,107 @@
+---
+title: Database Schema
+description: Tables, relationships, and indexes used by the Comments package.
+navigation:
+ icon: i-lucide-database
+seo:
+ description: Database schema reference for the Comments package.
+---
+
+## Tables
+
+Five tables are created by the package migrations.
+
+### comments
+
+The main comments table with polymorphic relationships and threading support.
+
+| Column | Type | Description |
+|--------|------|-------------|
+| `id` | bigint | Primary key |
+| `commentable_type` | string | Polymorphic model type |
+| `commentable_id` | bigint | Polymorphic model ID |
+| `user_type` | string | Commenter model type |
+| `user_id` | bigint | Commenter model ID |
+| `parent_id` | bigint (nullable) | Parent comment for replies |
+| `body` | text | HTML comment content |
+| `edited_at` | timestamp (nullable) | When the comment was last edited |
+| `deleted_at` | timestamp (nullable) | Soft delete timestamp |
+| `created_at` | timestamp | |
+| `updated_at` | timestamp | |
+
+**Indexes:** `(commentable_type, commentable_id, parent_id)`
+
+### comment_reactions
+
+Tracks emoji reactions per user per comment.
+
+| Column | Type | Description |
+|--------|------|-------------|
+| `id` | bigint | Primary key |
+| `comment_id` | bigint | Foreign key to comments |
+| `user_type` | string | Reactor model type |
+| `user_id` | bigint | Reactor model ID |
+| `reaction` | string | Reaction key (e.g., `thumbs_up`) |
+| `created_at` | timestamp | |
+
+**Unique constraint:** `(comment_id, user_id, user_type, reaction)`
+
+### comment_mentions
+
+Tracks @mentioned users per comment.
+
+| Column | Type | Description |
+|--------|------|-------------|
+| `id` | bigint | Primary key |
+| `comment_id` | bigint | Foreign key to comments |
+| `user_type` | string | Mentioned user model type |
+| `user_id` | bigint | Mentioned user model ID |
+| `created_at` | timestamp | |
+
+**Unique constraint:** `(comment_id, user_id, user_type)`
+
+### comment_subscriptions
+
+Tracks which users are subscribed to comment threads on specific models.
+
+| Column | Type | Description |
+|--------|------|-------------|
+| `id` | bigint | Primary key |
+| `commentable_type` | string | Subscribed model type |
+| `commentable_id` | bigint | Subscribed model ID |
+| `user_type` | string | Subscriber model type |
+| `user_id` | bigint | Subscriber model ID |
+| `created_at` | timestamp | |
+
+**Unique constraint:** `(commentable_type, commentable_id, user_type, user_id)`
+
+### comment_attachments
+
+Stores file attachment metadata for comments.
+
+| Column | Type | Description |
+|--------|------|-------------|
+| `id` | bigint | Primary key |
+| `comment_id` | bigint | Foreign key to comments |
+| `file_path` | string | Path on the storage disk |
+| `original_name` | string | Original uploaded filename |
+| `mime_type` | string | File MIME type |
+| `size` | bigint | File size in bytes |
+| `disk` | string | Laravel filesystem disk |
+| `created_at` | timestamp | |
+| `updated_at` | timestamp | |
+
+## Relationships
+
+```
+Commentable Model (e.g., Project)
+ └── comments (morphMany)
+ ├── user (morphTo → User)
+ ├── parent (belongsTo → Comment)
+ ├── replies (hasMany → Comment)
+ ├── reactions (hasMany → CommentReaction)
+ ├── attachments (hasMany → CommentAttachment)
+ └── mentions (morphToMany → User)
+```
+
+All relationships are polymorphic, allowing the same comment system to work across any number of models in your application.
diff --git a/docs/content/4.community/.navigation.yml b/docs/content/4.community/.navigation.yml
new file mode 100644
index 0000000..d332d32
--- /dev/null
+++ b/docs/content/4.community/.navigation.yml
@@ -0,0 +1 @@
+title: Community
diff --git a/docs/content/4.community/1.contributing.md b/docs/content/4.community/1.contributing.md
new file mode 100644
index 0000000..588e604
--- /dev/null
+++ b/docs/content/4.community/1.contributing.md
@@ -0,0 +1,39 @@
+---
+title: Contributing
+description: How to contribute to Comments
+navigation:
+ icon: i-lucide-heart-handshake
+---
+
+## Quick Start
+
+1. **Fork** the repository
+2. **Create** a feature branch
+3. **Make** your changes
+4. **Run** tests: `composer test`
+5. **Submit** a pull request
+
+## Guidelines
+
+- Follow the existing code style
+- Add tests for new features
+- Update documentation as needed
+- One feature per pull request
+
+## Development Commands
+
+```bash
+# Run tests
+composer test
+
+# Format code
+composer pint
+
+# Static analysis
+composer analyse
+```
+
+## Need Help?
+
+- [Open an issue](https://github.com/relaticle/comments/issues) for bugs or questions
+- Check [existing issues](https://github.com/relaticle/comments/issues) first
diff --git a/docs/content/4.community/2.license.md b/docs/content/4.community/2.license.md
new file mode 100644
index 0000000..ee70ce9
--- /dev/null
+++ b/docs/content/4.community/2.license.md
@@ -0,0 +1,39 @@
+---
+title: License
+description: MIT License terms and what it means for you
+navigation:
+ icon: i-lucide-scale
+---
+
+## MIT License
+
+```
+Copyright (c) Relaticle
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+```
+
+## What This Means
+
+You **can** use Comments in commercial projects.
+You **can** modify and distribute it.
+You **can** use it in closed source projects.
+You **can** sell applications that include it.
+
+Just include the license notice in your copy.
diff --git a/docs/content/index.md b/docs/content/index.md
new file mode 100644
index 0000000..d6f46d4
--- /dev/null
+++ b/docs/content/index.md
@@ -0,0 +1,151 @@
+---
+seo:
+ title: Filament Comments System
+ description: A full-featured commenting system for Filament panels with threaded replies, @mentions, emoji reactions, file attachments, and real-time updates.
+ ogImage: /og-image.png
+---
+
+::u-page-hero
+#title
+Comments
+
+#description
+A full-featured commenting system for Filament panels with threaded replies, @mentions, emoji reactions, and real-time updates.
+
+Drop-in integration with any Filament resource.
+
+#links
+ :::u-button
+ ---
+ color: neutral
+ size: xl
+ to: /getting-started/installation
+ trailing-icon: i-lucide-arrow-right
+ ---
+ Get started
+ :::
+
+ :::u-button
+ ---
+ color: neutral
+ icon: simple-icons:github
+ size: xl
+ to: https://github.com/relaticle/comments
+ variant: outline
+ ---
+ GitHub
+ :::
+::
+
+::u-page-section
+#title
+Why choose Comments?
+
+#features
+ :::u-page-feature
+ ---
+ icon: i-lucide-messages-square
+ ---
+ #title
+ Threaded Replies
+
+ #description
+ Nested comment threads with configurable depth limits. Users can reply to specific comments creating organized discussions.
+ :::
+
+ :::u-page-feature
+ ---
+ icon: i-lucide-at-sign
+ ---
+ #title
+ @Mentions
+
+ #description
+ Autocomplete user mentions with a customizable resolver interface. Dispatches events for notification handling.
+ :::
+
+ :::u-page-feature
+ ---
+ icon: i-lucide-smile
+ ---
+ #title
+ Emoji Reactions
+
+ #description
+ Six built-in emoji reactions with a configurable set. Users can react to comments with a single click.
+ :::
+
+ :::u-page-feature
+ ---
+ icon: i-lucide-paperclip
+ ---
+ #title
+ File Attachments
+
+ #description
+ Upload images and documents to comments with configurable storage, size limits, and MIME type validation.
+ :::
+
+ :::u-page-feature
+ ---
+ icon: i-lucide-radio
+ ---
+ #title
+ Real-time Updates
+
+ #description
+ Optional broadcasting via private channels with automatic polling fallback. Comments stay in sync across sessions.
+ :::
+
+ :::u-page-feature
+ ---
+ icon: i-lucide-puzzle
+ ---
+ #title
+ Full Filament Integration
+
+ #description
+ Three integration patterns: slide-over action, table row action, and infolist entry. Works with any Filament resource.
+ :::
+::
+
+::u-page-section
+#title
+Our Ecosystem
+
+#description
+Extend your Laravel applications with our ecosystem of complementary tools
+
+#default
+ ::card-group
+ :::card
+ ---
+ title: FilaForms
+ icon: i-simple-icons-laravel
+ to: https://filaforms.app
+ target: _blank
+ ---
+ Visual form builder for all your public-facing forms.
+ :::
+
+ :::card
+ ---
+ title: Custom Fields
+ icon: i-lucide-sliders
+ to: https://relaticle.github.io/custom-fields
+ target: _blank
+ ---
+ Let users add custom fields to any model without code changes.
+ :::
+
+ :::card
+ ---
+ title: Flowforge
+ icon: i-lucide-kanban
+ to: https://relaticle.github.io/flowforge
+ target: _blank
+ ---
+ Transform any Laravel model into a drag-and-drop Kanban board.
+ :::
+ ::
+::
diff --git a/docs/nuxt.config.ts b/docs/nuxt.config.ts
new file mode 100644
index 0000000..28ca681
--- /dev/null
+++ b/docs/nuxt.config.ts
@@ -0,0 +1,69 @@
+// https://nuxt.com/docs/api/configuration/nuxt-config
+const baseURL = process.env.NUXT_APP_BASE_URL || '/'
+const docsVersion = process.env.DOCS_VERSION || '1.x'
+
+export default defineNuxtConfig({
+ extends: 'docus',
+ modules: ['@nuxt/image', '@nuxt/scripts', 'nuxt-fathom'],
+ fathom: {
+ siteId: process.env.NUXT_PUBLIC_FATHOM_SITE_ID || '',
+ },
+ devtools: { enabled: true },
+ site: {
+ name: 'Comments',
+ },
+ runtimeConfig: {
+ public: {
+ docsVersion,
+ },
+ },
+ appConfig: {
+ docus: {
+ url: `https://relaticle.github.io${baseURL}`,
+ image: `${baseURL}preview.png`,
+ header: {
+ logo: {
+ light: `${baseURL}logo-light.svg`,
+ dark: `${baseURL}logo-dark.svg`,
+ },
+ },
+ },
+ seo: {
+ ogImage: `${baseURL}preview.png`,
+ },
+ github: {
+ branch: docsVersion,
+ },
+ },
+ app: {
+ baseURL,
+ buildAssetsDir: 'assets',
+ head: {
+ link: [
+ {
+ rel: 'icon',
+ type: 'image/x-icon',
+ href: baseURL + 'favicon.ico',
+ },
+ ],
+ },
+ },
+ image: {
+ provider: 'none',
+ },
+ content: {
+ build: {
+ markdown: {
+ highlight: {
+ langs: ['php', 'blade', 'bash', 'json'],
+ },
+ },
+ },
+ },
+ llms: {
+ domain: `https://relaticle.github.io${baseURL.replace(/\/$/, '')}`,
+ },
+ nitro: {
+ preset: 'github_pages',
+ },
+})
diff --git a/docs/package.json b/docs/package.json
new file mode 100644
index 0000000..e39242a
--- /dev/null
+++ b/docs/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "comments-docs",
+ "scripts": {
+ "dev": "nuxt dev --extends docus",
+ "build": "nuxt build --extends docus",
+ "generate": "nuxt build --preset github_pages",
+ "preview": "nuxt preview"
+ },
+ "dependencies": {
+ "@nuxt/image": "^1.11.0",
+ "@nuxt/scripts": "^0.12.1",
+ "@nuxt/ui": "^4.0.0",
+ "@unhead/vue": "^2.0.17",
+ "better-sqlite3": "^12.4.1",
+ "docus": "latest",
+ "nuxt": "^4.1.2",
+ "typescript": "^5.9.2"
+ },
+ "devDependencies": {
+ "nuxt-fathom": "^0.0.3"
+ }
+}
diff --git a/resources/boost/skills/comments-development/SKILL.md b/resources/boost/skills/comments-development/SKILL.md
new file mode 100644
index 0000000..89e49c9
--- /dev/null
+++ b/resources/boost/skills/comments-development/SKILL.md
@@ -0,0 +1,285 @@
+---
+name: comments-development
+description: Full-featured commenting system for Filament panels with polymorphic comments, threaded replies, @mentions, emoji reactions, file attachments, and real-time notifications. Use when adding the HasComments trait to models, integrating CommentsAction/CommentsTableAction/CommentsEntry in Filament, configuring threading, reactions, mentions, attachments, notifications, broadcasting, or customizing the CommentPolicy.
+---
+
+# Comments Development
+
+## When to Use This Skill
+
+Use when:
+- Adding commenting capability to an Eloquent model
+- Integrating comments into Filament resources (actions, table actions, infolists)
+- Configuring threading depth, reactions, mentions, or attachments
+- Working with comment notifications and subscriptions
+- Customizing the CommentPolicy for authorization
+- Implementing real-time updates via broadcasting or polling
+- Creating a custom MentionResolver
+
+## Quick Start
+
+### 1. Add Traits to Models
+
+```php
+use Relaticle\Comments\Concerns\HasComments;
+use Relaticle\Comments\Contracts\Commentable;
+
+class Project extends Model implements Commentable
+{
+ use HasComments;
+}
+```
+
+```php
+use Relaticle\Comments\Concerns\IsCommenter;
+use Relaticle\Comments\Contracts\Commenter;
+
+class User extends Authenticatable implements Commenter
+{
+ use IsCommenter;
+}
+```
+
+### 2. Register Plugin in Panel
+
+```php
+use Relaticle\Comments\CommentsPlugin;
+
+public function panel(Panel $panel): Panel
+{
+ return $panel
+ ->plugins([
+ CommentsPlugin::make(),
+ ]);
+}
+```
+
+### 3. Publish and Run Migrations
+
+```bash
+php artisan vendor:publish --tag=comments-migrations
+php artisan migrate
+```
+
+## Filament Integration
+
+### Slide-Over Action (View/Edit Pages)
+
+```php
+use Relaticle\Comments\Filament\Actions\CommentsAction;
+
+protected function getHeaderActions(): array
+{
+ return [
+ CommentsAction::make(),
+ ];
+}
+```
+
+Shows a comment count badge and opens a slide-over modal with the full comment thread.
+
+### Table Row Action
+
+```php
+use Relaticle\Comments\Filament\Actions\CommentsTableAction;
+
+public static function table(Table $table): Table
+{
+ return $table
+ ->actions([
+ CommentsTableAction::make(),
+ ]);
+}
+```
+
+### Infolist Entry
+
+```php
+use Relaticle\Comments\Filament\Infolists\Components\CommentsEntry;
+
+public static function infolist(Infolist $infolist): Infolist
+{
+ return $infolist->schema([
+ CommentsEntry::make('comments'),
+ ]);
+}
+```
+
+Embeds the full comment component inline within an infolist.
+
+## Configuration Reference
+
+Publish config: `php artisan vendor:publish --tag=comments-config`
+
+| Key | Default | Purpose |
+|-----|---------|---------|
+| `tables.comments` | `'comments'` | Main comments table name |
+| `models.comment` | `Comment::class` | Comment model class |
+| `commenter.model` | `User::class` | Commenter (user) model class |
+| `policy` | `CommentPolicy::class` | Authorization policy class |
+| `threading.max_depth` | `2` | Maximum reply nesting depth |
+| `pagination.per_page` | `10` | Comments per page |
+| `reactions.emoji_set` | 6 emojis | Available reaction emojis |
+| `mentions.resolver` | `DefaultMentionResolver::class` | User search resolver |
+| `mentions.max_results` | `5` | Autocomplete results limit |
+| `editor.toolbar` | bold, italic, strike, link, lists, codeBlock | Rich text toolbar buttons |
+| `notifications.enabled` | `true` | Enable/disable notifications |
+| `notifications.channels` | `['database']` | Notification channels |
+| `subscriptions.auto_subscribe` | `true` | Auto-subscribe on comment/mention |
+| `attachments.enabled` | `true` | Enable file attachments |
+| `attachments.disk` | `'public'` | Storage disk |
+| `attachments.max_size` | `10240` | Max file size (KB) |
+| `attachments.allowed_types` | images, pdf, text, word | Allowed MIME types |
+| `broadcasting.enabled` | `false` | Enable real-time broadcasting |
+| `broadcasting.channel_prefix` | `'comments'` | Private channel prefix |
+| `polling.interval` | `'10s'` | Livewire polling interval (fallback) |
+
+### Default Reactions
+
+```php
+'reactions' => [
+ 'emoji_set' => [
+ 'thumbs_up' => ['emoji' => "\u{1F44D}", 'label' => 'Like'],
+ 'heart' => ['emoji' => "\u{2764}\u{FE0F}", 'label' => 'Love'],
+ 'celebrate' => ['emoji' => "\u{1F389}", 'label' => 'Celebrate'],
+ 'laugh' => ['emoji' => "\u{1F602}", 'label' => 'Laugh'],
+ 'thinking' => ['emoji' => "\u{1F914}", 'label' => 'Thinking'],
+ 'sad' => ['emoji' => "\u{1F622}", 'label' => 'Sad'],
+ ],
+],
+```
+
+## Events
+
+| Event | Broadcast | Payload |
+|-------|-----------|---------|
+| `CommentCreated` | Yes | `$comment` |
+| `CommentUpdated` | Yes | `$comment` |
+| `CommentDeleted` | Yes | `$comment` |
+| `CommentReacted` | Yes | `$comment`, `$user`, `$reaction`, `$action` (added/removed) |
+| `UserMentioned` | No | `$comment`, `$mentionedUser` |
+
+Broadcasting uses private channels: `{prefix}.{commentable_type}.{commentable_id}`
+
+## Authorization
+
+Default `CommentPolicy` methods:
+
+| Method | Default | Description |
+|--------|---------|-------------|
+| `viewAny()` | `true` | Everyone can view comments |
+| `create()` | `true` | Everyone can create comments |
+| `update()` | Owner only | Only comment author can edit |
+| `delete()` | Owner only | Only comment author can delete |
+| `reply()` | Depth check | Can reply if max_depth not exceeded |
+
+### Custom Policy
+
+```php
+// config/comments.php
+'policy' => App\Policies\CustomCommentPolicy::class,
+```
+
+```php
+namespace App\Policies;
+
+use Relaticle\Comments\Comment;
+use Relaticle\Comments\Contracts\Commenter;
+
+class CustomCommentPolicy
+{
+ public function delete(Commenter $user, Comment $comment): bool
+ {
+ return $comment->user_id === $user->getKey()
+ || $user->hasRole('admin');
+ }
+}
+```
+
+## Common Patterns
+
+### Scoped Comments (Multi-tenancy)
+
+```php
+use Relaticle\Comments\Config;
+
+// In AppServiceProvider::boot()
+Config::resolveAuthenticatedUserUsing(function () {
+ return auth()->user();
+});
+```
+
+### Custom Mention Resolver
+
+```php
+use Relaticle\Comments\Contracts\MentionResolver;
+
+class TeamMentionResolver implements MentionResolver
+{
+ public function search(string $query): Collection
+ {
+ return User::query()
+ ->where('team_id', auth()->user()->team_id)
+ ->where('name', 'like', "{$query}%")
+ ->limit(config('comments.mentions.max_results'))
+ ->get();
+ }
+
+ public function resolveByNames(array $names): Collection
+ {
+ return User::query()
+ ->where('team_id', auth()->user()->team_id)
+ ->whereIn('name', $names)
+ ->get();
+ }
+}
+```
+
+Register in config:
+
+```php
+// config/comments.php
+'mentions' => [
+ 'resolver' => App\Comments\TeamMentionResolver::class,
+],
+```
+
+### Enable Broadcasting
+
+```php
+// config/comments.php
+'broadcasting' => [
+ 'enabled' => true,
+ 'channel_prefix' => 'comments',
+],
+```
+
+When broadcasting is enabled, the Livewire component listens for real-time events. When disabled, it falls back to polling at the configured interval.
+
+## Database Schema
+
+Five tables are created:
+
+- `comments` -- Polymorphic comments with parent_id for threading, soft deletes
+- `comment_reactions` -- Unique reactions per user+comment+emoji
+- `comment_mentions` -- Tracks @mentioned users per comment
+- `comment_subscriptions` -- Thread subscription tracking per user+commentable
+- `comment_attachments` -- File metadata (path, name, MIME type, size, disk)
+
+## Model Relationships
+
+```php
+// On any Commentable model
+$model->comments(); // All comments (morphMany)
+$model->topLevelComments(); // Top-level only (no parent)
+$model->commentCount(); // Total count
+
+// On Comment model
+$comment->commentable(); // Parent model (morphTo)
+$comment->user(); // Commenter (morphTo)
+$comment->parent(); // Parent comment (belongsTo)
+$comment->replies(); // Child comments (hasMany)
+$comment->reactions(); // Reactions (hasMany)
+$comment->attachments(); // File attachments (hasMany)
+$comment->mentions(); // Mentioned users (morphToMany)
+```