<?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: Manuk</title>
    <description>The latest articles on DEV Community by Manuk (@manukminasyan).</description>
    <link>https://dev.to/manukminasyan</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1392447%2F052628e5-071c-4a72-9c28-538bc567dac8.jpeg</url>
      <title>DEV Community: Manuk</title>
      <link>https://dev.to/manukminasyan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/manukminasyan"/>
    <language>en</language>
    <item>
      <title>How I Rebuilt CSV Imports to Handle 10,000 Messy Rows Without Breaking</title>
      <dc:creator>Manuk</dc:creator>
      <pubDate>Sat, 21 Feb 2026 03:53:35 +0000</pubDate>
      <link>https://dev.to/manukminasyan/how-i-rebuilt-csv-imports-to-handle-10000-messy-rows-without-breaking-26ng</link>
      <guid>https://dev.to/manukminasyan/how-i-rebuilt-csv-imports-to-handle-10000-messy-rows-without-breaking-26ng</guid>
      <description>&lt;p&gt;If you've ever built a CSV importer, you know it looks simple — until real users show up with messy data. Ambiguous dates, duplicate rows, partial updates, "Acme Corp" spelled three different ways. The basic parse-validate-insert pipeline crumbles fast.&lt;/p&gt;

&lt;p&gt;I'm building &lt;a href="https://relaticle.com" rel="noopener noreferrer"&gt;Relaticle&lt;/a&gt;, an open-source CRM, and for V3 I completely rebuilt the import system as a dedicated module with a strict workflow, staged processing, and explicit failure handling. Here's the architecture and the tradeoffs behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Rebuilt Imports for V3
&lt;/h2&gt;

&lt;p&gt;The old pattern most teams start with is straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parse CSV&lt;/li&gt;
&lt;li&gt;Validate in memory&lt;/li&gt;
&lt;li&gt;Insert/update directly&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That works for small clean files. It falls apart the moment someone uploads a CSV where "Acme Corp" appears three different ways, dates mix &lt;code&gt;MM/DD&lt;/code&gt; and &lt;code&gt;DD/MM&lt;/code&gt;, and half the rows should update existing records instead of creating duplicates.&lt;/p&gt;

&lt;p&gt;What you actually need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Matching against existing records without false positives&lt;/li&gt;
&lt;li&gt;Safe handling of relationships (company, contact, assignee links)&lt;/li&gt;
&lt;li&gt;Value-level corrections before anything hits the database&lt;/li&gt;
&lt;li&gt;Resumable state and reliable progress tracking&lt;/li&gt;
&lt;li&gt;Clear failure reporting users can act on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For V3, I wanted imports to behave like a proper workflow, not a one-shot script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Product Flow: 4 Steps, One State Machine
&lt;/h2&gt;

&lt;p&gt;The new Import Wizard is built around four explicit steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Upload CSV&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Map Columns&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review Values&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Preview and Import&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each step maps to an import status (&lt;code&gt;uploading&lt;/code&gt;, &lt;code&gt;mapping&lt;/code&gt;, &lt;code&gt;reviewing&lt;/code&gt;, &lt;code&gt;previewing&lt;/code&gt;, then &lt;code&gt;importing/completed/failed&lt;/code&gt;) so the UI and backend stay in sync.&lt;/p&gt;

&lt;p&gt;This looks like a UI detail, but it is a reliability decision. You can restore context, prevent invalid transitions, and reason about failures cleanly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Key Decision: Stage Data Outside Primary Tables
&lt;/h2&gt;

&lt;p&gt;The most important V3 decision was introducing a per-import staging store.&lt;/p&gt;

&lt;p&gt;Instead of writing directly to CRM tables during upload/review, each import gets its own SQLite-backed store (&lt;code&gt;storage/app/imports/&amp;lt;import-id&amp;gt;/data.sqlite&lt;/code&gt;). Rows are staged with metadata like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;raw_data&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;validation&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;corrections&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;skipped&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;match_action&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;matched_id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;relationships&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;processed&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This separation buys you three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Users review and correct data before anything touches production.&lt;/li&gt;
&lt;li&gt;Matching and validation run repeatedly without data drift.&lt;/li&gt;
&lt;li&gt;Cleanup is trivial: delete the import store directory.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What Happens When Someone Uploads 10,000 Rows?
&lt;/h2&gt;

&lt;p&gt;Upload enforces hard limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Max file size: 10MB&lt;/li&gt;
&lt;li&gt;Max rows: 10,000&lt;/li&gt;
&lt;li&gt;Chunk insert size: 500 rows&lt;/li&gt;
&lt;li&gt;Header sanitization and duplicate-header detection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rows are streamed from CSV and inserted into the staging store in chunks, not loaded into one huge in-memory structure.&lt;/p&gt;

