Looking to hire Laravel developers? Try LaraJobs

laravel-changelog maintained by asdrubalp9

Description
Role-targeted changelog entries with per-user read tracking for Laravel.
Author
Last update
2026/10/04 15:44 (dev-main)
License
Links
Downloads
19

Comments
comments powered by Disqus

Laravel Changelog

Publish role-targeted changelog entries and track what each user has read. Backend only: you build the interface.

Installation

composer require asdrubalp9/laravel-changelog
php artisan vendor:publish --tag=changelog-config
php artisan vendor:publish --tag=changelog-migrations
php artisan migrate

Set key_type, morph_key_type and scope_type to uuid before you migrate if your users table uses uuid keys. The package works on PostgreSQL, MySQL and SQLite.

Minimal configuration

Define the ability the administration routes check. Without it, every administration route responds 403:

Gate::define('manage-changelog', fn (User $user) => $user->hasRole('platform-admin'));

The default routes.user_middleware and routes.admin_middleware are ['api', 'auth:sanctum']. Override both if you do not use Sanctum.

Audience

An entry lists the roles that can see it. A reader sees an entry if they have any of those roles. An entry with no roles is visible to everyone.

The package does not know your role system. It asks ResolvesAudience. The default implementation calls getRoleNames() when the user model has it (spatie/laravel-permission) and returns no roles otherwise.

$this->app->bind(ResolvesAudience::class, MyAudience::class);

knownRoles() returns the valid role names, or null to skip validation. Role names are stored as text. If you rename a role, entries that list the old name stop being visible and nothing reports it. Return your roles from knownRoles() so the administration API rejects a typo with a 422.

Markdown

body is stored as Markdown. Set render_html to true to also receive body_html. The package removes raw HTML and unsafe links (javascript:) and does not let you turn that off. render_html needs league/commonmark, which laravel/framework already requires.

API

User routes, under routes.prefix (default changelog):

Method Path Result
GET entries Page of visible entries with read
GET unread-count { "data": { "unread": 3 } }
POST entries/{id}/read 204. 404 if not visible
POST read-all { "data": { "unread": 0 } }

Administration routes, under admin/:

Method Path Result
GET entries List, filter with ?status=draft|scheduled|live|expired
GET entries/{id} Detail with roles
POST entries 201
PUT entries/{id} 200, JSON
DELETE entries/{id} Soft delete
POST entries/{id}/publish Sets published_at to now unless already live
POST entries/{id}/unpublish Back to draft
POST entries/{id}/image Upload or replace, multipart
DELETE entries/{id}/image Remove

The image goes through POST. PHP does not populate uploaded files for a multipart PUT.

Dates

published_at and expires_at are normalized to app.timezone before they are stored. Laravel assumes app.timezone equals the database session timezone. Keep both in UTC.

Scopes

changelog_reads.scope_id holds a value from the ResolvesReaderScope contract. It lets your app write a row-level security policy without a join. The package never reads it.