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 Chat Laravel Package

geekcodev/filament-max-chat

Filament plugin for an operator chat with MAX messenger users. View dialogs with unread badges, reply with HTML formatting and media attachments, receive real-time Echo/Reverb updates with a poll fallback, and configure permissions, channel, disk and navigation via config.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

What v1.1.5 is. A single additive migration (0000_02_000003_add_unread_index_to_max_chat_messages.php) adding composite index max_chat_messages_unread_index on (direction, read_at) to max_chat_messages. No code paths, public signatures, config keys, translation keys, or defaults changed. This is a performance patch, not a feature release.

Architecture fit. The package already owns its schema via versioned migrations, so shipping an index as a migration is the correct Laravel-idiomatic mechanism — host applications get the fix through the normal php artisan migrate path with no publish step, no config edit, and no service-provider changes. The index targets exactly the predicate used by MaxMessageService::totalUnreadCount() and UnreadCountController (direction = 'in' AND read_at IS NULL), and deliberately leaves markRead() on the existing max_chat_id-leading index. That is a well-scoped, low-blast-radius change.

Integration feasibility. Highest-band feasibility: no env vars, no migrations to backfill, no data movement, no API surface change. up() is guarded by Schema::hasIndex, so re-running or installing into a host that already added an equivalent index will not fail the deploy. down() drops the index cleanly. The accompanying MaxChatMessagesSchemaTest covers presence, removal, and idempotency, and the suite reports 271 tests / 628 assertions / 98.31% line coverage with PHPStan at max — quality signal is strong for a patch of this size.

Technical risk.

  • Online-DDL behaviour of the index build itself is the dominant risk, and the release notes do not quantify it. On PostgreSQL, Laravel's schema builder emits a plain CREATE INDEX, which takes an ACCESS EXCLUSIVE lock and blocks writes for the duration of the build; there is no CONCURRENTLY path here. On MySQL/InnoDB, adding a secondary index is generally INPLACE/LOCK=NONE, but still requires a brief metadata lock and can be slow on a large table. php artisan migrate runs synchronously inside the deploy, so table size — not code correctness — determines whether this deploy is safe.
  • The guard detects by index name, not by column signature. A host that already created an equivalent index under a different name will get a second, redundant index; the reverse (host index named identically but differently defined) is unlikely but unverified. Duplicate indexes cost write throughput and storage silently.
  • Schema::hasIndex has a minimum Laravel version. The package's composer.json floor is not stated in the notes; if the constraint permits older Laravel releases, hasIndex may not exist and the migration errors on those installs.
  • This is a mitigation, not a cure. The badge still computes unread count on every panel page render and on every tab switch. The index makes a full scan into an index range scan, but the read amplification and the coupling of a navigation badge to a live aggregate query remain. Octane worker exhaustion under bursty tab-switching traffic is bounded by the index, not eliminated by design.
  • Verification gap in the release evidence. Coverage and static analysis are green, but there is no EXPLAIN before/after, no row-count-at-scale benchmark, and Gate step 7 (clean resolve in .ci-sim/) was skipped locally due to host disk pressure and deferred to CI.

Key questions for the maintainer.

  1. What table size did you benchmark, and what were the observed totalUnreadCount() timings and query plans before/after?
  2. What is the package's minimum supported Laravel version, and does it guarantee Schema::hasIndex availability across the full constraint range?
  3. What is the expected migration duration on a 10M/50M/200M-row max_chat_messages table on MySQL 8 and PostgreSQL 14+, and is there any documented guidance for hosts that need to build the index out-of-band (e.g. CREATE INDEX CONCURRENTLY manually, then run migrate relying on the idempotency guard)?
  4. Was Gate step 7 confirmed green in CI for this tag, or does the tag ship with that step unverified?
  5. Is there a roadmap item for denormalising the unread counter (per-chat counter column or cache), which would remove the per-render aggregate entirely?

Integration Approach

Stack fit. Drop-in for any Laravel host already running this package: standard package migration discovery, no vendor publish, no config cache invalidation, no queue or scheduler changes. Works across the three claimed drivers (SQLite, MySQL, PostgreSQL) through the schema builder with no driver-specific branches.