&lt;p&gt;Practical effect: uploads stay stable and fast even with large files, and failure modes are explicit (empty file, duplicate headers, too many rows, bad format).&lt;/p&gt;

&lt;h2&gt;
  
  
  Smart Mapping: Automation With an Escape Hatch
&lt;/h2&gt;

&lt;p&gt;Mapping combines three layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Header-based guesses&lt;/strong&gt; (aliases like &lt;code&gt;company_name&lt;/code&gt;, &lt;code&gt;contact_email&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entity-link mapping&lt;/strong&gt; for relationships (company, contact, assignee, polymorphic links)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data-type inference&lt;/strong&gt; for unmapped columns&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The type inference is driven by the custom-field system, not a static hardcoded map. That keeps behavior aligned with actual field configuration per team/entity.&lt;/p&gt;

&lt;p&gt;If users skip mapping any matchable field (like ID, email, or domain), the wizard warns them they may create duplicates. It does not silently continue as if everything is fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review: Where Most Importers Stop, V3 Keeps Going
&lt;/h2&gt;

&lt;p&gt;On entering the Review step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A validation job is dispatched per mapped column&lt;/li&gt;
&lt;li&gt;A separate match-resolution job is dispatched&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means users can start interacting with results while backend jobs complete, instead of waiting on one synchronous validation wall.&lt;/p&gt;

&lt;p&gt;Users can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fix invalid values once and apply those corrections to all matching raw values&lt;/li&gt;
&lt;li&gt;Skip problematic values&lt;/li&gt;
&lt;li&gt;Adjust date/number formats when ambiguity exists&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything is persisted in staged JSON fields, so each correction is deterministic and replayable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Matching Model: Create, Update, or Skip
&lt;/h2&gt;

&lt;p&gt;The resolver marks each row with one of three actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;create&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;update&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;skip&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Behavior depends on mapped match fields and their strategy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Match-only fields can skip unmatched rows&lt;/li&gt;
&lt;li&gt;Match-or-create fields can create unmatched rows&lt;/li&gt;
&lt;li&gt;Name-based matching can intentionally be "create only" to avoid unsafe assumptions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes matching policy explicit instead of buried in ad hoc conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Execution: What Happens When Rows Fail?
&lt;/h2&gt;

&lt;p&gt;The import runs as a queued job with retries and backoff, processing rows in chunks.&lt;/p&gt;

&lt;p&gt;Key behaviors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only unprocessed rows are handled&lt;/li&gt;
&lt;li&gt;Row-level processing marks success/failure without stopping the whole import&lt;/li&gt;
&lt;li&gt;Existing records are preloaded for update chunks&lt;/li&gt;
&lt;li&gt;Multi-choice field values merge on update&lt;/li&gt;
&lt;li&gt;Failed rows are captured with error messages and can be downloaded as CSV&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One detail I like in this design: &lt;strong&gt;intra-import deduplication&lt;/strong&gt;. If a row is initially marked &lt;code&gt;create&lt;/code&gt; but a previous row in the same file already created that logical record, it can be promoted to &lt;code&gt;update&lt;/code&gt;. That avoids duplicate records inside a single import run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Operational Hardening
&lt;/h2&gt;

&lt;p&gt;Beyond the happy path, I added practical operations support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transition lock to prevent double-starting the same import&lt;/li&gt;
&lt;li&gt;Import history view with created/updated/skipped/failed counts&lt;/li&gt;
&lt;li&gt;Signed failed-rows download&lt;/li&gt;
&lt;li&gt;Cleanup command for abandoned and terminal imports&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The cleanup strategy is especially useful in production: completed/failed stores are removed after a short retention window, and stale abandoned imports are purged.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Says About Relaticle V3
&lt;/h2&gt;

&lt;p&gt;The Import Wizard reflects broader V3 architecture principles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Workflow over one-shot scripts&lt;/li&gt;
&lt;li&gt;Staged processing over direct mutation&lt;/li&gt;
&lt;li&gt;Async jobs for expensive work&lt;/li&gt;
&lt;li&gt;Team-scoped safety as a default&lt;/li&gt;
&lt;li&gt;Extensibility via importer contracts and entity-link abstractions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Still a modular monolith, but with clearer boundaries and better operational behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  If You're Building an Importer: My Practical Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ Separate staging from final writes&lt;/li&gt;
&lt;li&gt;✅ Make matching policy explicit (and user-visible)&lt;/li&gt;
&lt;li&gt;✅ Support value-level corrections before commit&lt;/li&gt;
&lt;li&gt;✅ Model row action as &lt;code&gt;create/update/skip&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;✅ Keep a downloadable failed-row report&lt;/li&gt;
&lt;li&gt;✅ Add cleanup from day one&lt;/li&gt;
&lt;li&gt;✅ Test every stage (UI + jobs + validators + matchers)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Imports are one of those product surfaces where reliability compounds trust. If users get burned once by "mystery imports," they stop trusting the system.&lt;/p&gt;

&lt;p&gt;For Relaticle V3, the goal was simple: &lt;strong&gt;make imports boring in production, even when the data isn't.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Building imports for your own product? I've made most of the mistakes already — happy to save you some. Find me on &lt;a href="https://x.com/MinasyanManuk" rel="noopener noreferrer"&gt;X&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/manukminasyan/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>architecture</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Real-time Search with Laravel &amp; Alpine.js: The Simple Approach</title>
      <dc:creator>Manuk</dc:creator>
      <pubDate>Fri, 19 Sep 2025 20:03:53 +0000</pubDate>
      <link>https://dev.to/manukminasyan/real-time-search-with-laravel-alpinejs-the-simple-approach-42e2</link>
      <guid>https://dev.to/manukminasyan/real-time-search-with-laravel-alpinejs-the-simple-approach-42e2</guid>
      <description>&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.amazonaws.com%2Fuploads%2Farticles%2F4eka5zi79pmkjofvchhw.png" 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.amazonaws.com%2Fuploads%2Farticles%2F4eka5zi79pmkjofvchhw.png" alt="Filaforms demo templates" width="800" height="607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Learn how to build a fast, searchable selection modal using Laravel and Alpine.js. This tutorial shows the simple approach that performs well for small to medium datasets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Laravel&lt;/strong&gt; - Backend framework&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alpine.js&lt;/strong&gt; - Lightweight JavaScript reactivity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS&lt;/strong&gt; - Utility-first styling&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Approach
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Pre-compute Search Data
&lt;/h3&gt;

&lt;p&gt;Do the heavy work once during render:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Pre-compute search text for each item&lt;/span&gt;
&lt;span class="nv"&gt;$searchText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;strtolower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'description'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Alpine.js for Search and Selection
&lt;/h3&gt;

&lt;p&gt;Simple Alpine.js component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;search&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;hasResults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;selectedValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filterItems&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="nf"&gt;filterItems&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchLower&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.item-card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;visibleCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchText&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isVisible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;searchLower&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchLower&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isVisible&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isVisible&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;visibleCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;visibleCount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Basic HTML Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Search input --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;x-model=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Search..."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Items grid --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"grid gap-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Each item has data-search-text attribute --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"item-card"&lt;/span&gt; &lt;span class="na"&gt;data-search-text=&lt;/span&gt;&lt;span class="s"&gt;"contact form simple"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Contact Form&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Simple contact form&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Empty state --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;x-show=&lt;/span&gt;&lt;span class="s"&gt;"search !== '' &amp;amp;&amp;amp; !hasResults"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;No items found&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;x-on:click=&lt;/span&gt;&lt;span class="s"&gt;"search = ''"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Clear search&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Benefits
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Instant Search Response
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;No server requests during search&lt;/li&gt;
&lt;li&gt;Direct DOM manipulation for speed&lt;/li&gt;
&lt;li&gt;Works well for up to 50 items&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Progressive Enhancement
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Works without JavaScript (graceful degradation)&lt;/li&gt;
&lt;li&gt;Accessible by default&lt;/li&gt;
&lt;li&gt;Mobile-friendly&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Simple Maintenance
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;No complex state management&lt;/li&gt;
&lt;li&gt;Easy to debug and extend&lt;/li&gt;
&lt;li&gt;Standard Laravel patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance Tips
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pre-compute when possible:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Do this once during render, not during search&lt;/span&gt;
&lt;span class="nv"&gt;$searchText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;strtolower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$title&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$description&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use direct DOM manipulation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Faster than virtual DOM for small datasets&lt;/span&gt;
&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isVisible&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Auto-focus for better UX:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$nextTick&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$refs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchInput&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When to Use This Approach
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Perfect for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Small to medium datasets (&amp;lt; 50 items)&lt;/li&gt;
&lt;li&gt;Real-time search requirements&lt;/li&gt;
&lt;li&gt;Simple filtering logic&lt;/li&gt;
&lt;li&gt;Laravel applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Consider alternatives for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large datasets (&amp;gt; 100 items)&lt;/li&gt;
&lt;li&gt;Complex search algorithms&lt;/li&gt;
&lt;li&gt;Heavy data processing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Lessons
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start Simple&lt;/strong&gt; - Basic DOM manipulation often outperforms complex solutions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pre-compute When Possible&lt;/strong&gt; - Do heavy work once, not repeatedly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progressive Enhancement&lt;/strong&gt; - Build a working baseline first&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alpine.js Shines&lt;/strong&gt; - Perfect for form interactions and simple reactivity&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Complete Working Example
&lt;/h2&gt;

&lt;p&gt;Here's a full implementation you can copy and adapt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{{-- Quick test component --}}
@php
    $items = [
        'contact' =&amp;gt; ['name' =&amp;gt; 'Contact Form', 'description' =&amp;gt; 'Simple contact form', 'category' =&amp;gt; 'Business'],
        'survey' =&amp;gt; ['name' =&amp;gt; 'Survey Form', 'description' =&amp;gt; 'Multi-question survey', 'category' =&amp;gt; 'Research'],
        'registration' =&amp;gt; ['name' =&amp;gt; 'Event Registration', 'description' =&amp;gt; 'Event signup form', 'category' =&amp;gt; 'Events'],
        'newsletter' =&amp;gt; ['name' =&amp;gt; 'Newsletter Signup', 'description' =&amp;gt; 'Email subscription form', 'category' =&amp;gt; 'Marketing'],
        'feedback' =&amp;gt; ['name' =&amp;gt; 'Feedback Form', 'description' =&amp;gt; 'Customer feedback collection', 'category' =&amp;gt; 'Support'],
    ];
@endphp

&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Test Searchable Component&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.tailwindcss.com"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;defer&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-gray-50 min-h-screen"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;
    &lt;span class="na"&gt;x-data=&lt;/span&gt;&lt;span class="s"&gt;"{
        search: '',
        hasResults: true,
        selectedValue: '',

        init() {
            this.$watch('search', () =&amp;gt; this.filterItems());
            this.$nextTick(() =&amp;gt; this.$refs.searchInput?.focus());
        },

        filterItems() {
            const searchLower = this.search.toLowerCase().trim();
            const cards = this.$el.querySelectorAll('.item-card');
            let visibleCount = 0;

            cards.forEach(card =&amp;gt; {
                const text = card.dataset.searchText || '';
                const isVisible = searchLower === '' || text.includes(searchLower);
                card.style.display = isVisible ? '' : 'none';
                if (isVisible) visibleCount++;
            });

            this.hasResults = visibleCount &amp;gt; 0;
        }
    }"&lt;/span&gt;
    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-6 max-w-4xl mx-auto"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-3xl font-bold mb-8 text-gray-800"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Test: Real-time Search Component&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

    {{-- Search Input --}}
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt;
        &lt;span class="na"&gt;x-model=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt;
        &lt;span class="na"&gt;x-ref=&lt;/span&gt;&lt;span class="s"&gt;"searchInput"&lt;/span&gt;
        &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Search items..."&lt;/span&gt;
        &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none text-lg"&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    {{-- Items Grid --}}
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 mt-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        @foreach ($items as $value =&amp;gt; $item)
            @php
                $searchText = strtolower($item['name'] . ' ' . $item['description'] . ' ' . $item['category']);
            @endphp

            &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt;
                &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"item-card cursor-pointer block"&lt;/span&gt;
                &lt;span class="na"&gt;data-search-text=&lt;/span&gt;&lt;span class="s"&gt;"{{ $searchText }}"&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
                    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt;
                    &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"selected_item"&lt;/span&gt;
                    &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"{{ $value }}"&lt;/span&gt;
                    &lt;span class="na"&gt;x-model=&lt;/span&gt;&lt;span class="s"&gt;"selectedValue"&lt;/span&gt;
                    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sr-only"&lt;/span&gt;
                &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;
                    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"border rounded-xl p-6 transition-all duration-200 hover:shadow-lg"&lt;/span&gt;
                    &lt;span class="na"&gt;:class=&lt;/span&gt;&lt;span class="s"&gt;"selectedValue === '{{ $value }}' ? 'border-blue-600 bg-blue-50 shadow-lg ring-2 ring-blue-100' : 'border-gray-200 bg-white hover:border-gray-300'"&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;h3&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"font-bold text-xl mb-3"&lt;/span&gt; &lt;span class="na"&gt;:class=&lt;/span&gt;&lt;span class="s"&gt;"selectedValue === '{{ $value }}' ? 'text-blue-900' : 'text-gray-900'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ $item['name'] }}&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-600 mb-3 leading-relaxed"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ $item['description'] }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt;
                        &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"inline-block px-3 py-1 text-sm rounded-full font-medium"&lt;/span&gt;
                        &lt;span class="na"&gt;:class=&lt;/span&gt;&lt;span class="s"&gt;"selectedValue === '{{ $value }}' ? 'bg-blue-100 text-blue-800' : 'bg-gray-100 text-gray-700'"&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ $item['category'] }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        @endforeach
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    {{-- Empty State --}}
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;x-show=&lt;/span&gt;&lt;span class="s"&gt;"search !== '' &amp;amp;&amp;amp; !hasResults"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-center py-16"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-400 mb-6"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-16 h-16 mx-auto mb-4"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt; &lt;span class="na"&gt;stroke=&lt;/span&gt;&lt;span class="s"&gt;"currentColor"&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 24 24"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;stroke-linecap=&lt;/span&gt;&lt;span class="s"&gt;"round"&lt;/span&gt; &lt;span class="na"&gt;stroke-linejoin=&lt;/span&gt;&lt;span class="s"&gt;"round"&lt;/span&gt; &lt;span class="na"&gt;stroke-width=&lt;/span&gt;&lt;span class="s"&gt;"1.5"&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/path&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-xl font-semibold text-gray-600 mb-2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;No items found&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-500"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Try adjusting your search terms&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt;
            &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
            &lt;span class="na"&gt;x-on:click=&lt;/span&gt;&lt;span class="s"&gt;"search = ''"&lt;/span&gt;
            &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium"&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            Clear search
        &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    {{-- Results Info --}}
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mt-8 p-4 bg-white border border-gray-200 rounded-lg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"grid grid-cols-1 md:grid-cols-3 gap-4 text-sm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;strong&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-700"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Current search:&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-blue-600 font-mono"&lt;/span&gt; &lt;span class="na"&gt;x-text=&lt;/span&gt;&lt;span class="s"&gt;"search || '(none)'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;strong&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-700"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Has results:&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;:class=&lt;/span&gt;&lt;span class="s"&gt;"hasResults ? 'text-green-600' : 'text-red-600'"&lt;/span&gt; &lt;span class="na"&gt;x-text=&lt;/span&gt;&lt;span class="s"&gt;"hasResults ? 'Yes' : 'No'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;strong&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-700"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Selected:&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-blue-600 font-mono"&lt;/span&gt; &lt;span class="na"&gt;x-text=&lt;/span&gt;&lt;span class="s"&gt;"selectedValue || '(none)'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to Use
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create the component&lt;/strong&gt; - Save the above code as a Blade component&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Include it&lt;/strong&gt; - Use &lt;code&gt;&amp;lt;x-searchable-selector /&amp;gt;&lt;/code&gt; in your views&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customize data&lt;/strong&gt; - Replace the &lt;code&gt;$items&lt;/code&gt; array with your data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Style it&lt;/strong&gt; - Adjust Tailwind classes to match your design&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Key Implementation Details
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pre-computed search text:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$searchText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;strtolower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'description'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Alpine.js filtering:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchText&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isVisible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;searchLower&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchLower&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isVisible&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isVisible&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;visibleCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Visual selection feedback:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;:class="selectedValue === '{{ $value }}' ? 'border-blue-600 bg-blue-50' : 'border-gray-300'"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach scales well for typical use cases and can be enhanced later if requirements grow.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This tutorial shows the approach used in &lt;a href="https://filaforms.app/" rel="noopener noreferrer"&gt;FilaForms&lt;/a&gt; - Laravel form infrastructure for rapid development.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>laravel</category>
      <category>alpine</category>
      <category>livewire</category>
    </item>
    <item>
      <title>Building Relaticle: A Free &amp; Open Source CRM with Laravel 12 &amp; Filament 3</title>
      <dc:creator>Manuk</dc:creator>
      <pubDate>Sat, 26 Apr 2025 08:47:04 +0000</pubDate>
      <link>https://dev.to/manukminasyan/building-relaticle-a-free-open-source-crm-with-laravel-12-filament-3-h3g</link>
      <guid>https://dev.to/manukminasyan/building-relaticle-a-free-open-source-crm-with-laravel-12-filament-3-h3g</guid>
      <description>&lt;p&gt;After months of coding late into the night, I'm excited to share &lt;strong&gt;&lt;a href="https://relaticle.com/" rel="noopener noreferrer"&gt;Relaticle&lt;/a&gt;&lt;/strong&gt; - a modern, completely free and open source CRM built with Laravel 12 and Filament 3.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Built This
