oi-lab / oi-laravel-changelogs
A markdown-based change log journal for Laravel: artisan commands to write and check entries, and a ready-to-install Inertia/React screen to read them
Requires
- php: ^8.2
- illuminate/cache: ^11.0|^12.0|^13.0
- illuminate/console: ^11.0|^12.0|^13.0
- illuminate/contracts: ^11.0|^12.0|^13.0
- illuminate/filesystem: ^11.0|^12.0|^13.0
- illuminate/http: ^11.0|^12.0|^13.0
- illuminate/pagination: ^11.0|^12.0|^13.0
- illuminate/routing: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
- league/commonmark: ^2.0
- spatie/laravel-data: ^4.23
- symfony/yaml: ^6.0|^7.0|^8.0
Requires (Dev)
- inertiajs/inertia-laravel: ^1.0|^2.0
- laravel/pint: ^1.29
- orchestra/testbench: ^9.0|^10.0|^11.0
- pestphp/pest: ^3.0|^4.0
- pestphp/pest-plugin-laravel: ^3.0|^4.0
Suggests
- inertiajs/inertia-laravel: Required to render the change log screen (^1.0|^2.0)
Provides
None
Conflicts
None
Replaces
None
README
OI Laravel Changelogs
The journal of what was fixed and what was improved in your application, kept as markdown in the repository and read on a screen inside the application. One file per entry, written in the same pull request as the work it describes, reviewed with it and deployed with it — no table, no migration, and nothing that has to be regenerated by hand. The package brings the reader, two artisan commands to write and to police the entries, and a set of Inertia/React stubs you install into your own application and then own outright.
Features
- Entries are files.
resources/markdown/change-logs/2026-09-12-a-slug.md, frontmatter plus prose, diffed and reviewed like everything else. - A screen to read them. List on the left, entry on the right, previous and next walking the list; opening an entry is a fetch, so the column keeps its scroll and the url still follows.
change-log:makeopens an entry with the frontmatter filled in — HEAD included, because the hash exists in the terminal and not in your head.change-log:checkholds every entry to the format and prints the tag vocabulary in use, so it belongs in your test suite.- Typed all the way out.
spatie/laravel-dataobjects on the wire, sooi-laravel-tscan generate the TypeScript interfaces. - Server- or client-side markdown. Laravel converts it with
league/commonmark, or the browser does withreact-markdown— one config key, and the installer publishes only the renderer you chose. - Neutral stubs. Plain Shadcn UI components — badge, button, item, empty, skeleton — with no design system of ours in them.
- Nothing to regenerate. The repository fingerprints the directory: a file added is a file shown.
How It Works
The package never writes an entry at runtime and has no endpoint that could. Reading is three objects deep:
| Object | What it is |
|---|---|
ChangeLogRepository |
parses the directory, caches the parse under a fingerprint of it, and answers the list, one entry, and the two either side of it |
ChangeLogEntry |
one parsed file: slug, title, date, type, tags, commits, the opening paragraph, the body |
ChangeLogMarkdown |
the CommonMark converter, kept as a singleton because it is expensive to build and holds nothing |
Two shapes leave the server rather than one. ChangeLogRowData is what the
list column draws — frontmatter and the opening paragraph — and there may be a
hundred of them on a page. ChangeLogEntryData is the entry being read, with
its content in whichever form the configured engine asked for. Sending the
second shape for every row would put the whole journal on the wire to draw a
column 24rem wide.
The screen is one page behind two routes. change-logs.show answers json to a
fetch and the whole page to an Inertia visit or a cold browser, so the pane the
reader swaps and the page a pasted link opens can never drift apart.
Requirements
- PHP 8.2+
- Laravel 11, 12, or 13
spatie/laravel-data^4.23,league/commonmark^2.0,symfony/yamlinertiajs/inertia-laravel^1.0|^2.0 and a React front end, to use the published screen
Installation
composer require oi-lab/oi-laravel-changelogs
Then run the installer, which asks who may read the journal, where the markdown should be converted, and writes the screen into your application:
php artisan change-log:install
It publishes the config, creates the change log directory with one example entry, installs the React files, and offers to add the Shadcn UI components the screen draws with. Everything it writes is yours afterwards — the package renders nothing itself.
npm run build
Visit /change-logs.
Publish only the configuration
php artisan vendor:publish --tag=oi-laravel-changelogs-config
Configuration
// config/oi-laravel-changelogs.php 'changelog_path' => 'resources/markdown/change-logs', // Where the installer writes the React files. The pages path also decides the // Inertia component the controller renders: "resources/js/pages/console/change-logs" // is rendered as "console/change-logs/index", so moving the screen into your // console space is a one-line change and no code edit. 'components_path' => 'resources/js/components/change-logs', 'pages_path' => 'resources/js/pages/change-logs', 'route' => [ 'enabled' => env('OI_CHANGELOGS_ROUTES', true), 'prefix' => 'change-logs', 'name' => 'change-logs.', 'middleware' => ['web'], ], 'rendering' => [ 'markdown_engine' => 'server', // or 'client' 'ssr' => false, 'typeset' => false, ], 'entries' => [ 'locale' => null, // null = the app's locale 'summary_words' => ['min' => 30, 'max' => 75], 'max_tags' => 5, ], 'per_page' => 20, 'cache' => ['store' => null, 'ttl' => 3600],
Set route.enabled to false to keep the reader and declare your own routes
against ChangeLogController — inside an authenticated console group, for
instance.
Usage
Write an entry
The commit has to exist before the entry can name it, so: commit the fix, then open the entry.
php artisan change-log:make "The dashboard came back blank" \
--type=fix \
--tag=console --tag=teams
With no --commit, it fills in HEAD — the commit you just made. The file lands
at resources/markdown/change-logs/2026-09-12-the-dashboard-came-back-blank.md
with its frontmatter written and two placeholders where the prose goes:
--- title: The dashboard came back blank date: 2026-09-12 type: fix tags: - console - teams commits: - 9a9ab33 --- One paragraph of 30 to 75 words: what the person in front of the screen saw, then why it happened. It is the summary the list column shows, taken from the body so there is nowhere for a second copy to drift. ## Changes - What was changed, one bullet per change, in the past tense. - End with the tests added, when there are any.
An entry is a subject, not a commit: three commits fixing one thing are one
entry with three hashes in its commits:.
Check the format
php artisan change-log:check
It names everything wrong with every file — a date the file name disagrees
with, a tag that is not lowercase, an opening paragraph outside the word
bounds, a TODO left in the text — and ends by printing the tags in use with
how many entries each one holds, which is how you spot two spellings of one
subject.
The screen skips a malformed file rather than throwing on it, so put the checker in your test suite and a file that would silently vanish fails the build instead:
it('keeps every change log entry well formed', function () { $this->withoutMockingConsoleOutput(); expect($this->artisan('change-log:check'))->toBe(0); });
Read the journal somewhere else
use OiLab\OiLaravelChangelogs\Services\ChangeLogRepository; public function __construct(private readonly ChangeLogRepository $changeLogs) {} $latest = $this->changeLogs->all()->take(3); // Collection<ChangeLogEntry> $page = $this->changeLogs->paginate(20, 1, $url); // of ChangeLogRowData $entry = $this->changeLogs->find('2026-09-12-a-slug'); $detail = $this->changeLogs->detail($entry); // ChangeLogEntryData ['previous' => $previous, 'next' => $next] = $this->changeLogs->adjacent($entry->slug);
The Published Screen
The installer writes, and you own:
resources/js/components/change-logs/
├── types.ts # ChangeLogRow, ChangeLogEntry, ChangeLogAnswer
├── change-log-row.tsx # one row of the list
├── change-log-detail.tsx # the entry, and the two buttons that walk the list
├── change-log-pagination.tsx # previous / next / counter
├── change-log-html-content.tsx # rendering.markdown_engine = "server"
└── change-log-markdown-content.tsx # rendering.markdown_engine = "client"
resources/js/lib/change-log-typography.ts
resources/js/lib/change-log-date.ts
resources/js/layouts/change-logs-layout.tsx
resources/js/pages/change-logs/index.tsx
Only the renderer you chose is installed, and the import of the other one is
taken out of change-log-detail.tsx — an unused import of react-markdown is
a dependency you would have to install to build.
The layout is the neutral one, and the page names it at the bottom:
ChangeLogsIndex.layout = (page: ReactNode) => ( <ChangeLogsLayout>{page}</ChangeLogsLayout> );
Point it at your application's own layout, keeping the two constraints the
neutral one carries: cap the wrapper at h-svh and let min-h-0 through. An
application shell is usually min-h-svh, a floor — and a pane asked to scroll
inside a floor never does.
TypeScript Interfaces
The two Data classes are what oi-laravel-ts generates from, so the published
types.ts can be replaced by your generated interfaces:
php artisan oi:gen-ts
AI Assistant Skills
The package ships a skill teaching an AI assistant when an entry is owed, how one entry covers one subject, and the format the checker enforces. Install it into the host application:
php artisan oi:skills oilab-laravel-changelogs --project
It is the skill to activate right after committing a fix — before the task is considered done.
Testing
composer test
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
When contributing:
- Write tests for new features
- Ensure all tests pass:
vendor/bin/pest - Follow existing code style
- Update documentation as needed
License
The MIT License (MIT). Please see the License File for more information.
Credits
Olivier Lacombe - Creator and maintainer
Olivier is a Product & Technology Director based in Montpellier, France, with over 20 years of experience innovating in UX/UI and emerging technologies. He specializes in guiding enterprises toward cutting-edge digital solutions, combining user-centered design with continuous optimization and artificial intelligence integration.
Projects & Resources:
- OI Dev Docs - Documentation for all Open Source OI Lab packages
- OnAI - Training courses and masterclasses on generative AI for businesses
- Promptr - Prompt engineering Management Platform
Support
For support, please open an issue on the GitHub repository.
