<?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: Cristobal Chacon</title>
    <description>The latest articles on DEV Community by Cristobal Chacon (@appspesic).</description>
    <link>https://dev.to/appspesic</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%2F4209776%2Fbd5d3313-ca0e-4d1a-8d16-70659554d2cf.png</url>
      <title>DEV Community: Cristobal Chacon</title>
      <link>https://dev.to/appspesic</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/appspesic"/>
    <language>en</language>
    <item>
      <title>Why I sell the complete source code of a Laravel platform in the AI era</title>
      <dc:creator>Cristobal Chacon</dc:creator>
      <pubDate>Tue, 27 Oct 2026 14:32:29 +0000</pubDate>
      <link>https://dev.to/appspesic/why-i-sell-the-complete-source-code-of-a-laravel-platform-in-the-ai-era-21da</link>
      <guid>https://dev.to/appspesic/why-i-sell-the-complete-source-code-of-a-laravel-platform-in-the-ai-era-21da</guid>
      <description>&lt;p&gt;Most software purchases end with a login and a promise. You get access, not ownership. If you want a new field, a different report, or your own branding, you open a ticket and wait.&lt;/p&gt;

&lt;p&gt;I wanted to sell the opposite: a complete Laravel codebase that a team can open in Cursor, Claude Code or Copilot and actually change.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "complete" means
&lt;/h2&gt;

&lt;p&gt;SuGuardia is a multi-tenant Laravel 12 platform for field operations and emergency alerts. The package I sell has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;682 source files and 133,610 readable lines;&lt;/li&gt;
&lt;li&gt;central and per-tenant migrations;&lt;/li&gt;
&lt;li&gt;Blade, Vite and Tailwind frontend assets;&lt;/li&gt;
&lt;li&gt;an offline-first PWA with IndexedDB sync;&lt;/li&gt;
&lt;li&gt;README, INSTALL, architecture and validation docs;&lt;/li&gt;
&lt;li&gt;no encoded or obfuscated code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point matters more in the AI era than it did before. An AI assistant can only help with code it can read. A closed SaaS gives it nothing to work with.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a buyer can ask an AI to change
&lt;/h2&gt;

&lt;p&gt;A realistic prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Rename 'Guardia' to 'Operador' across the project, update views, permissions and PDF reports. Do not change the tenancy logic. Show me the diff and the tests."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is not a magic one-click rewrite. It is a normal engineering workflow: the AI proposes a diff, a developer reviews it, runs the tests and deploys. But the starting point is a real codebase with migrations, policies and documentation, not a blank file.&lt;/p&gt;

&lt;p&gt;Other examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add a &lt;code&gt;severity&lt;/code&gt; field to incidents (migration, request, view, PDF);&lt;/li&gt;
&lt;li&gt;change the report layout for a client;&lt;/li&gt;
&lt;li&gt;integrate an ERP, CRM or local payment gateway;&lt;/li&gt;
&lt;li&gt;adapt roles and permissions to a different operation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I deliberately do not include
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;support, SLA or consulting;&lt;/li&gt;
&lt;li&gt;installation, hosting or maintenance;&lt;/li&gt;
&lt;li&gt;customer data, credentials, APKs or third-party accounts;&lt;/li&gt;
&lt;li&gt;a monthly subscription.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is a one-time commercial license for one implementation. The buyer's team installs it with the docs. That is the trade-off: lower price, more autonomy, no hand-holding.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest part
&lt;/h2&gt;

&lt;p&gt;AI does not remove the need for engineers. It removes the "I have to rewrite this from scratch" tax. The buyer still needs someone who can review a diff, run migrations and test a deployment.&lt;/p&gt;

&lt;p&gt;If you are evaluating a source-code purchase, ask for three things: the file count, the migrations, and a real README. If any of those are missing, you are probably buying a demo, not a codebase.&lt;/p&gt;

&lt;p&gt;The landing page with the full breakdown is here: &lt;a href="https://suguardia.appspesic.cl/codigo-ia.html" rel="noopener noreferrer"&gt;https://suguardia.appspesic.cl/codigo-ia.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I'm the author and I sell this source-code license. No customers, revenue or production data are included.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What I learned building a multi-tenant Laravel platform for panic alerts and field operations</title>
      <dc:creator>Cristobal Chacon</dc:creator>
      <pubDate>Tue, 27 Oct 2026 02:39:01 +0000</pubDate>
      <link>https://dev.to/appspesic/what-i-learned-building-a-multi-tenant-laravel-platform-for-panic-alerts-and-field-operations-2c6c</link>
      <guid>https://dev.to/appspesic/what-i-learned-building-a-multi-tenant-laravel-platform-for-panic-alerts-and-field-operations-2c6c</guid>
      <description>&lt;p&gt;I spent the last few months working on a Laravel 12 platform that combines two things that usually live in separate products: &lt;strong&gt;field operations&lt;/strong&gt; (sites, shifts, patrols, incidents, evidence) and &lt;strong&gt;emergency alerts&lt;/strong&gt; (panic buttons, eWeLink relays, PWA clients, alert monitoring).&lt;/p&gt;

&lt;p&gt;The result is a multi-tenant application with a central control plane, isolated tenant databases, an offline-first PWA and a relay integration that has to work when the network does not.&lt;/p&gt;