&lt;/h2&gt;

&lt;p&gt;Most CRMs are either too expensive, too bloated, or too restrictive. I wanted something that was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Powerful enough&lt;/strong&gt; for real businesses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible enough&lt;/strong&gt; to customize without a CS degree&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open enough&lt;/strong&gt; that you own your data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple enough&lt;/strong&gt; that you don't need a consultant to use it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I built Relaticle as the CRM I wish existed when I started my first business.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tech Stack
&lt;/h2&gt;

&lt;p&gt;Relaticle is built on modern technologies that prioritize developer experience and performance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Laravel 12&lt;/strong&gt; - The latest version with all its goodies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filament 3&lt;/strong&gt; - For beautiful admin panels with minimal effort&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Livewire 3&lt;/strong&gt; - For dynamic components without writing JS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alpine.js&lt;/strong&gt; - For lightweight interactivity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS&lt;/strong&gt; - For responsive, utility-first styling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL&lt;/strong&gt; - For robust data storage (though SQLite works too)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;p&gt;Here's what makes Relaticle special from a technical perspective:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Multi-tenancy with Team Workspaces
&lt;/h3&gt;

&lt;p&gt;Using Laravel Jetstream's team features, combined with Filament's tenant system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/Providers/Filament/AppPanelProvider.php&lt;/span&gt;

