anselmokossa/filament-changelog
A Filament plugin for displaying and managing changelogs and release notes directly in your admin panel, so users can stay informed about updates without leaving the app.
Install and register
composer require anselmokossa/filament-changelog
Register the plugin on the panel you want the changelog UI available in (typically an admin/staff panel, not a customer-facing one):
use AnselmoKossa\FilamentChangelog\FilamentChangelogPlugin;
public function panel(Panel $panel): Panel
{
return $panel
->plugin(FilamentChangelogPlugin::make());
}
Publish and migrate
php artisan vendor:publish --tag="filament-changelog-config"
php artisan vendor:publish --tag="filament-changelog-migrations"
php artisan migrate
Check the published config for the path to the target CHANGELOG.md, the section labels it manages, and the default navigation group.
Where to look first, in order
navigationGroup, navigationLabel, shouldRegisterNavigation) that will be your main customization surface.src/Filament/Resources/ — this tells you the entry schema (version, type, description, date, unreleased flag) far faster than any README.config/filament-changelog.php once published.First use case that proves the package
added, version Unreleased, and a short description.CHANGELOG.md in your repo.If the file matches Keep a Changelog's expected shape (## [Unreleased] followed by ### Added etc.), the package is wired correctly and you can start building the release workflow on top of it.
Given the package's maturity (4 stars, 0 dependents), treat the source as the documentation. Budget an hour to read the resource, the model, and the generator before committing it to a production workflow.
Database as source of truth, Markdown as a build artifact
The strongest way to use this package is to treat the DB table as canonical and CHANGELOG.md as generated output. Never hand-edit the file — otherwise the next regeneration silently discards your edits. If you need manual prose (e.g. a migration note), model it as an entry type or add a field, don't edit the artifact.
The Unreleased → release promotion flow
The natural lifecycle the package is built around:
Unreleased as you merge PRs.Unreleased to a concrete version (1.4.0) with today's date.CHANGELOG.md, commit it as part of the release commit (or tag commit), and let a new empty Unreleased section begin.Wire this into whatever release tooling you already have (a make release target, a GitHub Action step, or a Filament action button) so the changelog is never a manual afterthought.
Seeding from an existing CHANGELOG.md
If the project already has a hand-maintained changelog, do the one-time import before switching:
tinker session or an artisan command, parse sections with a simple regex over ## / ### headings and insert rows matching the package's schema.Keep the backup until the generated output is stable across two regenerations.
Exposing "What's new" to end users
Because the data is in the DB, you are not limited to the admin resource. A small custom Livewire component or a Filament widget can query the same model and show the last N released entries to logged-in users. Query only rows where the version is not Unreleased and the date is <= now() so drafts never leak.
CI integration
Two viable patterns:
The first pattern is almost always the right call for a package this small; the second only pays off if the changelog must be produced by many people who can't be trusted to click a button.
Panel scoping and permissions
Use the plugin's fluent API to hide the resource from non-staff panels, and pair it with your existing policies (canViewAny, canCreate) so only release managers can promote Unreleased. Changelog editing is a write-heavy operation on a file — restrict it accordingly.
Custom section types
Keep a Changelog defines Added, Changed, Deprecated, Removed, Fixed, Security. If your team uses extras (Performance, Docs), extend the config's type map rather than overloading Changed — the generator's section ordering is usually driven by that map.
File writes fail silently or loudly depending on permissions. The web server user must be able to write to the CHANGELOG.md path. If the path is outside storage/ (e.g. the repo root), this is the single most common failure. Check storage/logs/laravel.log first; if the write is wrapped in a try/catch, the UI may look successful while the file is untouched. Always diff the file after your first generation.
Regeneration is destructive. Unless the generator is explicitly idempotent over hand-written content (verify in the source), assume it rewrites the whole file. There is no merge — any prose you added by hand disappears. Make this a rule in your team docs.
Publish tags are easy to miss. If you register the plugin without publishing and running the migration, you get a confusing "table not found" error the moment the resource mounts. Same for config: a missing published config means your CHANGELOG.md path customization is ignored and you'll chase a phantom. Run both vendor:publish commands explicitly.
Cache the config out of your debugging loop. php artisan config:clear (and optimize:clear if you use it) after editing the published config, or you will spend twenty minutes wondering why your change to the navigation group did nothing.
Dates and timezone. Release dates written to the file are typically taken from now(). On a server set to UTC you may ship a changelog entry dated yesterday for a user in your timezone. If date accuracy matters, set the app timezone explicitly or override the date field in the entry form.
Version ordering. Keep a Changelog expects newest-first. If the generator sorts lexically, 1.10.0 lands before 1.9.0. Sort with version_compare or composer/semver (already in most Laravel projects) in any query you write yourself, and confirm the resource's default sort behaves the same.
Section ordering is part of the spec. Added → Changed → Deprecated → Removed → Fixed → Security. If the generated file reorders sections when entries are inserted in a different order, pin the order in the generator config rather than relying on insertion order.
Merge conflicts on CHANGELOG.md. Two long-lived branches both regenerating the file will conflict. Either only generate on main after merge, or keep the file out of feature branches entirely. This is the most common reason teams abandon a hybrid DB+file workflow.
Extension points, in order of least pain
vendor:publish --tag=filament-changelog-views.Debug the generation step in isolation. When the file looks wrong, call the generator directly from tinker or a one-off artisan command with a fixed set of entries, and inspect the raw string before it is written. That separates "the data is wrong" from "the serializer is wrong" in one step.
Small-package expectations. With four stars and zero dependents, there is no community to catch regressions. Pin the version in composer.json, write a feature test that generates a changelog from a known set of entries and asserts the exact output string, and re-run it whenever you upgrade. That test is your changelog's regression suite, not the package's responsibility.
How can I help you explore Laravel packages today?