&lt;p&gt;This is not a “look at my SaaS” post. I packaged the source code as a one-time commercial license, so I want to share the engineering decisions that mattered and the parts I would do differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  The architecture
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Laravel 12 / PHP 8.2+&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stancl Tenancy&lt;/strong&gt; with one central database and one database per tenant&lt;/li&gt;
&lt;li&gt;Blade + Vite + Tailwind for the admin and tenant UI&lt;/li&gt;
&lt;li&gt;An installable PWA with IndexedDB sync for guards and community users&lt;/li&gt;
&lt;li&gt;Web Push for alert notifications&lt;/li&gt;
&lt;li&gt;eWeLink Cloud/WebSocket plus an optional local relay agent&lt;/li&gt;
&lt;li&gt;Dompdf for incident and shift reports&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The central database stores organizations, tenants, plans, modules, users and branding. Each tenant gets its own database and runs tenant-aware migrations. The tenant bootstrapper selects the connection per request and per queued job.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was actually hard
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Tenant isolation is not just a where clause
&lt;/h3&gt;

&lt;p&gt;The dangerous bugs are not the obvious ones. They are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a queued job that runs without tenant context;&lt;/li&gt;
&lt;li&gt;a global scope that is bypassed by a raw query;&lt;/li&gt;
&lt;li&gt;a cache key that does not include the tenant ID;&lt;/li&gt;
&lt;li&gt;a file path shared between tenants;&lt;/li&gt;
&lt;li&gt;an admin route that forgets the tenant middleware.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I ended up treating tenant context as part of every boundary: request, job, cache key, filesystem path and notification. If a code path can run without a tenant, it needs an explicit “central” decision.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Offline-first is a conflict-resolution problem
&lt;/h3&gt;

&lt;p&gt;The PWA lets guards capture check-ins, incidents and evidence without connectivity. The sync queue is not just “POST when online”. You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;client-generated IDs so retries are idempotent;&lt;/li&gt;
&lt;li&gt;a server-side deduplication key;&lt;/li&gt;
&lt;li&gt;explicit conflict states instead of silently overwriting;&lt;/li&gt;
&lt;li&gt;a visible sync status for the user;&lt;/li&gt;
&lt;li&gt;a safe way to expire stale local data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most useful decision was to store the sync state on the client and on the server, not only in memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Relay state is eventually consistent
&lt;/h3&gt;

&lt;p&gt;A panic button is a physical action. The relay may be online, offline, busy or reporting a stale state. The platform has to separate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;logical alert state&lt;/strong&gt; (the event exists and needs a response);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;device state&lt;/strong&gt; (the relay acknowledged the command);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;operator state&lt;/strong&gt; (someone acknowledged and is handling it).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Trying to make those one field produces false “closed” alerts. Keeping them separate made the monitoring screen honest.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Multi-tenant permissions get deep
&lt;/h3&gt;

&lt;p&gt;Roles are not enough. You need role + module + tenant + record-level checks. A supervisor in tenant A must not see tenant B, even if the role key is the same. Permissions also need to be cached per tenant, not globally.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would do differently
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Start with a &lt;strong&gt;tenant context test suite&lt;/strong&gt; before building features.&lt;/li&gt;
&lt;li&gt;Put &lt;strong&gt;idempotency keys&lt;/strong&gt; on every device command from day one.&lt;/li&gt;
&lt;li&gt;Treat the &lt;strong&gt;PWA sync queue&lt;/strong&gt; as a first-class module, not a helper.&lt;/li&gt;
&lt;li&gt;Add &lt;strong&gt;observability&lt;/strong&gt; for relay latency and queue lag earlier.&lt;/li&gt;
&lt;li&gt;Keep a &lt;strong&gt;single source of truth&lt;/strong&gt; for alert status transitions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The source-code option
&lt;/h2&gt;

&lt;p&gt;I decided to sell the source code instead of running a SaaS. The buyer deploys it on their own infrastructure, adapts it to their market and operates it locally. The package includes the central/tenant migrations, the PWA, the relay integration, documentation and a commercial license.&lt;/p&gt;

&lt;p&gt;If you are building something similar, the two products are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SuGuardia&lt;/strong&gt; — field operations, patrols, incidents, PWA and PDF reports: &lt;a href="https://cristobalchacon.gumroad.com/l/suguardia-enterprise-source-code?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=source-code" rel="noopener noreferrer"&gt;source code&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PulsoAlerta&lt;/strong&gt; — panic alerts, eWeLink relays, PWA and operations, with an optional POS/ERP module: &lt;a href="https://cristobalchacon.gumroad.com/l/pulsoalerta-source-code?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=source-code" rel="noopener noreferrer"&gt;source code&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is also a smaller Android TV remote-control project, &lt;strong&gt;FlashLink MX10&lt;/strong&gt;: &lt;a href="https://cristobalchacon.gumroad.com/l/flashlink-mx10-source-code?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=source-code" rel="noopener noreferrer"&gt;source code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I'm the author and I sell these source-code licenses. No customers, revenue or production data are included.&lt;/p&gt;

&lt;p&gt;If you have built multi-tenant Laravel apps with offline sync or device integrations, I would like to hear what broke first in your case.&lt;/p&gt;

</description>
      <category>webdev</category>
    </item>
  </channel>
</rss>