&lt;span class="nv"&gt;$panel&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;tenant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Team&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;tenantRegistration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CreateTeam&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;tenantProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;EditTeam&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Custom Fields System
&lt;/h3&gt;

&lt;p&gt;A flexible custom fields architecture that allows for schema-less data modeling without sacrificing query performance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Defining a custom field for tasks&lt;/span&gt;
&lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;CustomFieldTrait&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;STATUS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'status'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;PRIORITY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'priority'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getFieldType&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;CustomFieldType&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;STATUS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;PRIORITY&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;CustomFieldType&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SELECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="c1"&gt;// other cases...&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Kanban Boards for Visual Management
&lt;/h3&gt;

&lt;p&gt;Built a drag-and-drop Kanban system for both tasks and opportunities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TasksBoard&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;KanbanBoardPage&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;titleField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;columnField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'status'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;descriptionField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'description'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;orderField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'order_column'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;statuses&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;pluck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;columnColors&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;cardLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Task'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Other methods...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Smart Avatars and UI Components
&lt;/h3&gt;

&lt;p&gt;Created a service that dynamically generates avatars with appropriate contrast:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// A simple system that generates personalized SVG avatars&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;generateAuto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Analyze name characteristics to choose colors&lt;/span&gt;
    &lt;span class="nv"&gt;$nameAnalysis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;analyzeNameCharacteristics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Generate a deterministic hue based on the name&lt;/span&gt;
    &lt;span class="nv"&gt;$hue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getHueFromName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Adjust saturation and lightness based on name&lt;/span&gt;
    &lt;span class="nv"&gt;$saturation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;65&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$nameAnalysis&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'adjustment'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nv"&gt;$lightness&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;85&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$nameAnalysis&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'adjustment'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Create the SVG with the person's initials&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Architecture Decisions
