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

Filament Max Users Laravel Package

geekcodev/filament-max-users

Filament Max Users lets you enforce a maximum number of user accounts in your Filament panel. Set a limit, prevent new users from being created once it's reached, and keep registrations under control with simple configuration. Handy for licensing, plan tiers, demos, and single-tenant apps.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Filament 5 plugin (filament/filament ^5.0, dev-pinned to 5.9.0) that mirrors MAX messenger data into two panel resources — «Max пользователи» and «Max чаты» — backed by geekcodev/max-php-client. It is a read/observe surface, not an authoring tool: you browse users and chats, and drive one write-ish operation (refresh chat metadata from the MAX API).

Minimal path:

  1. composer require geekcodev/filament-max-users on Laravel 11/12 with a Filament 5 panel. Make sure your panel resolves to ≥5.9.0 — 1.1.1 pulls that in for advisory CVE-2026-104181, and a constrained lockfile can leave you on 5.7.8.
  2. Register the plugin in your PanelProvider (->plugin(...)) — confirm the exact class name and builder from the README, which is kept in sync with releases (1.1.1 updated both the config block and .env.example).
  3. Publish config and translations (vendor:publish for the package's config/lang tags), then set your panel's navigation group — FILAMENT_MAX_USERS_NAVIGATION_GROUP is now documented in .env.example, which tells you the nav group is env-tunable and worth setting per environment.
  4. Ensure MAX API credentials are configured for max-php-client; the resources read from your local tables, and only the refresh action hits the network.
  5. First use case: open Max чаты, pick a chat or channel, and hit «Обновить из MAX» to pull fresh displayName/participants/last activity. That single action is the best smoke test — if it works on a group (not just a dialog), your max-php-client is at 1.1.9 and the participants-map fix is in place.

Before going further, check the access story: permissions are namespaced (users.*, chats.*) and unchanged in this patch, so your existing policies/gates carry over.

Implementation Patterns

Treat the column toolbar as the customization contract. As of 1.1.1 every column in both lists is toggleable, and visibility state is persisted per Filament user. That means per-user table shape is a supported feature, not an accident — point your users at the column toggle instead of shipping variants of the resource. Defaults are deliberately narrow (identity, badges, avatar, phone, counters); the wide fields (email, username, description, full_avatar_url, last_activity_time, profile_checked_at, and for chats icon_url, title, link, chat_checked_at) are opt-in per user.

Extend by subclassing, not by patching. Order and visibility are now locked by dedicated feature tests (test_list_shows_columns_in_expected_default_order, test_list_exposes_every_column_as_toggleable, test_view_page_shows_entries_in_expected_order). That's great news for upgrades — upstream can't silently reshuffle your tables — but it also means your overrides won't be caught by upstream tests. If you need a different default order or a bespoke column, subclass the resource and override the table/infolist schema in your app, and write your own assertions.

Reuse the presenter for any link you render yourself. ChatPresenter::safeUrl() is what keeps javascript: / data: payloads out of href. If you add a custom column, a Blade view, an export, or a widget that shows the chat link, route it through the presenter rather than printing the API string. The same discipline applies to displayName, which does the title → interlocutor name → chat_id fallback — don't reimplement that resolution in your own views or the labels will drift.

Model relations are the join points. The chat count on a user is counts('chatLinks') and the participant count on a chat is counts('chatUsers'). Any dashboard widget or custom page you build should use the same relations with withCount/with to stay consistent and avoid N+1 — these are exactly the relations the refresh action writes through.

If you build your own sync, parse participants as a map. The 1.1.1 fix exists because real GET /chats/{id} returns {user_id: activity} for groups and channels, not a list. Any ingestion job or command you write against the client must handle the map shape, otherwise you'll reproduce the crash the package just fixed. Same for ordering: the {"user_id": activity} values are the source for the "последняя активность" column.

Localization is an override surface. lang/ru and lang/en are key-synchronized and additive in this release (users.table.name, users.table.description, users.table.full_avatar_url, users.table.phone_verified_at, chats.table.description, chats.table.link). Publish the lang files and rebrand strings in your app rather than editing vendor — new keys will land cleanly next release.

Gotchas and Tips

  • Label text changed (declared BC). table.username and view.username in lang/ru now read «Никнейм» instead of «Username»; lang/en still says "Username". If you published lang files and merged overrides, re-publish or diff — and any test or docs screenshot asserting "Username" in a Russian panel will fail.
  • Default visibility changed more than the label. Columns you may have been relying on being visible (email, username, description, phone_verified_at, last_activity_time, profile_checked_at; title, link, icon_url, chat_checked_at on chats) are hidden by default. Filament persists toggle state per user, so returning users can end up with a mix of old and new state. When in doubt, have them reset the column toggle for that table.
  • title is a legacy field. «Название из MAX» is now hidden-by-default in the chats list and removed from the chat view page, because it duplicates displayName for groups/channels and is empty for dialogs. Use displayName for anything user-facing; title stays only for diagnostics.
  • view.title duplicate key removed from lang/{ru,en}/chats.php. Behaviour is unchanged (the second, effective value was always the one used), but a hand-merged published lang file with the stale duplicate will now diverge from vendor — clean it up. chats.table.title and the chats.title.* section are untouched.
  • Lockfile traps when debugging the refresh crash. The group-participants fix lives in geekcodev/max-php-client 1.1.9, not in the plugin. composer update geekcodev/filament-max-users alone can leave the old client resolved; update the client explicitly. There's a regression test (test_refresh_metadata_action_parses_group_participants_map) guarding it upstream, but not in your app.
  • Errors are non-fatal by design. Failed refreshes surface as a user-facing notification and are logged. First debugging stop is laravel.log for the client exception — not the resource class.
  • Filament minor bump needs an asset rebuild. 5.7.8 → 5.9.0 is a minor version: run php artisan filament:assets (and clear cached views/components) after upgrading, especially if you have custom table/infolist overrides that touch column APIs.
  • Missing phone icon ≠ missing data. The phone column renders its icon off phone_verified_at; unverified numbers render plain. Don't chase it as a data bug.
  • is_bot is a badge, not a filter contract. It renders «Бот»/«Пользователь»; the label is unchanged in this release. Filter on the underlying boolean, not on localized strings.
  • Quality signals are usable as a floor. PHPStan level max, PSR-12 clean, 97.47% line coverage behind a 95% gate, and composer security-audit at zero. That means subclassing and typed overrides are safe bets — but keep docblocks on your own overrides if you run PHPStan in the host app.
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.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core