Backend Customization
Override models, policies, resolvers, actions, middleware, rate limiters, and more
Chatify is designed to be extended. This page covers every backend customization hook.
Publishing assets
The installer publishes common assets automatically, but you can also publish specific groups using tags:
php artisan vendor:publish --tag=chatify-config
php artisan vendor:publish --tag=chatify-migrations
php artisan vendor:publish --tag=chatify-channels
php artisan vendor:publish --tag=chatify-views
php artisan vendor:publish --tag=chatify-assets
php artisan vendor:publish --tag=chatify-patterns
php artisan vendor:publish --tag=chatify-sounds
php artisan vendor:publish --tag=chatify-frontend
php artisan vendor:publish --tag=chatify-lang| Tag | What it publishes | Destination |
|---|---|---|
chatify-config | Configuration file | config/chatify.php |
chatify-migrations | Database migrations | database/migrations/ |
chatify-channels | Broadcast channel definitions | routes/chatify/channels.php |
chatify-views | Blade views (layout + page) | resources/views/vendor/chatify/ |
chatify-assets | Compiled frontend bundle | public/vendor/chatify/ |
chatify-patterns | Wallpaper SVG patterns | public/vendor/chatify/patterns/ |
chatify-sounds | Sound files | public/vendor/chatify/sounds/ |
chatify-frontend | Vue 3 frontend source code | resources/vendor/chatify/frontend/ |
chatify-lang | Language files | lang/vendor/chatify/ |
Custom models
Override any Chatify model by extending it and updating the config:
// app/Models/ChatConversation.php
namespace App\Models;
use Chatify\Models\Conversation;
class ChatConversation extends Conversation
{
// Add custom methods, scopes, or relationships
}// config/chatify.php
'models' => [
'conversation' => App\Models\ChatConversation::class,
],All Chatify internals resolve models through the config, so your custom class will be used everywhere.
Custom RecipientResolver
The RecipientResolver determines whether one user can message another. The default implementation blocks messaging when either user has blocked the other.
To customize, implement the Chatify\Contracts\RecipientResolver interface:
namespace App\Chat;
use Chatify\Contracts\RecipientResolver;
use Illuminate\Database\Eloquent\Model;
class CustomRecipientResolver implements RecipientResolver
{
public function canMessage(Model $sender, Model $recipient): bool
{
if ($sender->getKey() === $recipient->getKey()) {
return false;
}
// Add your own logic: subscription checks, role restrictions, etc.
return $sender->hasActiveSubscription();
}
}Bind it in a service provider:
use App\Chat\CustomRecipientResolver;
use Chatify\Contracts\RecipientResolver;
$this->app->bind(RecipientResolver::class, CustomRecipientResolver::class);Custom policies
Chatify registers policies for Conversation and Message models. To override them, define your own policies and register them in your AuthServiceProvider:
use App\Policies\CustomConversationPolicy;
use Chatify\Models\Conversation;
use Illuminate\Support\Facades\Gate;
Gate::policy(Conversation::class, CustomConversationPolicy::class);ConversationPolicy methods
| Method | Parameters | Description |
|---|---|---|
view | $user, $conversation | Can view the conversation |
create | $user | Can create conversations (default: always true) |
update | $user, $conversation | Can update conversation settings |
updateGroup | $user, $conversation | Can edit group info (name, description, avatar) |
addParticipants | $user, $conversation | Can add participants to a group |
removeParticipant | $user, $conversation, $targetUserId | Can remove a participant |
manageParticipantRole | $user, $conversation | Can change participant roles |
transferOwnership | $user, $conversation | Can transfer group ownership |
leave | $user, $conversation | Can leave a group |
delete | $user, $conversation | Can delete the conversation |
hide | $user, $conversation | Can hide the conversation from inbox |
clear | $user, $conversation | Can clear all messages (saved messages only) |
MessagePolicy methods
| Method | Parameters | Description |
|---|---|---|
view | $user, $message | Can view the message |
create | $user, $message | Can create a message in the conversation |
update | $user, $message | Can edit the message (sender only) |
delete | $user, $message | Can delete the message (sender only) |
hide | $user, $message | Can hide the message for themselves |
Custom actions
Chatify uses action classes for core operations. You can replace any action by binding your own implementation in the container:
use App\Chat\Actions\CustomSendMessage;
use Chatify\Actions\Messages\SendMessage;
$this->app->bind(SendMessage::class, CustomSendMessage::class);Extending ChatifyMessenger
The ChatifyMessenger facade resolves to the Chatify\ChatifyMessenger class. You can extend it by binding a custom class:
$this->app->bind('ChatifyMessenger', function () {
return new \App\Chat\ExtendedChatifyMessenger();
});Rate limiters
Chatify registers two rate limiters in the service provider:
| Limiter | Default | Applied to |
|---|---|---|
chatify-messages | 60 requests/minute per user | Message send, typing, search, forward |
chatify-uploads | 10 requests/minute per user | Avatar upload, attachment upload, background upload, settings update |
To customize, redefine them in your AppServiceProvider:
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
RateLimiter::for('chatify-messages', function ($request) {
return Limit::perMinute(120)->by($request->user()?->getKey() ?: $request->ip());
});
RateLimiter::for('chatify-uploads', function ($request) {
return Limit::perMinute(20)->by($request->user()?->getKey() ?: $request->ip());
});Custom middleware
API middleware
Set the API middleware stack via environment variable:
CHATIFY_API_MIDDLEWARE=web,auth,verifiedWeb middleware
Override the web route middleware in config:
'web' => [
'middleware' => ['web', 'auth', 'verified'],
],Route bindings
Chatify registers custom route model bindings for conversation and message that scope queries to the authenticated user's conversations. This means a user can never access a conversation or message they are not a participant of, regardless of policy.
If you need to customize this behavior, you can override the bindings in your RouteServiceProvider.