nben/filament-record-nav
Adds zero-config next/previous record navigation buttons to Filament 4/5 admin panels. Drop two actions into getHeaderActions()—no trait required—with configurable ordering, page-type targets, smart boundary disabling, and one query per render. Works on ViewRecord and EditRecord pages.
Architecture fit. The package is a thin UI-layer utility, not a platform dependency. It ships ~7 PHP files: two Filament Action subclasses, a shared trait (ResolvesAdjacentRecord), an optional page trait, two enums/value objects, a contract, and a service provider. It adds no routes, no migrations, no middleware, no service-container bindings that other code would resolve, and no published assets beyond a config file. That is the ideal shape for a TPM to approve: bounded blast radius, trivially reversible. Adoption is a per-page getHeaderActions() edit, so it can be scoped, piloted, and rolled back one resource at a time.
Integration feasibility. Extremely high for any team already on Filament 4.x. The integration surface is one line per action and an optional config publish. There is no page class modification required, which means no inheritance conflicts with existing base pages, and the actions extend Filament's native Action, so existing fluent conventions (color, size, tooltip, keybindings, authorization) all work. The documented $livewire injection dependency is Filament's stable public API rather than internal lifecycle hooks — a deliberate and correct choice that lowers upgrade risk.
Technical risk. Four items a TPM should track:
id. Fine for auto-increment, actively misleading for UUID/ULID primary keys or any table where insertion order isn't the user's mental model. This is a correctness-of-experience risk, not a crash risk, but it will generate support tickets ("next goes to a random record").newQuery(), which respects Eloquent global scopes but not Filament resource scoping applied via getEloquentQuery() (the common multi-tenant pattern). Unverified, this could let a next/prev button navigate a user into another tenant's record, or to a record they lack view/update permission for — producing 403s at best. This needs a spike before rollout on any multi-tenant panel.Key questions.
Stack fit. Requires PHP 8.2+ and Filament 4.x. If we are on Filament 3, this package is out of scope until that upgrade completes — do not let it become a driver of the upgrade. Laravel 10–13 support means it will not constrain our framework upgrade cadence for the foreseeable future.
Migration path. Additive and non-breaking. composer require nben/filament-record-nav touches only composer.json/composer.lock; the config file is optional and publishable. No existing behavior changes until an action is added to a page. Rollback is removing two lines per page plus a composer remove — no data, no schema, no route cleanup.
Compatibility. Two axes to lock down: the Filament major (action API stability) and our own resource base classes. Because it requires no page trait, it composes cleanly with whatever shared ViewRecord/EditRecord base classes we already have. Where we do adopt the trait, watch for method-name collisions — getPreviousRecord/getNextRecord/getRecordNavigationUrl must remain unspecific in our base classes.
Sequencing.
ViewRecord/EditRecord pages. Prioritize resources where operators review records serially (moderation queues, tickets, invoices); deprioritize resources entered by search or dashboard link.Total realistic cost: 3–5 engineer-days for a mid-size panel, most of which is the convention step, not the package.
Maintenance. Near-zero steady state. No ongoing config churn, no data migrations, no cron, no storage. The only recurring maintenance is re-verifying the package after a Filament major upgrade — budget half a day there and treat it as a checklist item on our upgrade runbook.
Support. Community-maintained by a single author with no SLA. Our support posture should be: we own the behavior, the package supplies the mechanism. Practically, that means any override logic lives in our base page (reviewed, tested, version-controlled) rather than being forked into the vendor tree. Do not file upstream issues as our resolution path.
Scaling. Query cost is one database query per action per render — so typically two extra queries per ViewRecord/EditRecord load, resolved from an in-render cache so additional closure evaluations are free. That is acceptable at any traffic level we're likely to see in an admin panel. The scaling concern is not query volume but query shape: the adjacent-record lookup relies on order_column being indexed. On large tables with an unindexed timestamp or sort column, each page render does a filtered sort the database cannot satisfy from an index. Index the order column as part of rollout — treat it as a required step, not an optimization.
Failure modes.
order_column, or duplicate values in a timestamp column (records with identical created_at never find each other). Detectable in the pilot; symptom is user confusion, not error.NavigationPage::custom('x') where 'x' isn't an exact key in getPages(). Casing and hyphens matter. A typo yields an InvalidArgumentException on click.Ramp-up. Effectively none: a developer already comfortable with Filament actions is productive in under an hour, and the README is unusually good — installation, page-type targeting, custom routes, override recipes, and a troubleshooting section that preempts the exact failure modes above. The onboarding cost is not learning the package; it's learning our convention for ordering and scoping. Write that down, or every developer will configure ordering independently and the panel will behave inconsistently.
Recommendation. Adopt conditionally: run the tenancy/policy spike first, add the index on the order column, and encode ordering plus scoping conventions in our base resource page before broad rollout. The package's low score reflects community traction, not engineering quality — for a bounded admin-UX affordance, that's an acceptable trade given MIT licensing and a forkable footprint.
How can I help you explore Laravel packages today?