&lt;/h2&gt;

&lt;p&gt;When building Relaticle, I made a few important architecture decisions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Heavy use of PHP 8.3 features&lt;/strong&gt; like readonly properties, enums, and the &lt;code&gt;#[\Override]&lt;/code&gt; attribute&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Strict architecture enforcement&lt;/strong&gt; using Pest's architecture tests to enforce coding standards:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;arch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'strict types'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'App'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toUseStrictTypes&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nf"&gt;arch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'avoid open for extension'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'App'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toBeFinal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nf"&gt;arch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'avoid mutation'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'App'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toBeReadonly&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Application panels segregation&lt;/strong&gt; - Admin vs App panels to clearly separate concerns&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Observer pattern&lt;/strong&gt; for model events to keep controllers lean:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="na"&gt;#[ObservedBy(CompanyObserver::class)]&lt;/span&gt;
&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Company&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;HasCustomFields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HasMedia&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Development Journey
&lt;/h2&gt;

&lt;p&gt;Building Relaticle wasn't a straight path. Some lessons learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Laravel 12's new features&lt;/strong&gt; made testing much easier with the improved Pest integration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filament 3 is amazing&lt;/strong&gt; but requires some learning, especially when extending core components&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database performance&lt;/strong&gt; needed optimization for the custom fields system&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Balancing flexibility vs simplicity&lt;/strong&gt; is an ongoing challenge&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Want to try it out? Here's how to get started:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone the repository&lt;/span&gt;
git clone https://github.com/Relaticle/relaticle.git

&lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;relaticle
composer &lt;span class="nb"&gt;install
&lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Set up your environment&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
php artisan key:generate

&lt;span class="c"&gt;# Run migrations&lt;/span&gt;
php artisan migrate

&lt;span class="c"&gt;# Compile assets&lt;/span&gt;
npm run dev

&lt;span class="c"&gt;# Start the server&lt;/span&gt;
php artisan serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Future Plans
&lt;/h2&gt;

&lt;p&gt;This is just the beginning. Here's what's coming:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Email integration for tracking correspondence&lt;/li&gt;
&lt;li&gt;API for custom integrations&lt;/li&gt;
&lt;li&gt;More visualization reports&lt;/li&gt;
&lt;li&gt;Mobile app (eventually)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Join Me!
&lt;/h2&gt;

&lt;p&gt;I'd love to have more developers join this project. It's completely free and open source - no premium tiers, no locked features.&lt;/p&gt;

&lt;p&gt;If you're interested in contributing, check out the repository on GitHub: &lt;a href="https://github.com/Relaticle/relaticle" rel="noopener noreferrer"&gt;Relaticle/relaticle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or, if you just want to try it out, star the repo and follow along as we build something awesome together.&lt;/p&gt;

&lt;p&gt;Let me know what you think in the comments!&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>opensource</category>
      <category>crm</category>
    </item>
    <item>
      <title>Making Writing Easy with GetCopy: A Sneak Peek into the Tech Behind the Magic</title>
      <dc:creator>Manuk</dc:creator>
      <pubDate>Fri, 28 Jun 2024 20:29:47 +0000</pubDate>
      <link>https://dev.to/manukminasyan/making-writing-easy-with-getcopy-a-sneak-peek-into-the-tech-behind-the-magic-3pj9</link>
      <guid>https://dev.to/manukminasyan/making-writing-easy-with-getcopy-a-sneak-peek-into-the-tech-behind-the-magic-3pj9</guid>
      <description>&lt;p&gt;Ever wondered how it's possible for a platform to help you write documents as if it's reading your mind? Meet GetCopy.ai. It's been causing quite a stir in the world of document creation with its innovative approach and smart tech. This post will take you behind the scenes, exploring the tech that makes GetCopy.ai tick.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Nuts and Bolts of GetCopy.ai
