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

Filum Laravel Package

heyosseus/filum

Real-time chat between admin users inside your Filament panel. Click a colleague, the conversation opens, history persists, and messages arrive as sent. Broadcasting-agnostic and free: uses your broadcaster if configured, otherwise falls back to polling. Dark-first, English and Georgian included.

View on GitHub
Deep Wiki
Context7

Getting Started

Filum is a Filament panel plugin, so installation is a three-command affair plus one line in your panel provider:

composer require heyosseus/filum
php artisan filum:install
php artisan migrate
use Heyosseus\Filum\FilumPlugin;

public function panel(Panel $panel): Panel
{
    return $panel->plugin(FilumPlugin::make());
}

Before you migrate, decide one thing: which model authenticates your panel. If it is not App\Models\User, set it in .env in every environment:

FILUM_USER_MODEL=App\Models\AdminUser

This is the only mandatory configuration. Filum derives the migration's foreign key from the model you name, and it asks for the current user while the navigation is being built — so a wrong value does not degrade gracefully, it throws on every panel page.

Where to look first: after filum:install, read the published config/filum.php. The whole package is driven from it — transport.driver, notifications.enabled, groups.enabled, attachments.*, reactions.emoji, presence.*, users.*. You will rarely touch anything else. Second stop is the generated Chat page in the navigation, which is your smoke test.

First use case: two admin users chatting 1:1 with zero broadcaster configuration. Log in as two users in two browsers, click a colleague in the sidebar, send a message, and watch it arrive within five seconds via the polling fallback. That is the whole happy path and it requires no Reverb, no Echo, no npm build. Ship that first, then decide whether real-time latency is worth the extra infrastructure.

Implementation Patterns

Start on polling, upgrade later. The default auto driver does the right thing: no broadcaster configured means 5-second polls; a real broadcaster means push plus a 30-second reconciliation poll. Do not install Reverb on day one just because it says "real-time". The polling fallback is genuinely usable for back-office chat, and it means you can defer the WebSocket infrastructure decision indefinitely. When you do want push, php artisan reverb:install sets up Reverb, Echo, and BROADCAST_CONNECTION in one shot — Filum reads config/broadcasting.php and switches itself.

Gate access at the service provider, not the panel. The plugin installs into whatever panel you register it on, and by default admits anyone that panel has authenticated. That is often too broad. Narrow it once, centrally:

// AppServiceProvider::boot()
use Heyosseus\Filum\Filum;

Filum::auth(fn ($user) => $user->hasRole('admin'));

One gate governs the page, the slide-over, and the broadcast channel subscriptions together. This is the pattern to reach for whenever you need a "support team only" or "staff only" chat channel — you do not need to hide the navigation item separately, because the gate already refuses the page and the channels.

Wire notifications into your existing stack rather than replacing them. Filum writes into Filament's own notification bell using your app's notifications table. If your user model is Notifiable (it almost certainly is), this works with no work. If you want mail, Slack, or a pager on top, implement the contract and bind it:

$this->app->singleton(
    Heyosseus\Filum\Contracts\Notifier::class,
    App\Filum\SlackNotifier::class
);

Note the semantics you are inheriting: the bell rings once per conversation on the caught-up → behind transition, and only for recipients who are not currently present (per presence.ttl). A forty-message burst is one bell. Do not try to build per-message email alerts on top of Notifier — that is not what it fires on.

Custom user shapes go through ConfiguredUserProvider. If names are assembled from two columns, avatars live in a non-standard column, or users come from an external directory, implement the provider contract and point users.provider at it. This is the intended extension seam for anything the name_column / avatar_column config cannot express.

Treat groups as an invitation system, not a channel system. Any member can invite, anyone can leave, only the owner can remove/rename/delete. Ownership transfers automatically to the longest-joined member when the owner leaves, and the group is deleted if nobody is left. Declining and leaving are the same state. This means you do not need to build invite acceptance UI yourself — but it also means you cannot "just add someone" to a group programmatically without them accepting. If your product need is "announcement channel everyone is in", Filum groups are not that; use a 1:1 fan-out or a different tool.