Migration path. Run php artisan migrate. Nothing to backfill, nothing to rewrite, no downtime-window requirement beyond what the index build itself imposes on a large table. Because no application code references the new index, the migration is order-independent relative to the code deploy — it can be applied before, with, or after the release without correctness risk. Prefer before the code rollout if you deploy code and migrations as separate steps, so the perf win lands with the first request.

Compatibility. No breaking changes: public signatures, config keys/defaults, and translation keys are untouched. up() is idempotent via Schema::hasIndex, which makes the migration safe for hosts that pre-created the index and for repeated CI database resets. Rollback is a clean index drop, though it reinstates the pre-patch scan behaviour — treat rollback as a perf regression, not a functional one.

Sequencing for a large install. For tables in the low millions of rows or under, the default path is fine: deploy the version bump, let migrate run, monitor migration duration. For tables in the tens of millions or beyond, recommend a staged approach: (1) verify Schema::hasIndex behaviour on your Laravel version in staging, (2) on PostgreSQL, create the index manually with CREATE INDEX CONCURRENTLY max_chat_messages_unread_index ... during a low-traffic window so the migration's guard short-circuits, (3) set a deploy-time statement/lock timeout so a stalled DDL fails fast rather than pinning the deploy, (4) roll the application code, (5) confirm the index is present and the badge query plan changed. Keep the package version pinned in composer.lock and roll forward deliberately rather than absorbing it in a bulk dependency update.

Validation gates before merge. Run the host's own migration against a production-shaped dataset in staging, capture EXPLAIN for the unread count query, and confirm the pre-existing max_chat_id-leading index is still used by markRead() (i.e. the new index did not displace it). Confirm CI ran Gate step 7 green for the tag, since that step was skipped locally.

Operational Impact

Maintenance. Effectively zero steady-state maintenance: one index, no new config, no new env vars, no cron or queue entry. Write-path cost is a modest increase in index maintenance on max_chat_messages inserts and on read_at updates (which is what markRead() does) — measurable only at high message-ingest rates. The down() path is clean, so the change is fully reversible.

Support. The blast radius if something goes wrong is a slow or failed migration, not broken messaging. Support scripts should know: (a) failure mode = migration timeout / lock wait on a large table, remedy = build the index out-of-band and rely on the idempotency guard; (b) a redundant index appearing alongside a host-created one is expected if names differ and is harmless but worth pruning; (c) rollback reinstates the slow-scan behaviour immediately.

Scaling. This materially improves the failure mode described in the notes: the unread badge was a full table scan per panel render, so tab-switching traffic could exhaust Octane workers, starve /up, and trigger container restarts — a cascading availability incident driven by a read query. The index converts that to a bounded range scan and should remove the healthcheck-restart loop at the observed scales. Two caveats for capacity planning: the query remains O(unread rows) rather than O(1), so the ceiling moves out but does not disappear; and the underlying architectural coupling (synchronous per-render aggregate for a navigation badge) is unchanged. Flag the denormalised-counter follow-up as the durable fix.

Failure modes to instrument.

  • Deploy-time: migration duration and lock-wait on max_chat_messages; alert if migrate exceeds the deploy budget.
  • Runtime regression: if panel page latency or Octane worker saturation recurs, confirm the new index is actually present and selected (a dropped or unused index silently restores the old behaviour).
  • Write amplification: monitor insert/update latency on max_chat_messages after rollout, particularly if markRead() fires per message rather than per chat.
  • Duplicate-index drift: for hosts that pre-created an index under a different name, watch table storage growth and write latency as the signal.
  • Healthcheck coupling: /up failing under load remains the tripwire for this class of problem; keep the restart-loop runbook entry and point it at unread-count query cost.

Ramp-up. Minimal. No new concepts, APIs, or config for the team to learn — engineers need only the one-paragraph operational note (migrate, index may be built out-of-band on large tables, rollback is a perf regression) and the reminder that php artisan migrate is now a potentially long-running DDL step on big installs. Budget well under a day of engineering time including staging verification; the real cost is the staging dataset you need to validate the index build against, not the change itself. Confidence to adopt: high, contingent on verifying the DDL duration at your own table size and confirming Gate step 7 is green in CI.

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