&lt;/h2&gt;

&lt;p&gt;GetCopy.ai is powered by a blend of technologies that work together to make document creation smooth and efficient. Let’s dive into the key elements and why they were picked.&lt;/p&gt;

&lt;h3&gt;
  
  
  Behind the Scenes Tech
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;PHP&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Why PHP?:&lt;/strong&gt; It's flexible, widely-used, and perfect for web development. Plus, it comes with a ton of useful libraries and frameworks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it Does:&lt;/strong&gt; PHP is the engine under GetCopy.ai's hood, handling everything from user sign-ins to data processing.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Laravel&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Why Laravel?:&lt;/strong&gt; Laravel is a popular PHP framework that makes common tasks like authentication and caching a breeze. It's well-organized and quick to set up, which makes developing complex features faster and easier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it Does:&lt;/strong&gt; Laravel sets up a strong, scalable foundation for the platform, allowing for rapid feature implementation.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Laravel Echo&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Why Laravel Echo?:&lt;/strong&gt; Real-time updates are key for features like live document editing. Laravel Echo, which works seamlessly with Laravel, provides just that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it Does:&lt;/strong&gt; Laravel Echo keeps everything in real-time on the platform, ensuring instant updates and smooth teamwork.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Laravel Socialite&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Why Laravel Socialite?:&lt;/strong&gt; Making user authentication easy is crucial to a frictionless user experience. Laravel Socialite helps users log in using their social media accounts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it Does:&lt;/strong&gt; This package makes signing up and logging in a breeze by reducing the usual fuss associated with account creation.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Pest PHP&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Why Pest PHP?:&lt;/strong&gt; Keeping the backend code reliable and stable is critical. Pest PHP is a testing framework that makes it easier to write and maintain tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it Does:&lt;/strong&gt; Pest PHP helps the development team to make sure the backend code works as it should, reducing the risk of bugs and errors.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Filament&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Why Filament?:&lt;/strong&gt; Managing backend operations calls for a user-friendly admin panel. Filament is an admin panel builder for Laravel that provides a powerful and intuitive interface for admins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it Does:&lt;/strong&gt; Filament makes life easier for admins, letting them handle tasks like user management and system monitoring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Front of House Tech
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Vue.js&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Why Vue.js?:&lt;/strong&gt; It's a flexible JavaScript framework that's great for building dynamic and interactive user interfaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it Does:&lt;/strong&gt; Vue.js helps create engaging frontend components, ensuring a smooth and interactive user experience.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Inertia.js&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Why Inertia.js?:&lt;/strong&gt; Building single-page applications (SPAs) without a separate API simplifies development. Inertia.js makes this possible, providing a more fluid user experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it Does:&lt;/strong&gt; Inertia.js ensures real-time updates and a seamless connection between the front and back ends.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Brains of the Operation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;MySQL&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Why MySQL?:&lt;/strong&gt; MySQL is a robust relational database management system known for its performance and scalability. It's great at handling structured data and complex queries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it Does:&lt;/strong&gt; MySQL looks after the storage and retrieval of user info, documents, and references, ensuring data is safely stored and easily accessible.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Redis&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Why Redis?:&lt;/strong&gt; Redis is an in-memory data structure store known for its speed. It's excellent for real-time data processing and caching frequently accessed information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it Does:&lt;/strong&gt; Redis helps make the platform more responsive by dealing with real-time data and caching, ensuring a fast and smooth user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  The AI Secret Sauce
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;OpenAI GPT-4&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Why OpenAI GPT-4?:&lt;/strong&gt; OpenAI GPT-4 is a top-notch language model that's a whizz at understanding and producing human-like text.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it Does:&lt;/strong&gt; GPT-4 powers GetCopy.ai's AI capabilities, assisting users in drafting, editing, and enhancing their documents.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Anthropic Claude 3.5&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Why Anthropic Claude 3.5?:&lt;/strong&gt; Adding another advanced AI model helps the platform understand context and generate accurate text better. Claude 3.5 is known for its relevance and precision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it Does:&lt;/strong&gt; Together with GPT-4, Claude 3.5 forms the backbone of GetCopy.ai's intelligent writing assistance, ensuring high-quality and contextually relevant output.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Search Engine
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Typesense&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Why Typesense?:&lt;/strong&gt; Typesense is a fast, typo-tolerant search engine perfect for creating delightful search experiences. It's great for handling search queries efficiently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it Does:&lt;/strong&gt; Typesense ensures users can quickly and accurately find the info they need, even if their search queries are a little off.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Money Handler
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Lemon Squeezy&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Why Lemon Squeezy?:&lt;/strong&gt; Managing subscriptions and payments securely is crucial. Lemon Squeezy provides an easy-to-use interface and solid security features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it Does:&lt;/strong&gt; Lemon Squeezy makes managing subscriptions and payments simple, ensuring a smooth experience for users.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tech Orchestra in Action
&lt;/h2&gt;