Files must land on a private disk. The attachments.disk default of local is correct and you should keep it. Files are served through a panel route that re-checks conversation membership on every request, and answers 404 rather than 403 so non-participants cannot even confirm a file exists. Do not "helpfully" expose a public URL for a disk you configure here.

Reactions are a curated set, not a picker. Filum ships compiled CSS and runs no build step, so choose your six emojis in config and accept that anything outside the list is refused at the write path. This is a deliberate trade-off, not a missing feature.

Gotchas and Tips

Never publish filum-migrations on an existing install. This is the single most dangerous footgun in the package, and the README spells out the failure mode at length: your published create_filum_tables was stamped at install time, so vendor:publish cannot find the source name, copies it again under a fresh stamp, and migrate runs the duplicate first, hits table already exists, aborts, and never reaches the new migration. You then have new code querying columns that were never added, and chat fails wholesale — including 1:1. On upgrade, publish only the tagged migration:

composer update heyosseus/filum
php artisan vendor:publish --tag=filum-migrations-groups   # example: 0.1.x → 0.2.0
php artisan migrate

If you have already fallen into it, delete the newer duplicate of *_create_filum_tables.php before migrating.

Run the migration in the same release step as the code. New code on an old schema is a hard outage, not a degradation: opening a direct conversation writes kind, state and joined_at, and every membership check reads state. There is no defensive fallback. Deploy code and migration together, always.

A configured broadcaster with no Echo is slower than no broadcaster. Filum's transport switches itself based on config/broadcasting.php, but the browser only listens if window.Echo exists in the panel. Configure a broadcaster but forget to build Echo into your assets and you get the reconciliation poll at 30 seconds instead of the 5-second polling default — worse than doing nothing. php artisan reverb:install plus npm run build sets up both halves; if you wire a broadcaster by hand, verify Echo is actually on the page before you believe the transport switched.

presence.ttl is doing double duty and you cannot split it. The same number decides both the sidebar's HERE NOW set and whether the notification bell rings. At the default 180 seconds, someone who closed their laptop and is written to thirty seconds later still counts as present and gets no bell. That is intentional — a second threshold could produce a colleague marked HERE NOW who nonetheless gets a bell, which reads as a bug. Lower ttl if notification lag matters more than a twitchy presence indicator; accept that you cannot tune one without the other.

The Filament version floor is a security minimum, not a preference. Filament 4.11.5+/5.6.5+ and earlier releases carry published advisories. Composer will refuse to resolve against older versions, and you should not work around that. If you are stuck on an older Filament, Filum is not available to you yet.

Disabled means genuinely absent, not partially working. FILUM_GROUPS=false removes the groups section, the new-group action, and every group operation — a previously-joined member cannot open, read, send into, or leave a group while the switch is off. Nothing is deleted, so re-enabling restores everything. Same for the other feature switches. Plan your toggles accordingly — this is safe for a staged rollout, but do not expect a soft "read-only groups" mode.

Reactions never ring the bell, by design. A thumbs-up is an acknowledgement. If you need reaction notifications for some workflow, that is a custom Notifier concern, not something Filum will do for you.

Maturity check before you commit. Seven stars, zero dependents, a single maintainer, and a README that reads more like a design rationale than a reference manual. The engineering discipline on display — the migration tagging, the private-disk-by-default, the 404-not-403 file route, the MIME sniffing from bytes rather than the browser's claim, the explicit "one knob so the bell and the board cannot disagree" reasoning — is unusually careful for a package this young. But zero dependents means zero field reports. Pin the version, read the CHANGELOG before every upgrade, and treat each composer update heyosseus/filum as a release event rather than a routine bump. It is a good fit for internal back-office panels where the risk surface is your own staff; be more cautious if the chat sits anywhere near customer data or regulated workflows.

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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel