<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alberto Arena</title>
    <description>The latest articles on DEV Community by Alberto Arena (@alberto_arena_25a48484ed5).</description>
    <link>https://dev.to/alberto_arena_25a48484ed5</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1584618%2F8916c43c-3e5f-4896-b701-9e82ab63893f.jpeg</url>
      <title>DEV Community: Alberto Arena</title>
      <link>https://dev.to/alberto_arena_25a48484ed5</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alberto_arena_25a48484ed5"/>
    <language>en</language>
    <item>
      <title>What if every Filament write went through an aggregate?</title>
      <dc:creator>Alberto Arena</dc:creator>
      <pubDate>Tue, 23 Jun 2026 13:15:35 +0000</pubDate>
      <link>https://dev.to/alberto_arena_25a48484ed5/what-if-every-filament-write-went-through-an-aggregate-49c6</link>
      <guid>https://dev.to/alberto_arena_25a48484ed5/what-if-every-filament-write-went-through-an-aggregate-49c6</guid>
      <description>&lt;p&gt;Filament is a great admin panel. Event sourcing is a great architectural pattern. Getting the two to work together, though, has always meant compromises: either you bypass your aggregates and write directly to the database, or you ditch Filament's create/edit flows and build everything from scratch. I've been using both in the same projects for a while, and that friction kept bothering me. So I built a plugin to remove it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/albertoarena/filament-event-sourcing" rel="noopener noreferrer"&gt;filament-event-sourcing&lt;/a&gt; is a Filament plugin that intercepts the standard create, edit, and delete actions and routes them through your domain aggregates. Your forms stay the same. Your validations and notifications stay the same. The only change is what happens on write: instead of an Eloquent save, the data flows through your aggregate and gets stored as a domain event. The read model is still updated by your projectors, exactly as you'd expect.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get out of the box
&lt;/h2&gt;

&lt;p&gt;The plugin ships with a few things I found myself needing every time I mixed Filament with event sourcing.&lt;/p&gt;

&lt;p&gt;The first is an event history browser. Every record gets a dedicated view of its event log: event class, timestamp, version, and the full JSON payload on expand. It's available either as a relation manager tab or as a slide-over action on the table. No extra setup, add the trait to your resource and it appears.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjrr66xvxb2tpi4xzyvt0.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjrr66xvxb2tpi4xzyvt0.webp" alt="Per-record event history with expandable JSON payloads" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second is a system-wide stored events browser. This gives you a searchable, filterable view of every event in your application, across all aggregates. You can filter by event class, aggregate UUID, or date range. It's read-only by design, which keeps the event log immutable.&lt;/p&gt;

&lt;p&gt;The third is a projector replay page. You can trigger a replay for any registered projector directly from the admin panel, one at a time, with a live count of how many events were processed. Access is controlled by a three-layer authorization system: a plugin-level option, a config flag, and a Gate ability for fine-grained control.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to install it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require albertoarena/filament-event-sourcing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll need Laravel 11 or 12, Filament 4.0+, and Spatie's &lt;code&gt;laravel-event-sourcing&lt;/code&gt; 7.0+. The plugin registers itself automatically via Filament's plugin system.&lt;/p&gt;

&lt;p&gt;From there, you add two traits to your resource (&lt;code&gt;CreatesEventSourcedRecord&lt;/code&gt; and &lt;code&gt;EditsEventSourcedRecord&lt;/code&gt;), wire up the delete action, and the rest is your aggregate logic. The plugin doesn't try to generate your events or commands, that's your domain, and it should stay that way.&lt;/p&gt;

&lt;p&gt;A full working example with a &lt;code&gt;Post&lt;/code&gt; entity is available in the &lt;a href="https://github.com/albertoarena/filament-event-sourcing-demo/" rel="noopener noreferrer"&gt;demo repository&lt;/a&gt;, which walks through the complete setup from aggregate to Filament resource.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to go from here
&lt;/h2&gt;

&lt;p&gt;The package is at version 0.1.0 and working. There's more I want to add, but the core is solid enough to use in real projects today. The &lt;a href="https://albertoarena.github.io/filament-event-sourcing/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; covers installation, each feature in detail, configuration, and authorization. If you're already using Spatie's event sourcing package with Filament, this plugin is probably the missing piece.&lt;/p&gt;