&lt;p&gt;Here's how these technologies play together in GetCopy.ai:&lt;/p&gt;

&lt;h3&gt;
  
  
  User Interaction
&lt;/h3&gt;

&lt;p&gt;Users interact with the platform through a responsive front end built with Vue.js and Inertia.js, ensuring a smooth user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Behind-the-Scenes Stuff
&lt;/h3&gt;

&lt;p&gt;The back end, powered by PHP and Laravel, handles user sign-in, data processing, and all the important behind-the-scenes stuff. Laravel Echo adds real-time capabilities for instant updates and collaboration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Management
&lt;/h3&gt;

&lt;p&gt;MySQL safely stores user data, documents, and references, while Redis handles real-time data and caching to keep things zippy.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Assistance
&lt;/h3&gt;

&lt;p&gt;Advanced AI models like OpenAI GPT-4 and Anthropic Claude 3.5 provide intelligent writing assistance, helping users draft, edit, and polish their documents.&lt;/p&gt;

&lt;h3&gt;
  
  
  Search Functionality
&lt;/h3&gt;

&lt;p&gt;Typesense helps users quickly find the information they need, even if their search queries are a little off.&lt;/p&gt;

&lt;h3&gt;
  
  
  Payments and Subscriptions
&lt;/h3&gt;

&lt;p&gt;Lemon Squeezy handles all things money, providing a secure and easy-to-use interface for managing payments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;GetCopy.ai is shaking up the document creation game by leveraging a unique blend of technologies. From advanced AI models to a slick front end and a robust back end, every part of GetCopy.ai is designed to provide a seamless and efficient user experience. Whether you're a developer, researcher, or content creator, GetCopy.ai's tech stack guarantees top-notch performance, scalability, and reliability.&lt;/p&gt;

&lt;p&gt;Give GetCopy.ai a try and see how these technologies come together to create a powerful document creation platform.&lt;/p&gt;




&lt;p&gt;Got some thoughts or experiences with GetCopy.ai? Share them in the comments below. We're all ears!&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. How is GetCopy.ai different from other document creation platforms?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;GetCopy.ai stands out with its advanced AI capabilities, real-time collaboration features, and a highly responsive user interface. The integration of tech like GPT-4 and Vue.js makes document creation intuitive and seamless.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. How does GetCopy.ai keep user data safe?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;GetCopy.ai takes data security seriously. It uses data encryption, secure user authentication via Laravel Socialite, and reliable data management systems like MySQL and Redis to make sure user data is always protected.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Can I hook up GetCopy.ai with other tools and platforms?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Absolutely! GetCopy.ai is designed to be flexible and can be integrated with a variety of other tools and platforms. Its modular design makes customization and expansion easy.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. How do the AI models in GetCopy.ai make document creation better?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The AI models, including GPT-4 and Claude 3.5, offer intelligent writing assistance by understanding context, suggesting edits, and generating human-like text. This significantly improves the quality and speed of document creation.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;5. Is there a free trial for GetCopy.ai?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Yes, GetCopy.ai offers a free trial for newbies. This lets you test out the platform’s features before committing to a subscription.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