&lt;p&gt;Feedback and contributions are welcome.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>eventsourcing</category>
      <category>filament</category>
    </item>
    <item>
      <title>Your README Deserves Real Numbers</title>
      <dc:creator>Alberto Arena</dc:creator>
      <pubDate>Fri, 05 Jun 2026 07:21:44 +0000</pubDate>
      <link>https://dev.to/alberto_arena_25a48484ed5/your-readme-deserves-real-numbers-lhb</link>
      <guid>https://dev.to/alberto_arena_25a48484ed5/your-readme-deserves-real-numbers-lhb</guid>
      <description>&lt;p&gt;If you maintain an open-source repo, you have probably wondered at some point how many people actually visit it. GitHub has the answer buried in the Insights tab, but nobody looks there. It resets after 14 days, there is no history, and your README, the thing everyone sees, tells them nothing.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://github.com/marketplace/actions/traffic-badge" rel="noopener noreferrer"&gt;traffic-badge&lt;/a&gt; to fix that.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;It is a GitHub Action that runs on a schedule, hits the official GitHub Traffic API, and commits a live SVG badge to a dedicated branch in your repo. You embed that badge in your README once and it updates automatically from then on.&lt;/p&gt;

&lt;p&gt;The badge shows whatever you care about: total views, unique visitors, clones, unique cloners. One workflow file per metric, or stack them all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it is different from the alternatives
&lt;/h2&gt;

&lt;p&gt;A lot of traffic badge solutions rely on a third-party counting server. Which means you are trusting someone else's infrastructure, someone else's uptime, and someone else's definition of "a view." When that server goes down or changes its counting logic, your badge quietly becomes wrong.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;traffic-badge&lt;/code&gt; does not phone home. The numbers come straight from GitHub's own API, the same data you would see in your Insights tab. The raw JSON is committed to your repo under a &lt;code&gt;traffic-data&lt;/code&gt; branch, so you can inspect every data point, diff it, delete it, whatever you want. Full transparency.&lt;/p&gt;

&lt;p&gt;It also handles the awkward overlap problem. GitHub's Traffic API returns a rolling 14-day window, so if you run the action daily you would normally double-count the days that appear in both runs. &lt;code&gt;traffic-badge&lt;/code&gt; deduplicates by date automatically, so your cumulative totals stay accurate without any extra work on your end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting it up
&lt;/h2&gt;

&lt;p&gt;First, a heads-up that saves you the most common mistake: the default &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; does not work here. The Traffic API requires push or admin access, which that token does not have, so it fails with &lt;code&gt;403 Resource not accessible by integration&lt;/code&gt;. You need a Personal Access Token instead: a classic PAT with the &lt;code&gt;repo&lt;/code&gt; scope, or a fine-grained PAT with &lt;code&gt;Administration: read&lt;/code&gt; on the repo. Add it as a repository secret called &lt;code&gt;TRAFFIC_TOKEN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then add a workflow file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Traffic Badge&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;badge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;albertoarena/github-traffic-badge@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.TRAFFIC_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;metric&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;views&lt;/span&gt;
          &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;blue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it once manually, then grab the badge URL it creates and drop it in your README:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;Views&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://raw.githubusercontent.com/OWNER/REPO/traffic-data/badge.svg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is it. No server to maintain, no API key for a third-party service, no monthly bill. It runs on free GitHub-hosted runners.&lt;/p&gt;

&lt;h2&gt;
  
  
  The options worth knowing
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;metric&lt;/code&gt; field accepts &lt;code&gt;views&lt;/code&gt;, &lt;code&gt;clones&lt;/code&gt;, &lt;code&gt;views-unique&lt;/code&gt;, and &lt;code&gt;clones-unique&lt;/code&gt;. You can run multiple workflows with different metrics if you want to show both.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;color&lt;/code&gt; takes any named colour or a hex value. &lt;code&gt;style&lt;/code&gt; supports the standard shields.io styles: &lt;code&gt;flat&lt;/code&gt;, &lt;code&gt;flat-square&lt;/code&gt;, &lt;code&gt;plastic&lt;/code&gt;, &lt;code&gt;for-the-badge&lt;/code&gt;. And if your numbers get large enough that the badge looks cluttered, there is an &lt;code&gt;abbreviated&lt;/code&gt; flag that turns &lt;code&gt;12345&lt;/code&gt; into &lt;code&gt;12.3K&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A note on how it is built
&lt;/h2&gt;

&lt;p&gt;If you like to read the code before trusting an Action with a PAT, it is worth a look. Zero runtime dependencies, Node 20+ with built-in &lt;code&gt;fetch&lt;/code&gt; and the built-in test runner. The counting and rendering logic is written as pure functions with the network, filesystem, and clock injected, so it is fully tested without touching disk or hitting the API. The zero-dependency constraint is enforced in CI.&lt;/p&gt;




&lt;p&gt;It is open source, MIT licensed, and available on the &lt;a href="https://github.com/marketplace/actions/traffic-badge" rel="noopener noreferrer"&gt;GitHub Marketplace&lt;/a&gt;. The source is at &lt;a href="https://github.com/albertoarena/github-traffic-badge" rel="noopener noreferrer"&gt;albertoarena/github-traffic-badge&lt;/a&gt;. If you run into anything odd or have a feature request, issues are open.&lt;/p&gt;

</description>
      <category>github</category>
      <category>githubactions</category>
      <category>opensource</category>
      <category>devtools</category>
    </item>
  </channel>
</rss>
