<?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: Bibek</title>
    <description>The latest articles on DEV Community by Bibek (@bibekkakati).</description>
    <link>https://dev.to/bibekkakati</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%2F618021%2F8c0beed8-7df1-4b13-b4c8-6e947057107e.jpeg</url>
      <title>DEV Community: Bibek</title>
      <link>https://dev.to/bibekkakati</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bibekkakati"/>
    <language>en</language>
    <item>
      <title>CQRS: Read-Write Separation Design Pattern</title>
      <dc:creator>Bibek</dc:creator>
      <pubDate>Wed, 02 Sep 2026 15:29:30 +0000</pubDate>
      <link>https://dev.to/bibekkakati/cqrs-read-write-separation-design-pattern-49fe</link>
      <guid>https://dev.to/bibekkakati/cqrs-read-write-separation-design-pattern-49fe</guid>
      <description>&lt;p&gt;In traditional software architectures, we almost instinctively reach for the CRUD (Create, Read, Update, Delete) paradigm. We design an entity model, map it to a relational schema using an ORM, and use that identical abstraction to both alter state and display data on user dashboards.&lt;/p&gt;

&lt;p&gt;For simple applications, this works flawlessly. But as systems scale—both in business complexity and throughput, this dual-purpose model starts showing fractures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Write logic&lt;/strong&gt; demands tight validation, transactional boundaries, normalization, and domain invariants.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read logic&lt;/strong&gt; demands flat, pre-aggregated, denormalized representations across dozens of tables to serve responsive UIs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Trying to satisfy both masters with a single schema leads to unwieldy SQL joins, lock contention, compromised domain boundaries, and performance gridlock.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;Command Query Responsibility Segregation (CQRS)&lt;/strong&gt; enters the picture.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. What is CQRS?
&lt;/h2&gt;

&lt;p&gt;Coined by Greg Young and based on Bertrand Meyer’s &lt;strong&gt;Command-Query Separation (CQS)&lt;/strong&gt; principle, CQRS states that an application should use &lt;strong&gt;separate models to update and read data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At its philosophical core:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Command (Write):&lt;/strong&gt; Represents an intent to alter domain state (e.g., &lt;code&gt;SubmitOrder&lt;/code&gt;, &lt;code&gt;DeactivateUser&lt;/code&gt;, &lt;code&gt;ChangeBillingAddress&lt;/code&gt;). A command should focus entirely on domain logic, data integrity, and business rules. In strict CQRS, commands do not return domain data — only an acknowledgment, validation failure, or generated entity ID.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query (Read):&lt;/strong&gt; Retrieves data without mutating application state (e.g., &lt;code&gt;GetOrderSummaryById&lt;/code&gt;, &lt;code&gt;ListCustomerInvoices&lt;/code&gt;). Queries should execute side-effect-free operations that return lightweight Data Transfer Objects (DTOs).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;         ┌────────────────────────────────────────────────────────┐
         │                       Client                           │
         └─────────────┬────────────────────────────▲─────────────┘
                       │                            │
             Execute Command                    Run Query
                       │                            │
                       ▼                            │
         ┌───────────────────────────┐  ┌───────────┴─────────────┐
         │       Command Model       │  │       Query Model       │
         │ (Validation &amp;amp; Invariants) │  │   (Optimized for DTOs)  │
         └─────────────┬─────────────┘  └───────────▲─────────────┘
                       │                            │
                 Mutates State                Direct Read
                       │                            │
                       ▼                            │
         ┌───────────────────────────┐  ┌───────────┴─────────────┐
         │       Write Storage       │──|    Synchronization      │
         └───────────────────────────┘  │   (Sync / Async CDC)    │
                                        └─────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. How CQRS Works in Practice
&lt;/h2&gt;

&lt;p&gt;Let’s trace an end-to-end user interaction in a CQRS system using an e-commerce order:&lt;/p&gt;

&lt;h3&gt;
  
  
  The Write Path (Command Flow)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Client Action:&lt;/strong&gt; The user clicks "Place Order", dispatching a &lt;code&gt;PlaceOrderCommand&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Command Handler:&lt;/strong&gt; The handler receives the command, loads the aggregate (e.g., &lt;code&gt;Order&lt;/code&gt;), validates business rules (inventory checks, credit limits), and produces state changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write Persistence:&lt;/strong&gt; The entity state (or an event stream) is committed to the Write Data Store within an atomic transaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notification / Projection:&lt;/strong&gt; An event (e.g., &lt;code&gt;OrderPlaced&lt;/code&gt;) or a database Change Data Capture (CDC) stream is emitted.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Read Path (Query Flow)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read Model Projection:&lt;/strong&gt; A background projector (or synchronous handler) catches the update and reshapes the data into a denormalized table or document store (&lt;code&gt;order_views&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client Action:&lt;/strong&gt; The user visits their dashboard, issuing &lt;code&gt;GetCustomerOrdersQuery&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Query Handler:&lt;/strong&gt; The query bypasses business validation engines, complex ORM logic, and multi-table SQL joins, executing a direct indexed lookup:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;order_views&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DTO Return:&lt;/strong&gt; The UI receives ready-to-render JSON data immediately.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  3. Types of CQRS Implementations
&lt;/h2&gt;

&lt;p&gt;CQRS is not a binary choice. It exists on an implementation spectrum, ranging from simple code separation to distributed event-driven systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Single-Database CQRS (Code-Level Separation)
&lt;/h3&gt;

&lt;p&gt;Both read and write models target the &lt;strong&gt;same relational database&lt;/strong&gt;, but your application code completely decouples the command handling logic from the query handling logic.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; The write path uses domain entities, while the read path uses raw SQL, lightweight micro-ORMs, or database views to fetch flat DTOs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency:&lt;/strong&gt; &lt;strong&gt;Strong / Immediate.&lt;/strong&gt; Everything happens within a single ACID transaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When to use:&lt;/strong&gt; When your codebase is becoming bloated with domain logic inside query paths, but you do not have massive scale or high read/write asymmetry.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Dual-Model, Single Database (Synchronous Projection)
&lt;/h3&gt;

&lt;p&gt;The write model updates normalized tables (e.g., &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;order_items&lt;/code&gt;, &lt;code&gt;customers&lt;/code&gt;). Inside the &lt;strong&gt;same database transaction&lt;/strong&gt;, the application updates a denormalized summary table (&lt;code&gt;order_view_flat&lt;/code&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; The read queries hit the denormalized table, eliminating runtime joins without introducing message queues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency:&lt;/strong&gt; &lt;strong&gt;Strong / Immediate.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When to use:&lt;/strong&gt; When you need sub-millisecond query lookups for complex pages, but cannot tolerate the eventual consistency or infrastructure overhead of separate databases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Split Databases with Asynchronous Sync
&lt;/h3&gt;

&lt;p&gt;The write model targets a dedicated Write DB (e.g., PostgreSQL primary), while the read model targets an independent Read DB (e.g., a denormalized PostgreSQL instance, Elasticsearch, or MongoDB).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; Commits on the write DB publish events or WAL updates. CDC pipelines (Debezium/Kafka) or event subscribers consume these updates, transform the data, and upsert them into the read database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency:&lt;/strong&gt; &lt;strong&gt;Eventual Consistency.&lt;/strong&gt; Read views lag slightly behind the write path (typically 25ms–300ms).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When to use:&lt;/strong&gt; High read-to-write ratios (100:1+), disparate indexing requirements, or where full-text search / flexible document storage is required for queries.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  CQRS with Event Sourcing (ES)
&lt;/h3&gt;

&lt;p&gt;Instead of storing the current state of an entity, you store an append-only log of immutable domain events (&lt;code&gt;OrderCreated&lt;/code&gt;, &lt;code&gt;ItemAdded&lt;/code&gt;, &lt;code&gt;ShippingAddressUpdated&lt;/code&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; The write store is an &lt;strong&gt;Event Store&lt;/strong&gt;. The query models (projections) are derived read representations built by replaying and subscribing to this event stream.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency:&lt;/strong&gt; &lt;strong&gt;Eventual Consistency.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When to use:&lt;/strong&gt; Systems requiring complete auditability, temporal querying ("what was the state at 2:00 PM yesterday?"), financial ledgers, or complex distributed domains.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Alternative Approaches (and Why They Might Fall Short)
&lt;/h2&gt;

&lt;p&gt;Before adopting full CQRS, engineers often evaluate simpler architectural alternatives. Each comes with clear trade-offs:&lt;/p&gt;

&lt;h3&gt;
  
  
  Traditional Read Replicas
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Concept:&lt;/strong&gt; Direct read traffic to replica instances using standard database replication (e.g., Postgres WAL streaming).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drawbacks:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Schema Coupling:&lt;/strong&gt; Read replicas contain the &lt;em&gt;exact same normalized schema&lt;/em&gt; as the primary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query Overhead:&lt;/strong&gt; Complex joins, subqueries, and aggregations still occur at query time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Index Contention:&lt;/strong&gt; Adding excessive indexes to optimize read queries on replicas creates overhead and replication lag.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Database Materialized Views
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Concept:&lt;/strong&gt; Define views that pre-compute joins and aggregations directly in the database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drawbacks:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Refresh Costs:&lt;/strong&gt; Standard materialized views require manual or periodic refreshes (&lt;code&gt;REFRESH MATERIALIZED VIEW&lt;/code&gt;), locking rows or draining database CPU.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incremental Refresh Complexity:&lt;/strong&gt; Incremental view maintenance (IVM) is either unsupported natively or strictly limited to simple single-table operations without subqueries.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Application-Layer Cache (Redis / Memcached)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Concept:&lt;/strong&gt; Wrap queries in a caching layer (&lt;code&gt;Cache-Aside&lt;/code&gt; pattern).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drawbacks:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache Invalidation Nightmares:&lt;/strong&gt; Knowing exactly which cached objects to invalidate when a nested entity updates is notoriously difficult.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cold Start Latency:&lt;/strong&gt; Cache misses force heavy fallbacks onto the relational database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limited Query Flexibility:&lt;/strong&gt; Key-value caches do not excel at multi-attribute filtering, sorting, or pagination across variable criteria.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Addressing the Obvious Doubts &amp;amp; FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  "Isn't a denormalized read DB in Postgres just a read replica?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;No.&lt;/strong&gt; A read replica is an identical physical clone of your write database schema.&lt;/p&gt;

&lt;p&gt;In a CQRS split-database setup, the read database contains an entirely different, query-tailored schema. It holds pre-joined JSON documents, flattened tabular projections, and specialized indexes (such as GIN or full-text) that would be too heavy to maintain on your transactional write primary.&lt;/p&gt;

&lt;h3&gt;
  
  
  "Can I write denormalized tables in the same DB and just replicate them?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Yes, but watch your write latency.&lt;/strong&gt; Writing to both normalized tables and denormalized summary tables inside the same transaction increases transaction duration, amplifies WAL generation, and can introduce severe row-lock contention on aggregate records (e.g., multiple orders updating the same merchant total row).&lt;/p&gt;

&lt;h3&gt;
  
  
  "Do I have to use Event Sourcing to use CQRS?"
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;No.&lt;/strong&gt; This is the single most common misconception in system design. CQRS can be implemented with standard state-based ORMs and relational databases. While Event Sourcing almost always requires CQRS (because event streams are difficult to query directly without projections), CQRS does not require Event Sourcing.&lt;/p&gt;

&lt;h3&gt;
  
  
  "How much latency does eventual consistency introduce?"
&lt;/h3&gt;

&lt;p&gt;In a well-architected CDC and message-broker pipeline, the typical end-to-end lag ranges between &lt;strong&gt;25 ms and 300 ms&lt;/strong&gt; under normal load.&lt;/p&gt;

&lt;p&gt;Spikes can occur during large batch updates, rebalances, or heavy read-side lock contention.&lt;/p&gt;

&lt;h3&gt;
  
  
  "How do I deal with users seeing stale data immediately after submitting a form?"
&lt;/h3&gt;

&lt;p&gt;When using asynchronous CQRS, navigating immediately to a list page might show outdated data if the projection is lagging by 100ms. Common mitigation patterns include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Optimistic UI:&lt;/strong&gt; The frontend client updates its local state immediately upon a successful command dispatch without refetching from the read model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Command Response Payloads:&lt;/strong&gt; Return the newly updated projection directly in the command response body for immediate display.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read-Your-Own-Writes Tokens:&lt;/strong&gt; The command returns a version identifier (e.g., &lt;code&gt;version=42&lt;/code&gt;). The subsequent read query passes this token; if the read store has only caught up to &lt;code&gt;version=41&lt;/code&gt;, the query either waits for catch-up or momentarily queries the write primary.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  6. Summary: When to Use (and When to Avoid) CQRS
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Indicator&lt;/th&gt;
&lt;th&gt;Avoid CQRS&lt;/th&gt;
&lt;th&gt;Consider CQRS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Domain Complexity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Simple CRUD, small team, standard forms&lt;/td&gt;
&lt;td&gt;Intricate domain logic, complex invariants, distinct team ownership&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Workload Profile&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Balanced read/write, low traffic&lt;/td&gt;
&lt;td&gt;Heavy read-to-write asymmetry (e.g., 50:1 to 1000:1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Relationships&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Single-table queries, basic joins&lt;/td&gt;
&lt;td&gt;High-dimensional views requiring expensive 10-table joins&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Consistency Needs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strict global ACID consistency mandatory&lt;/td&gt;
&lt;td&gt;Read views can tolerate 100ms–500ms eventual consistency&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;CQRS is an architectural investment. While it eliminates performance bottlenecks and disentangles write-side business rules from read-side presentations, it introduces operational overhead, deployment complexity, and eventual consistency challenges. Start with simple CQS at the code level, and introduce split databases only when access patterns and scale justify the trade-off.&lt;/p&gt;

</description>
      <category>distributedsystems</category>
      <category>cqrs</category>
      <category>systemdesign</category>
      <category>software</category>
    </item>
    <item>
      <title>Understanding Kubernetes: A Beginner's Guide to Container Orchestration</title>
      <dc:creator>Bibek</dc:creator>
      <pubDate>Fri, 28 Aug 2026 19:15:50 +0000</pubDate>
      <link>https://dev.to/bibekkakati/understanding-kubernetes-a-beginners-guide-to-container-orchestration-2dgo</link>
      <guid>https://dev.to/bibekkakati/understanding-kubernetes-a-beginners-guide-to-container-orchestration-2dgo</guid>
      <description>&lt;p&gt;If you have already explored &lt;a href="https://bibekkakati.com/blog/docker-explained-containers-and-architecture" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;, you know how convenient containers are. You package your application, dependencies, and environment into a neat image, run &lt;code&gt;docker run&lt;/code&gt;, and it just works.&lt;/p&gt;

&lt;p&gt;Running &lt;strong&gt;one container&lt;/strong&gt; on your local machine is simple. But what happens when your application grows into a real-world product with millions of users?&lt;/p&gt;

&lt;p&gt;Imagine you launch an online food delivery app. On a Friday night at 8:00 PM:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traffic spikes by &lt;strong&gt;10x&lt;/strong&gt;—you suddenly need 20 copies of your backend container to handle orders.&lt;/li&gt;
&lt;li&gt;One of your physical servers overheats and crashes at 2:00 AM, taking down 5 containers with it.&lt;/li&gt;
&lt;li&gt;You need to deploy a bug fix to the payment gateway without dropping ongoing user checkouts.&lt;/li&gt;
&lt;li&gt;You need a way to distribute incoming user requests evenly across all running containers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Doing this manually means waking up at 3:00 AM, SSH-ing into servers, running &lt;code&gt;docker run&lt;/code&gt; commands by hand, and manually updating Nginx reverse proxy configs.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;Kubernetes&lt;/strong&gt; comes in.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Kubernetes?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt; (often abbreviated as &lt;strong&gt;K8s&lt;/strong&gt;, because there are 8 letters between 'K' and 's') is an open-source &lt;strong&gt;container orchestration platform&lt;/strong&gt;. It automates the deployment, scaling, load balancing, and self-healing of containerized applications across a cluster of servers.&lt;/p&gt;

&lt;p&gt;Originally developed by Google (based on over a decade of running Borg internally) and now maintained by the Cloud Native Computing Foundation (CNCF), Kubernetes has become the standard operating system for cloud-native infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Symphony Orchestra Analogy
&lt;/h3&gt;

&lt;p&gt;Think of it this way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A Docker Container&lt;/strong&gt; is a single musician (like a violinist playing their sheet music perfectly).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes&lt;/strong&gt; is the &lt;strong&gt;orchestra conductor&lt;/strong&gt;. The conductor ensures every musician plays in sync, brings in extra violinists when the crescendo builds, seamlessly replaces someone if a string snaps, and makes sure the entire performance sounds harmonious to the audience.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                +------------------------------------+
                |        Kubernetes Conductor        |
                | (Monitors, Scales, Heals, Routes)  |
                +-----------------+------------------+
                                  |
    +----------------------------+----------------------------+
    |                            |                            |
    v                            v                            v
[ Container 1 ]           [ Container 2 ]              [ Container 3 ]
 (Musician A)               (Musician B)                 (Musician C)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What Problems Does Kubernetes Solve?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problems&lt;/th&gt;
&lt;th&gt;How Kubernetes Solves It&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Server Crash&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Self-Healing:&lt;/strong&gt; Kubernetes detects the dead node and automatically restarts the affected containers on healthy servers within seconds.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Traffic Surges&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Horizontal Auto-Scaling:&lt;/strong&gt; Automatically scales the number of container copies (replicas) up or down based on CPU, memory, or custom metrics.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Zero-Downtime Updates&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Rolling Deployments:&lt;/strong&gt; Updates containers incrementally one by one. If an error occurs, it automatically rolls back to the last stable version.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Traffic Distribution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Service Discovery &amp;amp; Load Balancing:&lt;/strong&gt; Gives containers a single stable IP/DNS and distributes incoming network traffic evenly among healthy instances.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Secrets &amp;amp; Configs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Centralized Management:&lt;/strong&gt; Injects environment variables, passwords, and API keys securely without baking them into container images.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Kubernetes Architecture Explained
&lt;/h2&gt;

&lt;p&gt;A Kubernetes setup is called a &lt;strong&gt;Cluster&lt;/strong&gt;. A cluster is made of physical machines or Virtual Machines (VMs) divided into two main layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Control Plane (The Brain):&lt;/strong&gt; Makes high-level decisions, monitors the cluster, and schedules workloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Worker Nodes (The Muscle):&lt;/strong&gt; The actual machines that run your containerized applications.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-------------------------------------------------------------------------+
|                              CONTROL PLANE                              |
|                                                                         |
|   +-------------------+   +--------------------+   +----------------+   |
|   |  kube-apiserver   |   |        etcd        |   | kube-scheduler |   |
|   +-------------------+   +--------------------+   +----------------+   |
|             |                                                           |
|   +-------------------------+   +-----------------------------------+   |
|   | kube-controller-manager |   |      cloud-controller-manager     |   |
|   +-------------------------+   +-----------------------------------+   |
+------------------------------------+------------------------------------+
                                     |
              +----------------------+----------------------+
              |                                             |
+-------------v---------------+               +-------------v---------------+
|         WORKER NODE 1       |               |         WORKER NODE 2       |
|                             |               |                             |
|  +-----------------------+  |               |  +-----------------------+  |
|  |        kubelet        |  |               |  |        kubelet        |  |
|  +-----------------------+  |               |  +-----------------------+  |
|  +-----------------------+  |               |  +-----------------------+  |
|  |      kube-proxy       |  |               |  |      kube-proxy       |  |
|  |   (Network Router)    |  |               |  |   (Network Router)    |  |
|  +-----------------------+  |               |  +-----------------------+  |
|  +-----------------------+  |               |  +-----------------------+  |
|  |   Container Runtime   |  |               |  |   Container Runtime   |  |
|  |   [ Pod ]   [ Pod ]   |  |               |  |   [ Pod ]   [ Pod ]   |  |
|  +-----------------------+  |               |  +-----------------------+  |
+-----------------------------+               +-----------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Control Plane Components
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;kube-apiserver:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The main entry point for the entire cluster. Whenever you run a command via &lt;code&gt;kubectl&lt;/code&gt; or an automated CI/CD pipeline triggers a deployment, it speaks directly to the API Server. No component talks to the cluster without going through &lt;code&gt;kube-apiserver&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;etcd:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A fast, highly available, distributed key-value database. It stores the single source of truth for the entire cluster state (e.g., how many pods should be running, their IPs, secrets, and configurations). If it is not recorded in &lt;code&gt;etcd&lt;/code&gt;, it doesn't exist.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;kube-scheduler:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
When you request a new Pod, the scheduler decides &lt;em&gt;which&lt;/em&gt; Worker Node should host it. It checks node capacity, CPU/memory availability, and specific constraints (like "only run on nodes with a GPU") to find the best match.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;kube-controller-manager:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Runs background loops that constantly compare the &lt;strong&gt;actual state&lt;/strong&gt; of the cluster to your &lt;strong&gt;desired state&lt;/strong&gt;. If you requested 3 replicas of an app and one crashes (actual = 2), the controller notices the mismatch and commands the cluster to spin up a replacement.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;cloud-controller-manager:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Interfaces with cloud providers (AWS, Google Cloud, Azure) to provision external resources like cloud load balancers, storage volumes, and firewall rules.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Worker Node Components
&lt;/h3&gt;

&lt;p&gt;Every Worker Node in the cluster runs three essential processes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;kubelet:&lt;/strong&gt;
An agent that runs on each node. It receives instructions from the &lt;code&gt;kube-apiserver&lt;/code&gt; (e.g., "Run container X on this machine") and makes sure the containers are started and remain healthy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;kube-proxy:&lt;/strong&gt;
Manages network routing rules on each node. It ensures that requests sent to a Service get routed to the correct Pods, handling IP translations and load distribution across Pods.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container Runtime:&lt;/strong&gt;
The software responsible for pulling container images and running them (e.g., &lt;code&gt;containerd&lt;/code&gt; or &lt;code&gt;CRI-O&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Core Kubernetes Objects &amp;amp; Concepts
&lt;/h2&gt;

&lt;p&gt;Let's break down the building blocks you will interact with every day.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Pod (The Smallest Deployable Unit)
&lt;/h3&gt;

&lt;p&gt;In Kubernetes, you &lt;strong&gt;never&lt;/strong&gt; deploy a bare container directly. Instead, you deploy a &lt;strong&gt;Pod&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A Pod wraps one or more tightly coupled containers that share:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The same network namespace (meaning they can communicate with each other over &lt;code&gt;localhost&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Shared storage volumes.&lt;/li&gt;
&lt;li&gt;The same IP address.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt; Think of a Pod as a &lt;strong&gt;pea pod&lt;/strong&gt;. The peas inside are individual containers. Most Pods have just 1 container (e.g., your Node.js API), but some use helper "sidecar" containers (e.g., a logging or metrics collection agent).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+----------------------------------------------------+
| Pod (IP: 10.244.1.15)                              |
|                                                    |
|  +------------------------+  +------------------+  |
|  | Main Web App Container |  | Sidecar (Logger) |  |
|  |      (Port 3000)       |  |   (Port 9000)    |  |
|  +------------------------+  +------------------+  |
|               ^                       |            |
|               +--- talks via localhost --+         |
+----------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Deployment (The Self-Healing Manager)
&lt;/h3&gt;

&lt;p&gt;Pods are mortal. If a node loses power or a pod crashes due to an out-of-memory error, that individual Pod is gone forever.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Deployment&lt;/strong&gt; is a higher-level controller that manages Pods for you. You declare your desired state: &lt;em&gt;"I want 3 replicas of my web app running at all times."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The Deployment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates and tracks the Pods.&lt;/li&gt;
&lt;li&gt;Automatically replaces any dead or degraded Pods.&lt;/li&gt;
&lt;li&gt;Performs zero-downtime rolling updates when you change the image version.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Service (The Stable Front Door)
&lt;/h3&gt;

&lt;p&gt;Because Pods frequently start, stop, and move between nodes, their internal IP addresses are ephemeral and change constantly. If your Frontend needs to talk to your Backend, it cannot rely on hardcoded Pod IPs.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Service&lt;/strong&gt; provides a &lt;strong&gt;stable, permanent IP address and DNS name&lt;/strong&gt; that sits in front of a group of Pods and automatically load-balances traffic across them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Incoming Request
       |
       v
+--------------+
| Service VIP  |  (e.g., backend-service:80)
+-------+------+
        |
        +--------+------------------+
        |                           |
        v                           v
  [ Backend Pod 1 ]           [ Backend Pod 2 ]
  (IP: 10.244.1.5)            (IP: 10.244.2.8)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Common Service types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ClusterIP&lt;/code&gt; (Default):&lt;/strong&gt; Accessible only inside the Kubernetes cluster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;NodePort&lt;/code&gt;:&lt;/strong&gt; Exposes the service on a static port on each worker node's IP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;LoadBalancer&lt;/code&gt;:&lt;/strong&gt; Automatically provisions a cloud load balancer (e.g., AWS ALB or GCP Network Load Balancer) to expose your service to the internet.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Ingress (The Traffic Gatekeeper)
&lt;/h3&gt;

&lt;p&gt;While a &lt;code&gt;LoadBalancer&lt;/code&gt; Service gives you a dedicated public IP for a single service, spinning up a new cloud load balancer for every microservice is expensive and hard to manage.&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;Ingress&lt;/strong&gt; acts as a single, smart HTTP/HTTPS reverse proxy and router for your entire cluster:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Routes &lt;code&gt;api.example.com&lt;/code&gt; to your &lt;code&gt;backend-service&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Routes &lt;code&gt;example.com&lt;/code&gt; to your &lt;code&gt;frontend-service&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Handles SSL/TLS certificate termination in one place.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. ConfigMap &amp;amp; Secret (Configuration Decoupling)
&lt;/h3&gt;

&lt;p&gt;Following the 12-factor app methodology, your application code should be completely separated from its configuration.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ConfigMap:&lt;/strong&gt; Stores non-sensitive configuration data (e.g., &lt;code&gt;PORT: 8080&lt;/code&gt;, &lt;code&gt;ENVIRONMENT: production&lt;/code&gt;, &lt;code&gt;LOG_LEVEL: debug&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secret:&lt;/strong&gt; Encrypts and securely stores sensitive data (e.g., database passwords, OAuth tokens, API keys).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These values can be injected into your Pods as environment variables or mounted as configuration files.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Volume (Persistent Storage)
&lt;/h3&gt;

&lt;p&gt;By default, container filesystems are temporary (ephemeral). When a container restarts, any files saved to local disk are wiped clean.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Volume&lt;/strong&gt; attaches persistent storage (such as AWS EBS, Google Persistent Disk, or NFS) to a Pod so data survives pod restarts and migrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Glue": How YAML Files Connect (Labels &amp;amp; Selectors)
&lt;/h2&gt;

&lt;p&gt;Beginners often find Kubernetes YAML files confusing because they wonder: &lt;em&gt;How does a Service know which Pods belong to it? How does a Deployment know which Pods it is managing?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The secret is &lt;strong&gt;Labels and Selectors&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Labels:&lt;/strong&gt; Key-value tags attached to resources (e.g., &lt;code&gt;app: my-web-app&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selectors:&lt;/strong&gt; Queries used by Deployments and Services to find matching Pods.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's see this in action with annotated YAML files.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Deployment YAML
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;deployment.yaml&lt;/code&gt;&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-app-deployment&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Desired number of copies&lt;/span&gt;
    &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;

    &lt;span class="c1"&gt;# 1. SELECTOR: The Deployment manages Pods with this label&lt;/span&gt;
    &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-app&lt;/span&gt;
            &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. TEMPLATE: Blueprint for creating each Pod&lt;/span&gt;
    &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# These labels MUST match the selector above!&lt;/span&gt;
            &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-app&lt;/span&gt;
                &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
        &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-container&lt;/span&gt;
                  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:1.25-alpine&lt;/span&gt;
                  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
                  &lt;span class="na"&gt;envFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;configMapRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app-settings&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Service YAML
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;service.yaml&lt;/code&gt;&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-app-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterIP&lt;/span&gt;
    &lt;span class="c1"&gt;# The Service routes traffic to any Pod matching these labels:&lt;/span&gt;
    &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web-app&lt;/span&gt;
        &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
          &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt; &lt;span class="c1"&gt;# Port exposed by the Service&lt;/span&gt;
          &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt; &lt;span class="c1"&gt;# Port on the container inside the Pod&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. ConfigMap YAML
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;configmap.yaml&lt;/code&gt;&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ConfigMap&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app-settings&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;APP_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;production"&lt;/span&gt;
    &lt;span class="na"&gt;CACHE_ENABLED&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step-by-Step: What Happens When You Apply the YAML files?
&lt;/h2&gt;

&lt;p&gt;When a developer types &lt;code&gt;kubectl apply -f deployment.yaml&lt;/code&gt;, here is the exact sequence of events that unfolds behind the scenes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-----------------------------------------------------------------------+
| 1. Developer runs: kubectl apply -f deployment.yaml                   |
+-----------------------------------+-----------------------------------+
                                    |
                                    v
+-----------------------------+           +-----------------------------+
|       kube-apiserver        | &amp;lt;-------&amp;gt; |            etcd             |
|  (Receives &amp;amp; validates API) |           |  (Saves cluster state)      |
+--------------+--------------+           +-----------------------------+
               |
               | 2. Notifies controller of desired state
               v
+-----------------------------+
|   kube-controller-manager   |
| (Creates 3 Pod definitions) |
+--------------+--------------+
               |
               | 3. Detects unscheduled Pods
               v
+-----------------------------+
|       kube-scheduler        |
|  (Finds best Worker Nodes)  |
+--------------+--------------+
               |
               | 4. Dispatches Pods to Node
               v
+-----------------------------+
|           kubelet           |
| (Worker Node Agent receives)|
+--------------+--------------+
               |
               | 5. Pulls image &amp;amp; starts Pod
               v
+-----------------------------+
|      Container Runtime      |
|    (containerd / CRI-O)     | ===&amp;gt; Pod is LIVE &amp;amp; Healthy!
+-----------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Submission:&lt;/strong&gt; &lt;code&gt;kubectl&lt;/code&gt; sends the YAML manifest via an HTTP POST request to &lt;code&gt;kube-apiserver&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence:&lt;/strong&gt; &lt;code&gt;kube-apiserver&lt;/code&gt; validates the request and saves the record in &lt;code&gt;etcd&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Controller Loop:&lt;/strong&gt; The Deployment Controller detects that 3 Pods are desired, but 0 are currently running. It creates 3 unscheduled Pod objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduling:&lt;/strong&gt; The &lt;code&gt;kube-scheduler&lt;/code&gt; observes the unscheduled Pods, inspects the available Worker Nodes, and assigns each Pod to a node.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution:&lt;/strong&gt; The &lt;code&gt;kubelet&lt;/code&gt; on each assigned node detects the Pod assignment, instructs &lt;code&gt;containerd&lt;/code&gt; to pull the &lt;code&gt;nginx&lt;/code&gt; image, and starts the container.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network Setup:&lt;/strong&gt; &lt;code&gt;kube-proxy&lt;/code&gt; configures routing so traffic sent to &lt;code&gt;web-app-service&lt;/code&gt; reaches the new Pods.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Essential Cheat Sheet for Beginners
&lt;/h2&gt;

&lt;p&gt;Here are the most common &lt;code&gt;kubectl&lt;/code&gt; commands you will use daily:&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;# Check the status of your cluster nodes&lt;/span&gt;
kubectl get nodes

&lt;span class="c"&gt;# View all running Pods and Deployments&lt;/span&gt;
kubectl get pods
kubectl get deployments
kubectl get services

&lt;span class="c"&gt;# Deploy or update resources using a YAML file&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; deployment.yaml

&lt;span class="c"&gt;# View detailed debugging info and events for a specific Pod&lt;/span&gt;
kubectl describe pod &amp;lt;pod-name&amp;gt;

&lt;span class="c"&gt;# View real-time logs from a container&lt;/span&gt;
kubectl logs &lt;span class="nt"&gt;-f&lt;/span&gt; &amp;lt;pod-name&amp;gt;

&lt;span class="c"&gt;# Open an interactive shell inside a running container&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &amp;lt;pod-name&amp;gt; &lt;span class="nt"&gt;--&lt;/span&gt; /bin/sh

&lt;span class="c"&gt;# Manually scale your deployment up or down&lt;/span&gt;
kubectl scale deployment web-app-deployment &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5

&lt;span class="c"&gt;# Delete a resource&lt;/span&gt;
kubectl delete &lt;span class="nt"&gt;-f&lt;/span&gt; deployment.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When Should You Use Kubernetes (and When Should You Avoid It)?
&lt;/h2&gt;

&lt;p&gt;Kubernetes is powerful, but it comes with a steep operational learning curve. It is not always the right tool for every project.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to Use Kubernetes:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You run a microservices architecture with dozens or hundreds of services.&lt;/li&gt;
&lt;li&gt;You need automated horizontal scaling, self-healing, and multi-cloud portability.&lt;/li&gt;
&lt;li&gt;You have a dedicated DevOps or Platform Engineering team to maintain the cluster.&lt;/li&gt;
&lt;li&gt;You need complex rolling deployments, canary releases, or blue-green updates.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When to Avoid Kubernetes:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Small projects or MVPs: If you have a single monolithic app or a small side project, Kubernetes will add unnecessary complexity.&lt;/li&gt;
&lt;li&gt;Simpler alternatives are sufficient: Managed container services like AWS ECS, Google Cloud Run, Render, or Railway offer 90% of the benefits with zero cluster management overhead.&lt;/li&gt;
&lt;li&gt;Local development only: Use &lt;code&gt;docker compose&lt;/code&gt; instead.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>containers</category>
      <category>docker</category>
      <category>devops</category>
    </item>
    <item>
      <title>Docker Demystified: The Ultimate Guide to Containers and Architecture</title>
      <dc:creator>Bibek</dc:creator>
      <pubDate>Fri, 28 Aug 2026 17:08:18 +0000</pubDate>
      <link>https://dev.to/bibekkakati/docker-demystified-the-ultimate-guide-to-containers-and-architecture-h18</link>
      <guid>https://dev.to/bibekkakati/docker-demystified-the-ultimate-guide-to-containers-and-architecture-h18</guid>
      <description>&lt;p&gt;If you have ever dealt with the nightmare of "it works on my machine but crashes in production," you have felt the pain that containerization was built to solve. This post breaks down exactly what Docker is, how it works under the hood, and how it compares to its modern rival, Podman.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Docker
&lt;/h2&gt;

&lt;p&gt;For years, deploying software meant provisioning a server, installing the correct operating system, downloading dependencies, and praying no other application on that server caused a conflict. If you deployed a Node.js server directory directly, you were at the mercy of whatever version of Node, Python, or system libraries happened to be installed on that host machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker&lt;/strong&gt; is a containerization platform that solves this by packaging your application code alongside its entire environment: the specific OS user space, runtime, and system dependencies, into a single, standardized unit called a &lt;strong&gt;container&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Do We Need Docker
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistency:&lt;/strong&gt; The container runs exactly the same way on a developer's Mac, a testing server, and a production AWS EC2 instance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolation:&lt;/strong&gt; You can run App A (requiring Node 16) and App B (requiring Node 20) on the exact same server without them fighting over global variables or dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast Deployments &amp;amp; Rollbacks:&lt;/strong&gt; Because you are pulling a pre-built image rather than running &lt;code&gt;npm install&lt;/code&gt; on a live server, deployments take seconds. If an update breaks, rolling back is as simple as running the previous image version.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Immutability:&lt;/strong&gt; Once an image is built, it cannot be changed. This guarantees that what you tested is exactly what gets deployed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight:&lt;/strong&gt; Unlike Virtual Machines (VMs) that bundle an entire heavy operating system, containers share the host's OS kernel, making them incredibly small (often under 50MB) and fast to boot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portability:&lt;/strong&gt; A Docker image built anywhere can run anywhere Docker is installed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Docker Architecture (The "Kernel" Trick)
&lt;/h2&gt;

&lt;p&gt;To understand why containers are so lightweight, you have to look at the architecture. Every operating system has two parts: the &lt;strong&gt;Kernel&lt;/strong&gt; (which talks to the CPU and memory) and the &lt;strong&gt;User Space&lt;/strong&gt; (the file system, UI, and system utilities).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No Guest Kernel:&lt;/strong&gt; Docker images do &lt;em&gt;not&lt;/em&gt; include a kernel. They only package the User Space (e.g., the Alpine or Ubuntu file system). When the container runs, it hooks directly into the host machine's existing Linux Kernel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client-Server Model:&lt;/strong&gt; Docker relies on a background service called the &lt;strong&gt;Docker Daemon&lt;/strong&gt; (&lt;code&gt;dockerd&lt;/code&gt;). When you type &lt;code&gt;docker run&lt;/code&gt; in your terminal (the Client), it sends an API request to the Daemon, which actually does the heavy lifting of building, running, and monitoring the containers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Managing Environments and Ports
&lt;/h2&gt;

&lt;p&gt;Because containers are isolated boxes, you have to explicitly define how they interact with the outside world.&lt;/p&gt;

&lt;h3&gt;
  
  
  Environment Management
&lt;/h3&gt;

&lt;p&gt;You should never hardcode passwords or API keys into your code. Docker gives you three ways to inject them safely:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Dockerfile (&lt;code&gt;ENV&lt;/code&gt;):&lt;/strong&gt; Bakes default, non-sensitive variables directly into the image.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime (&lt;code&gt;-e&lt;/code&gt;):&lt;/strong&gt; Injects overrides when the container boots (e.g., &lt;code&gt;docker run -e DB_PASS=secret my-app&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Env Files (&lt;code&gt;--env-file&lt;/code&gt;):&lt;/strong&gt; Loads a list of variables from a local &lt;code&gt;.env&lt;/code&gt; file, keeping your CLI commands clean.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Port Management
&lt;/h3&gt;

&lt;p&gt;By default, a container's internal network is completely blocked off.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;EXPOSE&lt;/code&gt; Command:&lt;/strong&gt; Often found in a &lt;code&gt;Dockerfile&lt;/code&gt; (e.g., &lt;code&gt;EXPOSE 3000&lt;/code&gt;), this does &lt;em&gt;not&lt;/em&gt; open the port. It is merely documentation for other developers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publishing Ports:&lt;/strong&gt; To let traffic in, you use the &lt;code&gt;-p&lt;/code&gt; flag to map a port on your host server to a port inside the container: &lt;code&gt;docker run -p 80:3000 my-app&lt;/code&gt;. This forwards all traffic hitting the host's Port 80 directly into the container's Port 3000.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How Docker Build Works (And The Mac/Ubuntu Magic)
&lt;/h2&gt;

&lt;p&gt;If Docker relies on the host's Linux Kernel, how can a developer build and run Linux containers on a Mac?&lt;/p&gt;

&lt;p&gt;When you install Docker Desktop on macOS, it secretly installs a highly optimized, hidden Linux Virtual Machine in the background. When you run &lt;code&gt;docker build&lt;/code&gt;, you are actually using that hidden Linux VM to compile a native Linux image. Therefore, when you move that image to an Ubuntu EC2 instance, it feels right at home.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚠️ The Caveat: CPU Architecture
&lt;/h3&gt;

&lt;p&gt;While the OS difference is handled via the hidden VM, the &lt;strong&gt;CPU Architecture&lt;/strong&gt; is a strict physical boundary.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modern Macs use &lt;strong&gt;ARM64&lt;/strong&gt; processors (M1/M2/M3 chips).&lt;/li&gt;
&lt;li&gt;Standard AWS EC2 instances use &lt;strong&gt;AMD64&lt;/strong&gt; (x86) processors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you build an image on an M-series Mac and run it on a standard EC2 instance, it will crash with an &lt;code&gt;exec format error&lt;/code&gt;. To fix this, you must either cross-compile during the build (&lt;code&gt;docker build --platform linux/amd64&lt;/code&gt;) or deploy to an ARM-based server (like AWS Graviton instances).&lt;/p&gt;

&lt;h2&gt;
  
  
  Registries: Updating and Pulling Images
&lt;/h2&gt;

&lt;p&gt;You do not manually upload Docker images via SSH. Instead, you use a &lt;strong&gt;Container Registry&lt;/strong&gt;—a specialized storage server designed to hold container images.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Workflow:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Tag:&lt;/strong&gt; Name your image with the registry URL (e.g., &lt;code&gt;docker tag my-app accnt.dkr.ecr.us-east-1.amazonaws.com/my-app:v2&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Push:&lt;/strong&gt; Upload the updated code/environment to the registry (&lt;code&gt;docker push ...&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pull:&lt;/strong&gt; On your EC2 server, fetch the new image (&lt;code&gt;docker pull ...&lt;/code&gt;) and restart the container.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Types of Registries:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Docker Hub:&lt;/strong&gt; The public default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS ECR:&lt;/strong&gt; Secure, private, and tightly integrated into AWS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-Hosted:&lt;/strong&gt; You can run your own registry using Docker itself. However, the Docker Daemon strictly requires &lt;strong&gt;HTTPS&lt;/strong&gt; for registries. If you self-host via plain HTTP, you must explicitly configure the daemon to allow &lt;code&gt;insecure-registries&lt;/code&gt;, otherwise it will block the connection.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Obvious Concerns Clarified
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Performance Gap, Latency, and CPU/RAM Consumption
&lt;/h3&gt;

&lt;p&gt;Containers do not run a hypervisor or a separate OS, so they have &lt;strong&gt;zero CPU or memory overhead&lt;/strong&gt;. Your Node.js app runs at bare-metal speeds.&lt;br&gt;
There is a microscopic network latency overhead (about 5-25 microseconds) when using Docker's default "Bridge" network due to internal routing. If you require absolute zero latency, you can use the &lt;code&gt;--network host&lt;/code&gt; flag, which binds the container directly to the host's network interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  Image-to-Image Communication
&lt;/h3&gt;

&lt;p&gt;How does a Node.js container talk to a Redis container on the same server?&lt;br&gt;
They do not use &lt;code&gt;localhost&lt;/code&gt;. Instead, Docker creates a private internal network with its own DNS. If you name your cache container &lt;code&gt;redis-server&lt;/code&gt;, your Node.js app can connect to it simply via &lt;code&gt;redis://redis-server:6379&lt;/code&gt;. The ports never have to be exposed to the public internet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Volume Storage (Hosting Databases)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Containers are ephemeral.&lt;/strong&gt; If a container restarts, all data created inside it is permanently destroyed.&lt;br&gt;
If you run a database inside Docker, you must use &lt;strong&gt;Docker Volumes&lt;/strong&gt;. This maps a persistent folder on your host server (e.g., &lt;code&gt;/home/ubuntu/db-data&lt;/code&gt;) to the database directory inside the container. When the container dies, the data remains safely on the EC2 drive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker vs. Podman: What is the Difference?
&lt;/h2&gt;

&lt;p&gt;As containerization evolves, Docker is no longer the only option. &lt;strong&gt;Podman&lt;/strong&gt; is a modern alternative that aims to solve a few structural concerns with Docker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Architectual Shift:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Daemon vs. Daemonless:&lt;/strong&gt; Docker relies on the central &lt;code&gt;dockerd&lt;/code&gt; background daemon to manage everything. If the daemon crashes, your containers can go down. Podman is &lt;strong&gt;daemonless&lt;/strong&gt;; each container runs as an independent, isolated child process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security (Rootless by Default):&lt;/strong&gt; The Docker daemon requires root privileges, which is a security risk if an attacker breaks out of the container. Podman was built from the ground up to be &lt;strong&gt;rootless&lt;/strong&gt;. You can build and run containers as a standard user without any elevated privileges, drastically reducing the attack surface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compatibility:&lt;/strong&gt; Podman intentionally mimics the Docker CLI. In most CI/CD pipelines or local development environments, you can simply &lt;code&gt;alias docker=podman&lt;/code&gt; and your existing scripts will run without modification.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While Docker remains the king of developer experience and tooling, Podman is rapidly becoming the enterprise standard for secure, production-grade Linux environments.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>containers</category>
      <category>devops</category>
      <category>automation</category>
    </item>
    <item>
      <title>The State Pattern Trap: Why GoF Is Not Always the Best Choice</title>
      <dc:creator>Bibek</dc:creator>
      <pubDate>Wed, 26 Aug 2026 09:20:13 +0000</pubDate>
      <link>https://dev.to/bibekkakati/the-state-pattern-trap-why-gof-is-not-always-the-best-choice-487k</link>
      <guid>https://dev.to/bibekkakati/the-state-pattern-trap-why-gof-is-not-always-the-best-choice-487k</guid>
      <description>&lt;p&gt;Have you ever tried to use the classic &lt;a href="https://www.geeksforgeeks.org/system-design/gang-of-four-gof-design-patterns/" rel="noopener noreferrer"&gt;Gang of Four (GoF)&lt;/a&gt; State Pattern in real code? You might have hit a wall. You might have thought, "Wait, this feels way too connected."&lt;/p&gt;

&lt;p&gt;You are not wrong about that.&lt;/p&gt;

&lt;p&gt;In school and many engineering interviews, the GoF State Pattern looks great. It promises to fix big, ugly &lt;code&gt;switch&lt;/code&gt; statements. But real business rules are hard. When you use this pattern in real life, it can become a huge mess. Every state knows too much about the other states.&lt;/p&gt;

&lt;p&gt;Let us look at why this happens. We will learn the difference between the GoF pattern and a Finite State Machine (FSM). We will also learn when to use each one.&lt;/p&gt;




&lt;h2&gt;
  
  
  The False Promise of the GoF State Pattern
&lt;/h2&gt;

&lt;p&gt;The main idea of the GoF State Pattern is to spread out the work.&lt;/p&gt;

&lt;p&gt;The main object gives its work to state objects. But there is a catch. The state classes themselves must trigger the change to the next state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: The Traffic Light
&lt;/h3&gt;

&lt;p&gt;Think about a simple traffic light. It goes Red to Green to Yellow to Red. It does this forever.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RedState&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;TrafficLightState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TrafficLight&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;RED light, Stop&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GreenState&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// Very connected!&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;The Problem:&lt;/strong&gt; &lt;code&gt;RedState&lt;/code&gt; is forced to know about &lt;code&gt;GreenState&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is fine for a simple traffic light. It is a closed loop. The rules will never change.&lt;/p&gt;

&lt;p&gt;But what happens when business rules change?&lt;br&gt;
Imagine the city council makes a new rule. From midnight to 5:00 AM, the light must flash yellow.&lt;/p&gt;

&lt;p&gt;Now, you must open your &lt;code&gt;RedState&lt;/code&gt; and &lt;code&gt;YellowState&lt;/code&gt; classes. You have to add new time checks. You have to add the new flashing state. The more states you add, the messier your code gets.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Better Choice: The Central FSM
&lt;/h2&gt;

&lt;p&gt;In the real world, things do not always happen in a straight line.&lt;/p&gt;

&lt;p&gt;An online order does not just go from Pending to Shipped to Delivered. It can jump from Pending to Cancelled. It can go from Shipped to Returned.&lt;/p&gt;

&lt;p&gt;If you use GoF here, your &lt;code&gt;PendingState&lt;/code&gt; needs to know about many other states. It gets too big.&lt;/p&gt;

&lt;p&gt;This is where the Finite State Machine (FSM) comes in.&lt;br&gt;
The main idea here is central control. State classes become simple. They only hold the rules for what happens inside that specific state. A central controller handles the moves between states. We call this central controller an Orchestrator.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Order Processing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orderRules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;PENDING&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;PAID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SHIPPED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;CANCELLED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CANCELLED&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="na"&gt;SHIPPED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;ARRIVED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DELIVERED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;RETURNED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;RETURNED&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="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;currentState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PENDING&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;handleEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;nextState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;orderRules&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;currentState&lt;/span&gt;&lt;span class="p"&gt;]?.[&lt;/span&gt;&lt;span class="nx"&gt;event&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;nextState&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;currentState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nextState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="c1"&gt;// Run the state logic here&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bad move!&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="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;Why this works better:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Not Connected:&lt;/strong&gt; State handlers do not know about each other.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear Rules:&lt;/strong&gt; You can look at one simple list to understand the whole flow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy to Change:&lt;/strong&gt; Adding a new state does not break your old code. You just update the rules list.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Final Choice: Which Should You Use?
&lt;/h2&gt;

&lt;p&gt;Here are some simple rules to follow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use the GoF State Pattern when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The flow is always a simple loop. A traffic light is a good example.&lt;/li&gt;
&lt;li&gt;The rules are locked. You are very sure you will never add new states.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Use a Central FSM when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The rules are complex and can jump around. Online orders and game AI are good examples.&lt;/li&gt;
&lt;li&gt;Outside events choose the next state. If a user click or a timer changes things, use an FSM.&lt;/li&gt;
&lt;li&gt;You need to track your code. A central FSM makes it very easy to see why a state changed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Do not let old textbooks force you to write bad code. The GoF State Pattern is great for learning and for simple problems. But for complex real world software, a central FSM will save you a lot of stress.&lt;/p&gt;

</description>
      <category>lld</category>
      <category>designpatterns</category>
      <category>statemachine</category>
    </item>
    <item>
      <title>9 RAG Techniques That Actually Improve Retrieval Quality</title>
      <dc:creator>Bibek</dc:creator>
      <pubDate>Sat, 22 Aug 2026 19:36:18 +0000</pubDate>
      <link>https://dev.to/bibekkakati/9-rag-techniques-that-actually-improve-retrieval-quality-36jh</link>
      <guid>https://dev.to/bibekkakati/9-rag-techniques-that-actually-improve-retrieval-quality-36jh</guid>
      <description>&lt;p&gt;Retrieval-Augmented Generation (RAG) is often described as a simple pipeline:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Query → Retrieve documents → Send context to an LLM → Generate answer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In production, however, retrieval is rarely that simple.&lt;/p&gt;

&lt;p&gt;The retriever can return irrelevant documents. Important information may be buried in the middle of a document. A query may be too vague for semantic search. Retrieved chunks may lose their surrounding context. And sometimes the model does not need retrieval at all.&lt;/p&gt;

&lt;p&gt;The quality of a RAG system therefore depends heavily on &lt;strong&gt;how information is retrieved, filtered, ranked, compressed, and presented to the model&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This guide covers nine techniques that address different parts of the RAG pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reranking&lt;/li&gt;
&lt;li&gt;Hybrid Search&lt;/li&gt;
&lt;li&gt;Chunking Strategies&lt;/li&gt;
&lt;li&gt;Multi-Query Retrieval&lt;/li&gt;
&lt;li&gt;Parent Document Retrieval&lt;/li&gt;
&lt;li&gt;Context Compression&lt;/li&gt;
&lt;li&gt;HyDE&lt;/li&gt;
&lt;li&gt;Self-RAG&lt;/li&gt;
&lt;li&gt;CRAG&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. Reranking
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Retrieve candidates. Reranking finds the best.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A vector database may search through hundreds or thousands of documents and return the top 20 candidate chunks.&lt;/p&gt;

&lt;p&gt;But the first result from vector search is not necessarily the best result.&lt;/p&gt;

&lt;p&gt;For example, suppose the correct answer is ranked at position #19.&lt;/p&gt;

&lt;p&gt;If the application only sends the top 3–5 chunks to the LLM, the correct information never reaches the model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;                100 Pages
                    ↓
              Vector Search
                    ↓
           20 Candidate Chunks
                    │
        ┌───────────┴───────────┐
        ↓                       ↓
  Without Reranking       With Reranking
        ↓                       ↓
  Top 3–5 Chunks             Reranker
        ↓                       ↓
        │                 Top 5 Relevant
        │                     Chunks
        ↓                       ↓
        ↓                       ↓
       LLM                     LLM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without reranking, the most relevant chunk might be ranked #19 and never reach the model.&lt;/p&gt;

&lt;p&gt;With reranking, a reranker evaluates the retrieved candidates using both the query and the content of each chunk, promoting the most relevant results to the top.&lt;/p&gt;

&lt;p&gt;The reranker can move a previously low-ranked but highly relevant chunk to the top.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does a reranker do?
&lt;/h3&gt;

&lt;p&gt;A reranker essentially asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which of these retrieved chunks actually answers the user's question best?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unlike basic vector similarity, a reranker can inspect the relationship between the entire query and the retrieved document.&lt;/p&gt;

&lt;p&gt;This helps it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand context better&lt;/li&gt;
&lt;li&gt;Find hidden relevance&lt;/li&gt;
&lt;li&gt;Filter out noise&lt;/li&gt;
&lt;li&gt;Improve the quality of the final answer&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Types of rerankers
&lt;/h3&gt;

&lt;p&gt;Common approaches include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cross-Encoder&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High accuracy&lt;/li&gt;
&lt;li&gt;Slower&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bi-Encoder + Rerank Model&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Balanced performance&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;LLM-based Reranker&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Potentially highest quality&lt;/li&gt;
&lt;li&gt;More expensive&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;Suppose a developer asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How can I make a Node.js API handle thousands of simultaneous connections?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A basic vector search might initially return chunks about HTTP status codes, API authentication, or general Node.js syntax.&lt;/p&gt;

&lt;p&gt;A reranker can compare each candidate directly against the question and prioritize content discussing connection handling, asynchronous I/O, event loops, connection pooling, and horizontal scaling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key takeaway
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Retrieve more. Rerank intelligently. Let the LLM see the best context, not merely the first context.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Hybrid Search
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Meaning + Keywords = Better Retrieval&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Semantic vector search and keyword search solve different problems.&lt;/p&gt;

&lt;p&gt;Vector search understands &lt;strong&gt;meaning&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Keyword search understands &lt;strong&gt;exact words&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Using only one can cause important documents to be missed.&lt;/p&gt;

&lt;h3&gt;
  
  
  The problem
&lt;/h3&gt;

&lt;p&gt;Consider this query:&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="s2"&gt;"Redis connection timeout"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A semantic search might return:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Diagnosing cache connection failures&lt;/li&gt;
&lt;li&gt;Distributed cache troubleshooting&lt;/li&gt;
&lt;li&gt;Network latency in application infrastructure&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These documents may be semantically related, but the exact phrase &lt;code&gt;Redis connection timeout&lt;/code&gt; might not appear.&lt;/p&gt;

&lt;p&gt;A keyword search such as BM25 can find:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Redis connection timeout configuration&lt;/li&gt;
&lt;li&gt;Fixing Redis client timeout errors&lt;/li&gt;
&lt;li&gt;Redis socket timeout settings&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But keyword search may fail when the document uses different terminology.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hybrid Search
&lt;/h3&gt;

&lt;p&gt;Hybrid search combines both approaches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;                User Query
                    │
          ┌─────────┴─────────┐
          ↓                   ↓
    Vector Search        Keyword Search
     &lt;span class="o"&gt;(&lt;/span&gt;Semantic&lt;span class="o"&gt;)&lt;/span&gt;              &lt;span class="o"&gt;(&lt;/span&gt;BM25&lt;span class="o"&gt;)&lt;/span&gt;
          │                   │
          └─────────┬─────────┘
                    ↓
              Merge &amp;amp; Rank
                    ↓
              Final Results
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The results from both searches are combined and ranked.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common ranking methods
&lt;/h3&gt;

&lt;p&gt;Popular approaches include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reciprocal Rank Fusion (RRF)&lt;/li&gt;
&lt;li&gt;Weighted score combination&lt;/li&gt;
&lt;li&gt;Relative score fusion&lt;/li&gt;
&lt;li&gt;Rank-based fusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why hybrid search works
&lt;/h3&gt;

&lt;p&gt;Vector search is good at understanding intent:&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="s2"&gt;"cache performance troubleshooting"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keyword search is good at exact terms:&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="s2"&gt;"Redis MISCONF"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A production search system often needs both.&lt;/p&gt;

&lt;h3&gt;
  
  
  When hybrid search is useful
&lt;/h3&gt;

&lt;p&gt;Hybrid search is particularly useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Technical documentation&lt;/li&gt;
&lt;li&gt;Spelling variations&lt;/li&gt;
&lt;li&gt;Abbreviations&lt;/li&gt;
&lt;li&gt;Exact technical terms&lt;/li&gt;
&lt;li&gt;Natural language queries&lt;/li&gt;
&lt;li&gt;Systems requiring both high recall and high precision&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key takeaway
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't choose between meaning and keywords. Use both.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3. Chunking Strategies
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Good chunks → Better Retrieval → Better Answers&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Chunking is one of the most important decisions in a RAG system.&lt;/p&gt;

&lt;p&gt;Documents are usually too large to embed and retrieve as a single unit, so they must be divided into smaller pieces.&lt;/p&gt;

&lt;p&gt;But chunk size matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why chunking matters
&lt;/h3&gt;

&lt;p&gt;If a chunk is too large:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Important information can get buried&lt;/li&gt;
&lt;li&gt;Retrieval becomes less precise&lt;/li&gt;
&lt;li&gt;More irrelevant context reaches the LLM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a chunk is too small:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Context is lost&lt;/li&gt;
&lt;li&gt;More noise can be introduced&lt;/li&gt;
&lt;li&gt;Individual chunks may not contain enough information to answer a question&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Keep chunks as small as possible for precision, but as large as necessary for completeness.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  1. Fixed-Size Chunking
&lt;/h3&gt;

&lt;p&gt;The document is divided into chunks of a fixed number of tokens.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Document
   ↓
400 tokens
   ↓
400 tokens
   ↓
400 tokens
   ↓
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An overlap can be added between chunks.&lt;/p&gt;

&lt;h4&gt;
  
  
  Advantages
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Simple&lt;/li&gt;
&lt;li&gt;Fast&lt;/li&gt;
&lt;li&gt;Works reasonably well for general documents&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Disadvantages
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Can split sentences or concepts in the middle&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Sentence-Based Chunking
&lt;/h3&gt;

&lt;p&gt;Instead of splitting at arbitrary token boundaries, the system splits around sentence boundaries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Sentence 1
Sentence 2
Sentence 3

Sentence 4
Sentence 5
Sentence 6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Advantages
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Preserves meaning better&lt;/li&gt;
&lt;li&gt;More natural and readable&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Disadvantage
&lt;/h4&gt;

&lt;p&gt;Sentence lengths can vary significantly.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Semantic Chunking
&lt;/h3&gt;

&lt;p&gt;Semantic chunking groups sentences or paragraphs based on their meaning.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Topic A
  ├── Authentication configuration
  ├── Token validation
  └── Session management

Topic B
  ├── Database indexing
  ├── Query planning
  └── Connection pooling
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Advantages
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;High topic relevance&lt;/li&gt;
&lt;li&gt;Keeps related content together&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Disadvantages
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;More complicated&lt;/li&gt;
&lt;li&gt;Requires embeddings&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Parent Document Chunking
&lt;/h3&gt;

&lt;p&gt;Small chunks are used for retrieval, but the larger parent section is returned to the LLM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    Large Parent Document
              │
   ┌──────────┼──────────┐
   ↓          ↓          ↓
 Small      Small      Small
 Chunk      Chunk      Chunk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The small chunks provide retrieval precision while the parent document provides context.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Sliding Window Chunking
&lt;/h3&gt;

&lt;p&gt;A moving window is used to create overlapping chunks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Window 1
████████

    Window 2
    ████████

        Window 3
        ████████
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This preserves more context across chunk boundaries.&lt;/p&gt;

&lt;h4&gt;
  
  
  Advantages
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Good coverage&lt;/li&gt;
&lt;li&gt;Maintains context flow&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Disadvantage
&lt;/h4&gt;

&lt;p&gt;More chunks mean more storage and potentially more retrieval cost.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. Structure-Aware Chunking
&lt;/h3&gt;

&lt;p&gt;The document's structure is used to determine chunk boundaries.&lt;/p&gt;

&lt;p&gt;For example:&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;# Authentication&lt;/span&gt;
    ↓
Chunk 1

&lt;span class="c"&gt;## Token Validation&lt;/span&gt;
    ↓
Chunk 2

- Access token
- Refresh token
    ↓
Chunk 3

Configuration Table
    ↓
Chunk 4

Code Block
    ↓
Chunk 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works particularly well for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Documentation&lt;/li&gt;
&lt;li&gt;Code&lt;/li&gt;
&lt;li&gt;Structured PDFs&lt;/li&gt;
&lt;li&gt;Knowledge bases&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How should you choose?
&lt;/h3&gt;

&lt;p&gt;There is no universally best chunking strategy.&lt;/p&gt;

&lt;p&gt;The right strategy depends on the data.&lt;/p&gt;

&lt;p&gt;A production system may combine multiple approaches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Structure-aware splitting
        +
Semantic grouping
        +
Parent document retrieval
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should also experiment with chunk sizes such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;256 tokens
512 tokens
1024 tokens
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and measure actual retrieval performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key takeaway
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Good chunks bring the right context. The right context helps the LLM produce the right answer.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  4. Multi-Query Retrieval
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;One question. Multiple perspectives. Better results.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A single query can fail because documents may describe the same concept using completely different language.&lt;/p&gt;

&lt;p&gt;Even if query expansion improves the wording, searching in only one direction can still miss relevant documents.&lt;/p&gt;

&lt;h3&gt;
  
  
  The idea
&lt;/h3&gt;

&lt;p&gt;Instead of searching once, ask the LLM to generate multiple versions of the query.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Original question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How does OAuth token refresh work?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The system might generate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;What is OAuth token refresh?

How does a refresh token work?

What happens when an access token expires?

How does an application obtain a new access token?

What is the OAuth refresh-token flow?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each query is searched independently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;               Original Question
                     ↓
               Generate Queries
                     ↓
        ┌────────┬────────┬────────┐
        ↓        ↓        ↓        ↓
      Search   Search   Search   Search
        └────────┴────────┴────────┘
                     ↓
               Merge &amp;amp; Rerank
                     ↓
                Final Chunks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why this works
&lt;/h3&gt;

&lt;p&gt;Different documents use different terminology.&lt;/p&gt;

&lt;p&gt;One document might say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;OAuth token refresh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while another says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;renewing an expired access token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and another says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;obtaining a new bearer token using a refresh credential
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multiple queries give the retriever more opportunities to find relevant information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-Query vs Query Expansion
&lt;/h3&gt;

&lt;p&gt;These concepts are related but not identical.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Query Expansion&lt;/th&gt;
&lt;th&gt;Multi-Query&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Main goal&lt;/td&gt;
&lt;td&gt;Better wording&lt;/td&gt;
&lt;td&gt;Different viewpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Queries&lt;/td&gt;
&lt;td&gt;Similar variations&lt;/td&gt;
&lt;td&gt;More diverse queries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Focus&lt;/td&gt;
&lt;td&gt;Query improvement&lt;/td&gt;
&lt;td&gt;Retrieval coverage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recall&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Often higher&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical use&lt;/td&gt;
&lt;td&gt;General search&lt;/td&gt;
&lt;td&gt;Production RAG&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  When it works best
&lt;/h3&gt;

&lt;p&gt;Multi-query retrieval is particularly useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large knowledge bases&lt;/li&gt;
&lt;li&gt;Technical documentation&lt;/li&gt;
&lt;li&gt;Enterprise search&lt;/li&gt;
&lt;li&gt;Research papers&lt;/li&gt;
&lt;li&gt;Legal documents&lt;/li&gt;
&lt;li&gt;Medical documents&lt;/li&gt;
&lt;li&gt;Production RAG systems&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key takeaway
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't ask once. Ask in multiple smart ways.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;More angles give the retriever more chances to find the right information.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Parent Document Retrieval
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Small chunks = better search. Parent documents = better understanding.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Small chunks are useful because they make retrieval precise.&lt;/p&gt;

&lt;p&gt;But small chunks have a problem:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They can lose context.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider retrieving this chunk:&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="s2"&gt;"... it automatically retries failed operations ..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The chunk might be relevant, but by itself it doesn't tell us what "it" refers to.&lt;/p&gt;

&lt;p&gt;The original section might say:&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="s2"&gt;"The job processor automatically retries failed operations when a worker temporarily loses access to the message queue."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The parent document provides the missing context.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Parent Document Retrieval works
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Step 1: Create small chunks
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Document
   ↓
Chunk 1
Chunk 2
Chunk 3
Chunk 4
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2: Search the small chunks
&lt;/h4&gt;

&lt;p&gt;The vector database retrieves the most relevant chunks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Top Chunks:
1
2
8
9
10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Map chunks to their parent
&lt;/h4&gt;

&lt;p&gt;Each chunk stores a reference to its parent section or document.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Chunk 8
   ↓
Parent Document / Section
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 4: Send the parent context to the LLM
&lt;/h4&gt;

&lt;p&gt;Instead of giving the LLM only the tiny chunk, provide the relevant parent section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Small chunks → Search

Parent document → Context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a useful separation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Retrieve small. Read big.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  When to use it
&lt;/h3&gt;

&lt;p&gt;Parent document retrieval is useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chunks are very small&lt;/li&gt;
&lt;li&gt;Documents contain many references&lt;/li&gt;
&lt;li&gt;Answers require surrounding context&lt;/li&gt;
&lt;li&gt;Pronouns and references are common&lt;/li&gt;
&lt;li&gt;The meaning depends on information elsewhere in the section&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Implementation tip
&lt;/h3&gt;

&lt;p&gt;Store a &lt;code&gt;parent_id&lt;/code&gt; with each chunk.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Chunk:
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;id&lt;/span&gt;: &lt;span class="s2"&gt;"chunk_123"&lt;/span&gt;,
  parent_id: &lt;span class="s2"&gt;"section_42"&lt;/span&gt;,
  embedding: &lt;span class="o"&gt;[&lt;/span&gt;...]
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After retrieval, use &lt;code&gt;parent_id&lt;/code&gt; to fetch the larger context.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key takeaway
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Chunks help you find information. Parent documents help the model understand it.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  6. Context Compression
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Too much context can be as bad as too little.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine a retriever returns 40 chunks, but your LLM can effectively process only 8 useful chunks.&lt;/p&gt;

&lt;p&gt;Sending all 40 creates several problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Higher token usage&lt;/li&gt;
&lt;li&gt;Higher cost&lt;/li&gt;
&lt;li&gt;More irrelevant information&lt;/li&gt;
&lt;li&gt;More redundancy&lt;/li&gt;
&lt;li&gt;Potentially worse answers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is related to the &lt;strong&gt;lost-in-the-middle&lt;/strong&gt; problem: important information can become harder for the model to use when surrounded by large amounts of irrelevant context.&lt;/p&gt;

&lt;h3&gt;
  
  
  How context compression works
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;40 Retrieved Chunks
        ↓
     Compress
        ↓
Keep Relevant Information
        ↓
8 Clean Chunks
        ↓
       LLM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compressor attempts to remove everything that does not contribute meaningfully to answering the question.&lt;/p&gt;

&lt;h3&gt;
  
  
  What can be compressed?
&lt;/h3&gt;

&lt;p&gt;Common targets include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Duplicate chunks&lt;/li&gt;
&lt;li&gt;Filler sentences&lt;/li&gt;
&lt;li&gt;Low-relevance information&lt;/li&gt;
&lt;li&gt;Long-winded explanations&lt;/li&gt;
&lt;li&gt;Off-topic sections&lt;/li&gt;
&lt;li&gt;Repeated information&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Popular compression techniques
&lt;/h3&gt;

&lt;h4&gt;
  
  
  LLM Summarization
&lt;/h4&gt;

&lt;p&gt;Summarize each chunk into a smaller representation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Large chunk
    ↓
1–2 sentence summary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Keyword / Keyphrase Extraction
&lt;/h4&gt;

&lt;p&gt;Keep the most important terms and phrases.&lt;/p&gt;

&lt;h4&gt;
  
  
  Redundancy Removal
&lt;/h4&gt;

&lt;p&gt;Remove information that appears repeatedly across retrieved documents.&lt;/p&gt;

&lt;h4&gt;
  
  
  Extractive Compression
&lt;/h4&gt;

&lt;p&gt;Keep only the sentences that directly contribute to answering the query.&lt;/p&gt;

&lt;h4&gt;
  
  
  Relevance Scoring
&lt;/h4&gt;

&lt;p&gt;Score individual sentences or chunks and keep only high-scoring content.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;Suppose retrieval returns 40 chunks.&lt;/p&gt;

&lt;p&gt;After compression:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;40 chunks
   ↓
8 chunks
   ↓
~75% token reduction
   ↓
Better focused context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact improvement depends on the data and compression method, but the goal is to make the context &lt;strong&gt;smaller without losing useful information&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key takeaway
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;More context is not always better. Relevant context is better.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  7. HyDE
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Hypothetical Document Embeddings
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;Think before you search.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;HyDE stands for &lt;strong&gt;Hypothetical Document Embeddings&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It addresses a common retrieval problem:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The user's query may be too short or vague to produce a strong embedding.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example:&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="s2"&gt;"message queue retries"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The query contains only a few terms.&lt;/p&gt;

&lt;p&gt;A better search signal could be a hypothetical answer generated by an LLM.&lt;/p&gt;

&lt;h3&gt;
  
  
  How HyDE works
&lt;/h3&gt;

&lt;p&gt;Instead of embedding the original question:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;User Question
     ↓
Embedding
     ↓
Vector Search
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HyDE introduces an intermediate generation step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;User Question
     ↓
Generate Hypothetical Answer
     ↓
Embed Hypothetical Answer
     ↓
Vector Search
     ↓
Retrieve Documents
     ↓
    LLM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, the user asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How does a message queue retry failed jobs?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The LLM might generate a hypothetical answer such as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A message processing system can retry a failed job when the worker encounters a temporary error. Retry policies commonly use a maximum attempt count and exponential backoff before moving permanently failed messages to a dead-letter queue.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The hypothetical answer contains more meaningful domain terms than the original question.&lt;/p&gt;

&lt;p&gt;The system embeds that hypothetical answer and uses the embedding to search the knowledge base.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why it can work
&lt;/h3&gt;

&lt;p&gt;The generated answer may contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More domain-specific terminology&lt;/li&gt;
&lt;li&gt;More context&lt;/li&gt;
&lt;li&gt;Better representation of the user's intent&lt;/li&gt;
&lt;li&gt;Terms that are likely to appear in relevant documents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This can improve semantic matching.&lt;/p&gt;

&lt;h3&gt;
  
  
  HyDE is not random guessing
&lt;/h3&gt;

&lt;p&gt;The hypothetical answer is not used as the final answer.&lt;/p&gt;

&lt;p&gt;It is primarily a &lt;strong&gt;search representation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The actual answer still comes from retrieved documents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Question
   ↓
Hypothetical Answer
   ↓
Embedding
   ↓
Retrieve Real Documents
   ↓
Generate Final Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  HyDE vs Query Expansion
&lt;/h3&gt;

&lt;p&gt;Query expansion usually creates multiple alternative queries.&lt;/p&gt;

&lt;p&gt;HyDE generates a hypothetical document or answer and embeds that representation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Query Expansion
→ Multiple queries

HyDE
→ One hypothetical answer
→ One embedding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  When HyDE is useful
&lt;/h3&gt;

&lt;p&gt;HyDE can help with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RAG systems&lt;/li&gt;
&lt;li&gt;Research assistants&lt;/li&gt;
&lt;li&gt;Code search&lt;/li&gt;
&lt;li&gt;Legal search&lt;/li&gt;
&lt;li&gt;Medical document search&lt;/li&gt;
&lt;li&gt;Enterprise knowledge bases&lt;/li&gt;
&lt;li&gt;Vague or complex queries&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key takeaway
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;HyDE turns a weak question into a stronger search signal.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  8. Self-RAG
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Why search every time? Let the model decide first.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Traditional RAG often retrieves documents for every query.&lt;/p&gt;

&lt;p&gt;But not every question needs external retrieval.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;What is the square root of 144?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retrieving documents from a vector database would be unnecessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  The problem
&lt;/h3&gt;

&lt;p&gt;Always retrieving causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extra latency&lt;/li&gt;
&lt;li&gt;Extra token usage&lt;/li&gt;
&lt;li&gt;Additional infrastructure cost&lt;/li&gt;
&lt;li&gt;Unnecessary vector database load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Self-RAG introduces a decision step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;      User Question
            ↓
   Should I retrieve?
            ↓
   ┌────────┴────────┐
  NO                YES
   ↓                 ↓
Answer            Retrieve
Directly             ↓
                  Generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How Self-RAG works
&lt;/h3&gt;

&lt;p&gt;The model first considers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do I need external information?&lt;/li&gt;
&lt;li&gt;Do I already know the answer?&lt;/li&gt;
&lt;li&gt;Is the question domain-specific?&lt;/li&gt;
&lt;li&gt;Is the information likely to be recent?&lt;/li&gt;
&lt;li&gt;Do I need private or internal documents?&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  If the answer is NO
&lt;/h4&gt;

&lt;p&gt;The model answers using its internal knowledge.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;What is 15 × 8?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No retrieval is required.&lt;/p&gt;

&lt;h4&gt;
  
  
  If the answer is YES
&lt;/h4&gt;

&lt;p&gt;The system retrieves relevant documents.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;What changed &lt;span class="k"&gt;in &lt;/span&gt;our company&lt;span class="s1"&gt;'s API documentation this week?
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retrieval is useful because the information is recent and internal.&lt;/p&gt;

&lt;h3&gt;
  
  
  When should Self-RAG retrieve?
&lt;/h3&gt;

&lt;p&gt;Typical cases include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recent information&lt;/li&gt;
&lt;li&gt;Live information&lt;/li&gt;
&lt;li&gt;Domain-specific knowledge&lt;/li&gt;
&lt;li&gt;Private/internal documents&lt;/li&gt;
&lt;li&gt;Complex multi-hop questions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When can it skip retrieval?
&lt;/h3&gt;

&lt;p&gt;Typical cases include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;General knowledge&lt;/li&gt;
&lt;li&gt;Simple mathematics&lt;/li&gt;
&lt;li&gt;Logic questions&lt;/li&gt;
&lt;li&gt;Common facts&lt;/li&gt;
&lt;li&gt;Questions where the model is sufficiently confident&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;p&gt;Self-RAG can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduce unnecessary retrieval&lt;/li&gt;
&lt;li&gt;Save tokens&lt;/li&gt;
&lt;li&gt;Reduce cost&lt;/li&gt;
&lt;li&gt;Reduce vector database load&lt;/li&gt;
&lt;li&gt;Improve response latency&lt;/li&gt;
&lt;li&gt;Use retrieval when it actually matters&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key takeaway
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Traditional RAG retrieves every time. Self-RAG decides whether retrieval is needed before acting.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  9. CRAG
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Corrective Retrieval-Augmented Generation
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;Not every retrieved chunk is useful. CRAG checks the quality before trusting it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A retriever is not perfect.&lt;/p&gt;

&lt;p&gt;It can return:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Irrelevant chunks&lt;/li&gt;
&lt;li&gt;Outdated information&lt;/li&gt;
&lt;li&gt;Misleading information&lt;/li&gt;
&lt;li&gt;Incomplete information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the LLM blindly trusts those chunks, it can produce a confident but incorrect answer.&lt;/p&gt;

&lt;p&gt;CRAG introduces a quality-control step.&lt;/p&gt;

&lt;h3&gt;
  
  
  How CRAG works
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;      User Question
           ↓
   Retrieve Documents
           ↓
Evaluate Retrieved Documents
           ↓
   ┌───────┴───────┐
 GOOD              BAD
   ↓                ↓
Use Docs     Correct Retrieval
                    ↓
             Refine / Re-query
                    ↓
              Retrieve Again
                    ↓
               Final Context
                    ↓
                   LLM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The retrieved documents are evaluated before they are trusted.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does the evaluator check?
&lt;/h3&gt;

&lt;p&gt;Potential criteria include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Relevance&lt;/li&gt;
&lt;li&gt;Completeness&lt;/li&gt;
&lt;li&gt;Consistency&lt;/li&gt;
&lt;li&gt;Whether the documents actually support the question&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the documents are good enough, they can be passed to the LLM.&lt;/p&gt;

&lt;p&gt;If they are poor, the system can attempt corrective actions.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Refine the query&lt;/li&gt;
&lt;li&gt;Try another search&lt;/li&gt;
&lt;li&gt;Expand the query&lt;/li&gt;
&lt;li&gt;Rerank the results&lt;/li&gt;
&lt;li&gt;Filter noisy chunks&lt;/li&gt;
&lt;li&gt;Retrieve from another source&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;Suppose the user asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which database is a good choice for high-volume event analytics?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The retriever returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;1. Introduction to relational databases
2. Key-value cache configuration
3. Columnar database architecture &lt;span class="k"&gt;for &lt;/span&gt;analytics
4. Basic SQL CRUD operations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The evaluator can determine that only some of these documents directly address the question.&lt;/p&gt;

&lt;p&gt;The system can then remove weak results and perform additional retrieval if necessary.&lt;/p&gt;

&lt;p&gt;The goal is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Retrieve
   ↓
Check
   ↓
Correct
   ↓
Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

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

&lt;ul&gt;
&lt;li&gt;Reduce confident wrong answers&lt;/li&gt;
&lt;li&gt;Improve retrieval quality&lt;/li&gt;
&lt;li&gt;Reduce hallucinations&lt;/li&gt;
&lt;li&gt;Handle difficult queries&lt;/li&gt;
&lt;li&gt;Filter noisy retrieval results&lt;/li&gt;
&lt;li&gt;Improve the quality of final context&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When CRAG helps most
&lt;/h3&gt;

&lt;p&gt;CRAG is particularly useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complex multi-hop questions&lt;/li&gt;
&lt;li&gt;Ambiguous queries&lt;/li&gt;
&lt;li&gt;Long-tail questions&lt;/li&gt;
&lt;li&gt;Low-quality retrieval systems&lt;/li&gt;
&lt;li&gt;Domain-specific technical search&lt;/li&gt;
&lt;li&gt;Enterprise knowledge systems&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  CRAG vs Normal RAG
&lt;/h3&gt;

&lt;p&gt;Normal RAG:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Retrieve → Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CRAG:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Retrieve → Evaluate → Correct → Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fundamental difference is that CRAG does not blindly trust the retriever.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key takeaway
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;CRAG verifies the retrieved context before allowing the model to rely on it.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Putting the Techniques Together
&lt;/h2&gt;

&lt;p&gt;These techniques do not need to be used independently.&lt;/p&gt;

&lt;p&gt;A production RAG system can combine several of them.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;                    User Query
                        │
                        ▼
                 Self-RAG Decision
                  /            &lt;span class="se"&gt;\&lt;/span&gt;
                 NO             YES
                 │               │
                 ▼               ▼
             Direct Answer   Multi-Query
                                 │
                                 ▼
                           Hybrid Search
                           Vector + BM25
                                 │
                                 ▼
                             Retrieval
                                 │
                                 ▼
                              Reranking
                                 │
                                 ▼
                          CRAG Evaluation
                          /             &lt;span class="se"&gt;\&lt;/span&gt;
                       GOOD              BAD
                        │                 │
                        │         Re-query/Correct
                        │                 │
                        └───────┬─────────┘
                                ▼
                      Parent Document Retrieval
                                │
                                ▼
                       Context Compression
                                │
                                ▼
                               LLM
                                │
                                ▼
                           Final Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not every application needs every component.&lt;/p&gt;

&lt;p&gt;The correct architecture depends on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Query complexity&lt;/li&gt;
&lt;li&gt;Document structure&lt;/li&gt;
&lt;li&gt;Retrieval quality&lt;/li&gt;
&lt;li&gt;Latency requirements&lt;/li&gt;
&lt;li&gt;Cost constraints&lt;/li&gt;
&lt;li&gt;Accuracy requirements&lt;/li&gt;
&lt;li&gt;Whether the information changes frequently&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  A Practical Mental Model
&lt;/h2&gt;

&lt;p&gt;Each technique solves a different failure mode.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Technique&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Correct chunk is retrieved but ranked too low&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Reranking&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exact keywords and semantic meaning both matter&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Hybrid Search&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Documents are difficult to split correctly&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Better Chunking&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One query misses relevant terminology&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Multi-Query Retrieval&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retrieved chunk lacks surrounding context&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Parent Document Retrieval&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Too many retrieved chunks overwhelm the model&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Context Compression&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query is vague or lacks useful search terms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;HyDE&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retrieval isn't necessary for every question&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Self-RAG&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retriever returns poor or misleading documents&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;CRAG&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  A Strong Production RAG Pipeline
&lt;/h2&gt;

&lt;p&gt;A practical system might start with something relatively simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Documents
   ↓
Structure-Aware Chunking
   ↓
Embeddings + Keyword Index
   ↓
Hybrid Search
   ↓
Reranking
   ↓
Parent Context
   ↓
Context Compression
   ↓
LLM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add more advanced techniques only where measurements show they are needed.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Self-RAG
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;can reduce unnecessary retrieval.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Multi-Query Retrieval
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;can improve recall for difficult questions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;HyDE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;can help with vague queries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;CRAG
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;can add a validation and correction loop.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Picture
&lt;/h2&gt;

&lt;p&gt;The biggest mistake when building RAG systems is treating retrieval as a single operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Query → Vector DB → LLM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Real-world retrieval is closer to a pipeline of decisions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Should I retrieve?
        ↓
What should I search &lt;span class="k"&gt;for&lt;/span&gt;?
        ↓
Where should I search?
        ↓
How should I &lt;span class="nb"&gt;split &lt;/span&gt;the documents?
        ↓
Which results are actually relevant?
        ↓
Which results should be ranked highest?
        ↓
How much context should I provide?
        ↓
Is the retrieved context trustworthy?
        ↓
Can the LLM answer from this context?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The quality of the final answer is often determined &lt;strong&gt;before the LLM generates a single token&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Better retrieval → Better context → Better answers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And the goal isn't to build the most complicated RAG pipeline.&lt;/p&gt;

&lt;p&gt;The goal is to build the &lt;strong&gt;simplest retrieval architecture that reliably provides the right context for your workload&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>llm</category>
      <category>agents</category>
    </item>
    <item>
      <title>Engineering Reliable AI Document Scanning: Prompts and Schemas</title>
      <dc:creator>Bibek</dc:creator>
      <pubDate>Sat, 22 Aug 2026 19:32:16 +0000</pubDate>
      <link>https://dev.to/bibekkakati/engineering-reliable-ai-document-scanning-prompts-and-schemas-16a6</link>
      <guid>https://dev.to/bibekkakati/engineering-reliable-ai-document-scanning-prompts-and-schemas-16a6</guid>
      <description>&lt;p&gt;Managing short-term rentals and homestays usually involves a chaotic mix of spreadsheets, WhatsApp messages, and scattered paper receipts. &lt;strong&gt;&lt;a href="https://github.com/bibekkakati/propio.ai" rel="noopener noreferrer"&gt;Propio&lt;/a&gt;&lt;/strong&gt; was built to replace that chaos with a purpose-built financial tracking platform.&lt;/p&gt;

&lt;p&gt;One of the most powerful features in Propio is &lt;strong&gt;Smart Scan&lt;/strong&gt; — an AI-powered OCR system that allows property managers to drop a receipt, invoice, or booking confirmation into the app and have all the relevant financial fields extracted and categorized automatically.&lt;/p&gt;

&lt;p&gt;But building an AI that reads documents is easy; building one that extracts data &lt;em&gt;reliably enough for financial records&lt;/em&gt; is incredibly difficult. If your AI hallucinates a tax amount or miscategorizes an expense, you haven't saved the user time—you've created a data integrity nightmare.&lt;/p&gt;

&lt;p&gt;Here is a deep dive into how Propio's document scanning architecture works, focusing on the critical importance of system prompts, output structuring, and fallback mechanisms.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Asynchronous Pipeline
&lt;/h2&gt;

&lt;p&gt;Document processing is slow. Relying on a synchronous HTTP request to wait for an LLM to parse a multi-page PDF is a recipe for browser timeouts and frozen UIs.&lt;/p&gt;

&lt;p&gt;Propio handles this asynchronously:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Stream to Storage&lt;/strong&gt;: The user uploads a file, which is streamed directly to Cloudflare R2.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task Creation&lt;/strong&gt;: An &lt;code&gt;AgentTask&lt;/code&gt; is created in MongoDB with a &lt;code&gt;PENDING&lt;/code&gt; status, and the Task ID is returned to the client immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Background Processing&lt;/strong&gt;: The server kicks off the OCR processing in the background (&lt;code&gt;asyncOcrAgentProcess&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client Polling&lt;/strong&gt;: The frontend polls the Task ID. The user sees a real-time progress stepper. Once the status hits &lt;code&gt;COMPLETED&lt;/code&gt;, the extracted data pre-fills the expense or booking form for a quick human review.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This "fire-and-forget with polling" approach ensures the UI remains snappy regardless of how long the AI takes to "think."&lt;/p&gt;

&lt;h2&gt;
  
  
  Taming the AI: Schemas Over Free-Text
&lt;/h2&gt;

&lt;p&gt;The biggest mistake when using LLMs for data extraction is asking for free-text or loosely formatted JSON. LLMs are eager to please and will often include conversational filler (e.g., &lt;em&gt;"Here is the extracted data:"&lt;/em&gt;), which breaks standard JSON parsers.&lt;/p&gt;

&lt;p&gt;Propio enforces strict structured outputs at the API level using the &lt;code&gt;@google/genai&lt;/code&gt; SDK's schema definition.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;responseMimeType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;responseSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OBJECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;recordDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This is receipt/invoice/billing date&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="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExpenseCategories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// e.g., ["Electricity", "Water", "Maintenance"...]&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NUMBER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;paymentMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExpensePaymentOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;vendorName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;nullable&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="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;systemInstruction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;expenseParsingSystemInstruction&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;By enforcing &lt;code&gt;responseMimeType: "application/json"&lt;/code&gt; and providing a strict OpenAPI-style schema, we guarantee that the output will be parseable JSON matching our exact database requirements. We even pass our application's ENUMs (&lt;code&gt;ExpenseCategories&lt;/code&gt;) directly into the schema to ensure the AI categorizes the expense into a bucket our frontend actually supports.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Art of the System Prompt
&lt;/h2&gt;

&lt;p&gt;Even with a forced JSON schema, the AI needs strict behavioral boundaries. Propio's &lt;code&gt;expenseParsingSystemInstruction&lt;/code&gt; acts as a rigid set of rules designed to prevent hallucination and enforce normalization.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The "Do Not Guess" Rule
&lt;/h3&gt;

&lt;p&gt;Financial data must be exact. The prompt explicitly states:&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="s2"&gt;"Extract only data that is explicitly visible in the document. Never guess, infer, or fabricate values. If a field is missing or unclear, return null for that field."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Normalization Rules
&lt;/h3&gt;

&lt;p&gt;Raw OCR data is messy. Dates come in various formats (MM/DD/YY, DD-MMM-YYYY), and amounts often include currency symbols or commas. We instruct the model to normalize this on the fly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;recordDate&lt;/code&gt; → &lt;code&gt;YYYY-MM-DD&lt;/code&gt; format.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;amount&lt;/code&gt; → numeric value only (remove currency symbols, commas, text).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Graceful Rejection
&lt;/h3&gt;

&lt;p&gt;What happens if a user uploads a photo of their cat instead of a receipt? The agent needs an escape hatch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;FAILURE CONDITIONS: If the file is corrupted, blank, unsupported, not readable, or not a financial document, &lt;span class="k"&gt;return &lt;/span&gt;only: &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'error'&lt;/span&gt;: &lt;span class="s1"&gt;'Seems like file is not a valid document'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because our schema includes a nullable &lt;code&gt;error&lt;/code&gt; string, the AI can legally fulfill the JSON requirement while still rejecting the document.&lt;/p&gt;

&lt;h2&gt;
  
  
  High Availability: The Multi-Model Cascade
&lt;/h2&gt;

&lt;p&gt;AI APIs go down. They get rate-limited. Models get overloaded. If your feature relies on a single model endpoint, your feature &lt;em&gt;will&lt;/em&gt; break.&lt;/p&gt;

&lt;p&gt;To ensure near-zero downtime for the Smart Scan feature, Propio implements a multi-model cascade with exponential backoff.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Models&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gemma-4-31b-it&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="s2"&gt;gemini-2.5-flash-lite&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;generateContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;)&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;delayMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maxRetryPerModel&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="k"&gt;for &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;model&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for &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;attempt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;maxRetryPerModel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;attempt&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;try&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateContent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                    &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="nx"&gt;contents&lt;/span&gt;&lt;span class="p"&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// If it's a 429 Rate Limit, break and try the next model immediately&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;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;ApiError&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="c1"&gt;// Otherwise, wait with exponential backoff and retry this model&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;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;maxRetryPerModel&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;waitTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;delayMs&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;waitTime&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;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Model API call error. All models failed.&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This wrapper iterates through an array of preferred models. If the primary model fails due to a standard error, it retries with exponential backoff. Crucially, if it receives a &lt;code&gt;429 Too Many Requests&lt;/code&gt; error, it immediately aborts retrying the current model and seamlessly cascades to the next fallback model. The user rarely notices a delay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building reliable AI features isn't just about sending a prompt to an endpoint. It requires treating the AI as an unreliable function that needs strict guardrails.&lt;/p&gt;

&lt;p&gt;By combining &lt;strong&gt;asynchronous processing&lt;/strong&gt; for UX, &lt;strong&gt;strict JSON schemas&lt;/strong&gt; for structural integrity, &lt;strong&gt;rigid system instructions&lt;/strong&gt; for data accuracy, and &lt;strong&gt;multi-model cascading&lt;/strong&gt; for resilience, Propio turns AI document scanning from a novelty into a dependable tool for property managers.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>ocr</category>
      <category>gemini</category>
    </item>
    <item>
      <title>Building a Multi-Agent AI Pipeline with Mastra and TypeScript</title>
      <dc:creator>Bibek</dc:creator>
      <pubDate>Sat, 22 Aug 2026 19:28:33 +0000</pubDate>
      <link>https://dev.to/bibekkakati/building-a-multi-agent-ai-pipeline-with-mastra-and-typescript-1fjk</link>
      <guid>https://dev.to/bibekkakati/building-a-multi-agent-ai-pipeline-with-mastra-and-typescript-1fjk</guid>
      <description>&lt;p&gt;Building an AI feature is easy. Building a reliable multi-agent pipeline that coordinates four specialized AI agents, persists intermediate state, skips already-completed work on retries, and keeps the API responsive while the models think — that is the hard part.&lt;/p&gt;

&lt;p&gt;This post walks through the architecture behind &lt;strong&gt;&lt;a href="https://github.com/bibekkakati/clause.ai" rel="noopener noreferrer"&gt;Clause AI&lt;/a&gt;&lt;/strong&gt;, a platform that analyzes rental and lease agreements. It extracts key terms, flags risky clauses, and lets users chat with their contracts using RAG (Retrieval-Augmented Generation) — all powered by a coordinated pipeline of specialized AI agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with "Just Call an LLM"
&lt;/h2&gt;

&lt;p&gt;The naive approach to building an AI-powered document analysis tool would be a single function that calls an LLM, parses the output, and saves it to a database. It works until it doesn't.&lt;/p&gt;

&lt;p&gt;The moment you introduce multiple steps — parsing, summarizing, embedding, risk analysis — things break:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A worker crashes mid-pipeline, and you re-run everything from scratch.&lt;/li&gt;
&lt;li&gt;You burn API quota re-processing steps that already succeeded.&lt;/li&gt;
&lt;li&gt;Partial writes leave the database in an inconsistent state.&lt;/li&gt;
&lt;li&gt;Multiple uploads compete for rate-limited model endpoints.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clause AI was designed from the start to handle these failure modes, not as an afterthought.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent Design: Four Specialists, One Pipeline
&lt;/h2&gt;

&lt;p&gt;Rather than one monolithic prompt that tries to do everything, the system uses four purpose-built agents — each with a focused responsibility, tuned model parameters, and a structured output schema.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;th&gt;Model Settings&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Parser Agent&lt;/td&gt;
&lt;td&gt;Extracts entities, dates, parties, payments, and clause-level structure&lt;/td&gt;
&lt;td&gt;Low reasoning, temp 0.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Summary Agent&lt;/td&gt;
&lt;td&gt;Converts legal jargon into plain-English bullet points&lt;/td&gt;
&lt;td&gt;Low reasoning, temp 0.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Risk Agent&lt;/td&gt;
&lt;td&gt;Flags risky or unfair clauses with severity scoring&lt;/td&gt;
&lt;td&gt;Medium reasoning, temp 0.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query Agent&lt;/td&gt;
&lt;td&gt;Answers user questions via RAG with tool use&lt;/td&gt;
&lt;td&gt;Medium reasoning, temp 0.7&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each agent is configured with distinct reasoning levels and temperatures. The Parser Agent runs at a low temperature (0.2) because extraction requires precision — you want deterministic, faithful reproduction of what the document says. The Query Agent runs warmer (0.7) because conversational responses benefit from more natural phrasing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structured Output with Zod Schemas
&lt;/h3&gt;

&lt;p&gt;Every agent produces validated, structured output using Zod schemas. The Parser Agent, for example, returns a typed object with nullable fields — if information is missing from the document, the agent returns &lt;code&gt;null&lt;/code&gt; rather than hallucinating data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ResponseSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;nullable&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AGREEMENT_TYPES&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;nullable&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;effectiveDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;nullable&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="na"&gt;expiryDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;nullable&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="na"&gt;autoRenewal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;nullable&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="na"&gt;governingLaw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;nullable&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;span class="nf"&gt;nullable&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;parties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AGREEMENT_PARTY_ROLES&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;nullable&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;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nullable&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;sections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SECTION_CLAUSE_TYPES&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="na"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&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;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nullable&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;nullable&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;This schema-first approach means downstream agents and database writes can trust the shape of the data they receive. No defensive parsing, no "hope the LLM returned the right format" — it either validates or it fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Orchestration with Mastra Workflows
&lt;/h2&gt;

&lt;p&gt;The orchestration layer is where the architecture earns its complexity budget. The project uses &lt;strong&gt;&lt;a href="https://mastra.ai" rel="noopener noreferrer"&gt;Mastra&lt;/a&gt;&lt;/strong&gt; — a TypeScript-native agent orchestration framework — to define workflows as composable, sequential pipelines with branching, iteration, and shared state.&lt;/p&gt;

&lt;p&gt;Here is the main workflow definition, stripped to its essence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;agentWorkflow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createWorkflow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;agent-workflow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;outputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="na"&gt;stateSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WorkflowStateSchema&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;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initiateStateHydration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;skipParserAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parsingWorkflow&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;skipSummaryAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;summaryWorkflow&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;embeddingWorkflow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;skipRiskAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;riskWorkflow&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finishStep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;.then()&lt;/code&gt; calls chain steps sequentially. The &lt;code&gt;.branch()&lt;/code&gt; calls conditionally execute sub-workflows based on runtime state. This is where fault tolerance comes in — but more on that in the next section.&lt;/p&gt;

&lt;p&gt;Each sub-workflow itself is a two-step pattern: &lt;strong&gt;LLM call → DB persistence&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;summaryWorkflow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createWorkflow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;summary-workflow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;outputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;stateSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WorkflowStateSchema&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;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;summaryAgentStep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// LLM call: generate summary&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storeSummaryStep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// DB call: persist to Postgres&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This separation is deliberate. The LLM step writes only to workflow state — an in-memory, transient object. The DB step is a separate, retryable operation. If the DB write fails, the LLM result isn't lost; it lives in state and can be retried without re-running the expensive model call.&lt;/p&gt;

&lt;h2&gt;
  
  
  State Hydration: The Key to Fault Tolerance
&lt;/h2&gt;

&lt;p&gt;The most critical design pattern in the entire system is &lt;strong&gt;state hydration&lt;/strong&gt; — the first step of every pipeline run.&lt;/p&gt;

&lt;p&gt;Before any agent executes, the workflow reads the current state of the agreement from the database. If a previous run already completed the parsing step (title, type, parties, and sections exist in the DB), the hydration step sets &lt;code&gt;skipParserAgent: true&lt;/code&gt; in the workflow state. The main workflow's &lt;code&gt;.branch()&lt;/code&gt; sees this flag and skips the parsing sub-workflow entirely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hydrateWorkflowState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;agreementId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&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;agreement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AgreementsService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchAgreement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;agreementId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;userId&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dbSections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dbRisks&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="nx"&gt;AgreementsService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchSectionsByAgreement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;agreementId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nx"&gt;AgreementsService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchRisksByAgreement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;agreementId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;agreement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;sections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dbSections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="nx"&gt;dbSections&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;risks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dbRisks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="nx"&gt;dbRisks&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;risks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;// Skip flags based on what already exists&lt;/span&gt;
        &lt;span class="na"&gt;skipParserAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;agreement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="nx"&gt;agreement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="nx"&gt;agreement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parties&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="nx"&gt;dbSections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="na"&gt;skipSummaryAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;agreement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;skipRiskAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dbRisks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Crash recovery is free.&lt;/strong&gt; If the worker dies after parsing but before summarization, the retry picks up exactly where it left off.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No wasted API calls.&lt;/strong&gt; Already-completed LLM steps are not re-run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotent by design.&lt;/strong&gt; Running the workflow twice on the same agreement produces the same result without side effects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is also a &lt;code&gt;forceRestart&lt;/code&gt; flag that bypasses hydration entirely, useful when the user explicitly wants to re-process a document from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Fan-Out: Embeddings and Risk Analysis
&lt;/h2&gt;

&lt;p&gt;Not every step in the pipeline is a simple A→B chain. The embedding and risk workflows use Mastra's &lt;code&gt;.foreach()&lt;/code&gt; primitive to fan out work across multiple items.&lt;/p&gt;

&lt;h3&gt;
  
  
  Embedding Workflow
&lt;/h3&gt;

&lt;p&gt;After parsing, each section needs a vector embedding for semantic search. The embedding workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Prepares&lt;/strong&gt; a list of sections that don't yet have embeddings (idempotent — already-embedded sections are skipped).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fans out&lt;/strong&gt; with &lt;code&gt;.foreach()&lt;/code&gt;, running each section through a per-section sub-workflow.&lt;/li&gt;
&lt;li&gt;Each sub-workflow generates the embedding, then persists it to the database.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;embeddingWorkflow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createWorkflow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;embedding-workflow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;outputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;stateSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WorkflowStateSchema&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;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prepareEmbeddingSectionsStep&lt;/span&gt;&lt;span class="p"&gt;)&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;embeddingPerSectionWorkflow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Risk Workflow
&lt;/h3&gt;

&lt;p&gt;The risk workflow follows a similar fan-out pattern, but with a twist: sections are grouped by clause type before analysis. Instead of analyzing 15+ individual sections, the system groups them into logical categories (Rent, Termination, Maintenance, etc.) and analyzes each group in a single LLM call. This reduces the number of API calls while keeping each prompt focused.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;riskWorkflow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createWorkflow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;risk-workflow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;outputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;stateSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WorkflowStateSchema&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;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prepareRiskSectionsStep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Group sections by type&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;riskAnalyzeStep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Analyze each group&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storeRiskResultStep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Persist all results&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The risk scoring itself is intentionally conservative. The Risk Agent's system prompt explicitly states that "absence of risk is a valid and expected outcome" and sets a high bar: only flag issues that are "risky enough to mention in a legal memo." Each identified risk gets a numeric score (0–100) that maps to severity levels.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Score Range&lt;/th&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0–40&lt;/td&gt;
&lt;td&gt;LOW&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;41–60&lt;/td&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;61–80&lt;/td&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;81–100&lt;/td&gt;
&lt;td&gt;CRITICAL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The RAG Q&amp;amp;A Flow: Query Agent with Tool Use
&lt;/h2&gt;

&lt;p&gt;Once the processing pipeline completes, the agreement is ready for interactive Q&amp;amp;A. The Query Agent is architecturally different from the other three — it runs on-demand per user question rather than as part of the batch pipeline, and it uses &lt;strong&gt;tool calling&lt;/strong&gt; to decide what information it needs.&lt;/p&gt;

&lt;p&gt;The agent has access to two tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;fetchSectionsTool&lt;/code&gt;&lt;/strong&gt; — Generates a query embedding, runs vector similarity search against the agreement's sections in pgvector, and returns the most relevant sections within a token budget.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;fetchRisksTool&lt;/code&gt;&lt;/strong&gt; — Returns pre-identified risks from the database (no embedding step needed).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The critical design choice here is that the agent decides whether to use tools at all. For simple questions that can be answered from the agreement's metadata (already injected into the system prompt) or from conversation history, no tool call is made. This keeps simple queries fast.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Token-budgeted retrieval instead of fixed top-K&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectedSections&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="k"&gt;for &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;s&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;sections&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;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;estimateTokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;estimateTokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;heading&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;tokens&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;usedTokens&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;maxTokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;usedTokens&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;selectedSections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;section&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;similarity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;similarity&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;p&gt;The sections tool uses &lt;strong&gt;token-budgeted retrieval&lt;/strong&gt; rather than a fixed top-K count. Since the Query Agent already carries conversation history and agreement metadata in its context window, blindly returning 10 sections could overflow the context and degrade response quality. Instead, sections are added until a token cap is reached, regardless of how many or how few that turns out to be.&lt;/p&gt;

&lt;h3&gt;
  
  
  Async Processing with Polling
&lt;/h3&gt;

&lt;p&gt;The Q&amp;amp;A flow is fully asynchronous. When a user sends a question:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The message is saved and a query ID is returned immediately.&lt;/li&gt;
&lt;li&gt;The Query Agent processes the question in a background worker.&lt;/li&gt;
&lt;li&gt;The client polls the query ID until the status changes from &lt;strong&gt;Processing&lt;/strong&gt; to &lt;strong&gt;Success&lt;/strong&gt; or &lt;strong&gt;Failed&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This keeps the API responsive even when the model takes several seconds to reason through a complex question.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decoupling with BullMQ
&lt;/h2&gt;

&lt;p&gt;The entire processing pipeline is decoupled from the API layer through &lt;strong&gt;&lt;a href="https://bullmq.io" rel="noopener noreferrer"&gt;BullMQ&lt;/a&gt;&lt;/strong&gt; (Redis-backed job queues). When a user uploads a document, the API doesn't start AI processing inline — it enqueues a job.&lt;/p&gt;

&lt;p&gt;This solves two problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Rate limit protection.&lt;/strong&gt; If multiple agreements are uploaded simultaneously, the queue absorbs the burst and processes jobs sequentially, avoiding concurrent model calls that would hit API rate limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Process isolation.&lt;/strong&gt; A crash in the AI worker doesn't take down the API server. The job stays in the queue and gets retried.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The message worker handles both file processing jobs and email notification jobs, routing based on job name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;PROCESS_FILE_JOB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;WorkflowService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startAgreementProcessing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;agreementId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;EMAIL_NOTIFICATION_JOB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NotificationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendEmailNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&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;h2&gt;
  
  
  Model Resilience: Fallback and Rate Limit Handling
&lt;/h2&gt;

&lt;p&gt;Every agent is configured with multiple model fallbacks. If the primary model returns a 429 (rate limited), the system marks it as unavailable for the duration specified in the &lt;code&gt;retry-after&lt;/code&gt; header and automatically falls back to the next available model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parserAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;parser-agent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Parser Agent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Instructions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getAvailableModels&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;modelSettings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;reasoning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;low&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.2&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;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means the pipeline doesn't fail because of a temporary rate limit — it gracefully degrades to a different model and continues processing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting It All Together
&lt;/h2&gt;

&lt;p&gt;Here is the full pipeline from upload to interactive Q&amp;amp;A:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Upload&lt;/strong&gt; — User uploads a PDF or DOCX lease agreement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Queue&lt;/strong&gt; — A BullMQ job is enqueued; the API returns immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hydration&lt;/strong&gt; — The worker checks what work has already been done for this agreement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parse&lt;/strong&gt; — The Parser Agent extracts structured data (conditionally skipped).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Summarize&lt;/strong&gt; — The Summary Agent generates plain-English bullet points (conditionally skipped).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embed&lt;/strong&gt; — Each section is converted into a vector embedding (per-section fan-out, skips already-embedded sections).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risk&lt;/strong&gt; — The Risk Agent scores and classifies risky clauses (conditionally skipped, fan-out by clause type).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Finish&lt;/strong&gt; — Status is set to &lt;strong&gt;Success&lt;/strong&gt;; the agreement is ready for Q&amp;amp;A.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chat&lt;/strong&gt; — The Query Agent answers questions using tool-based RAG, grounded strictly in the document.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every step is discrete, retryable, and idempotent. Intermediate state is persisted between steps. The workflow can be interrupted and resumed without losing progress or wasting API calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;Building a multi-agent system isn't about calling multiple LLMs — it's about &lt;strong&gt;orchestrating&lt;/strong&gt; them. The real engineering work is in the scaffolding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Schema-first agent design&lt;/strong&gt; ensures downstream consumers can trust the data shape.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State hydration&lt;/strong&gt; makes crash recovery and retries free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separating LLM calls from DB writes&lt;/strong&gt; means expensive model calls aren't repeated when only the persistence step fails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fan-out with &lt;code&gt;.foreach()&lt;/code&gt;&lt;/strong&gt; handles variable-length work (sections, risk groups) without hardcoding batch sizes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token-budgeted retrieval&lt;/strong&gt; adapts to the available context window rather than using arbitrary limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Job queues&lt;/strong&gt; decouple compute-intensive AI work from the request-response cycle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The multi-agent approach isn't just an architectural choice — it's a reliability strategy. Each agent has a focused responsibility, a clear contract, and a failure boundary that doesn't contaminate the rest of the pipeline.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>mastra</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Simplify Phone Screening with Twilio and AI Automation</title>
      <dc:creator>Bibek</dc:creator>
      <pubDate>Sun, 23 Jun 2024 22:52:58 +0000</pubDate>
      <link>https://dev.to/bibekkakati/simplify-phone-screening-with-twilio-and-ai-automation-3e8e</link>
      <guid>https://dev.to/bibekkakati/simplify-phone-screening-with-twilio-and-ai-automation-3e8e</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/twilio"&gt;Twilio Challenge &lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I explored several ideas for this challenge and did some research. Then, I found a LinkedIn post about how recruiters handle phone interviews for screening and the problems they face, like coordinating schedules between recruiters and candidates. Often, these calls are unplanned for the candidates, causing nervousness and a poor first impression. This inspired me to create a product that &lt;strong&gt;automates the process using IVR to conduct phone interviews for screening&lt;/strong&gt;. The product would evaluate the call recordings and provide a summary of the entire conversation to the recruiter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flow of the system:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The recruiter will enter the candidate's details into the system through a form.&lt;/li&gt;
&lt;li&gt;The candidate will receive an SMS notification with a link included in the message.&lt;/li&gt;
&lt;li&gt;When the candidate clicks the link, the system will automatically dial their phone number.&lt;/li&gt;
&lt;li&gt;An IVR call will guide the candidate through the interview and ask the necessary questions.&lt;/li&gt;
&lt;li&gt;The candidate's responses will be recorded and transcribed by the system. AI will then use the transcription to provide context for the call recording.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Future Scopes/Improvements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Develop a comprehensive multi-tenant dashboard for recruiters to manage records efficiently.&lt;/li&gt;
&lt;li&gt;Integrate the system with job boards for seamless operation.&lt;/li&gt;
&lt;li&gt;Implement an AI model to evaluate candidates' responses and rank them based on job requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Walkthrough video&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/ooiqpuqpMow"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo application link&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application URL is &lt;a href="https://ai-interview-call-8568-dev.twil.io/add-candidate.html" rel="noopener noreferrer"&gt;https://ai-interview-call-8568-dev.twil.io/add-candidate.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;IVR call might not work for you as it is a demo account and only verified phone numbers are allowed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Github link&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/bibekkakati/ai-interview-call" rel="noopener noreferrer"&gt;https://github.com/bibekkakati/ai-interview-call&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Twilio and AI
&lt;/h2&gt;

&lt;p&gt;Let's discuss how I used Twilio and AI in the project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Twilio Verify&lt;/strong&gt; is used to validate the candidate's phone number and provide an internationally formatted result.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Twilio Programmable Messaging&lt;/strong&gt; is used to send an SMS to the candidate with the interview call link.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Twilio Voice&lt;/strong&gt; is used to make a call to the candidate, gather information, and record the candidate's responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Twilio Voice Intelligence&lt;/strong&gt; is used to transcribe the call recordings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemini AI&lt;/strong&gt; is used to extract key points from the candidate's responses (transcriptions).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Twilio Serverless&lt;/strong&gt; functions are used to deploy the functions and assets (a form to capture candidate details).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Additional Prize Categories
&lt;/h2&gt;

&lt;p&gt;My submission qualifies for the following additional prize categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Twilio Times Two&lt;/strong&gt;: Multiple Twilio features are used in the project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Impactful Innovators&lt;/strong&gt;: This product will greatly help recruiters and companies manage their time and resources better.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>twiliochallenge</category>
      <category>ai</category>
      <category>twilio</category>
    </item>
    <item>
      <title>How to Build a Classic Snake Game Using React.js</title>
      <dc:creator>Bibek</dc:creator>
      <pubDate>Tue, 04 Jun 2024 10:41:45 +0000</pubDate>
      <link>https://dev.to/bibekkakati/how-to-build-a-classic-snake-game-using-reactjs-5dn8</link>
      <guid>https://dev.to/bibekkakati/how-to-build-a-classic-snake-game-using-reactjs-5dn8</guid>
      <description>&lt;p&gt;Hello folks! Welcome to this tutorial on developing the classic Snake game using ReactJS.&lt;/p&gt;

&lt;p&gt;I've been working with technology for over six years now, but I've never tried building a game that many of us loved during our childhood. So, this weekend, I decided to create this classic Snake game using web technologies, specifically ReactJS.&lt;/p&gt;

&lt;p&gt;Before proceeding further, let me clarify what we are building. As we know, there are various versions of the Snake game available on the internet. What we are building is a game board where the snake will move at a constant speed in the user-selected direction. When it consumes a food ball, its length will increase, and a point will be scored. If the snake's head touches the wall boundary or any part of its own body, the game is over.&lt;/p&gt;

&lt;p&gt;Github: &lt;a href="https://github.com/bibekkakati/snake-game-web" rel="noopener noreferrer"&gt;https://github.com/bibekkakati/snake-game-web&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Demo: &lt;a href="https://snake-ball.netlify.app" rel="noopener noreferrer"&gt;https://snake-ball.netlify.app&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Game Design
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Components in the game
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Snake&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Food Ball&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Game Board&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Boundary Walls&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Approach
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The game board is a 2D matrix with multiple rows and columns.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The intersection of rows and columns forms a cell.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A cell can be identified by its row number and column number.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The snake's body parts will be represented by these cell numbers on the board.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When the snake moves, the cell number (i.e., row and column number) will be updated for the body part cell based on the direction. For example, if the snake is moving to the right, the cell's column number will be incremented by 1.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Before rendering the snake's position after each movement, we also need to perform these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check if this movement results in any collision with the boundary wall or its own body. If there is a collision, stop the game and show "game over"; otherwise, continue.&lt;/li&gt;
&lt;li&gt;Check if the snake's head cell number is the same as the food ball's cell number. If they match, update the score and place a new food ball on the board.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;We are writing all the logic and UI code in a single file, &lt;code&gt;App.jsx&lt;/code&gt;, and using &lt;code&gt;index.css&lt;/code&gt; for the styling. In this implementation, we will not be discussing the styling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Constants
&lt;/h3&gt;

&lt;p&gt;First, we will declare the constants before the component function definition.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;COLs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Number of columns on board&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ROWs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Number of rows on board&lt;/span&gt;

&lt;span class="c1"&gt;// Default length of snake i.e, it will consume 10 cell by default&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_LENGTH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Declaring directions as symbol for equality checks&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;up&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;DOWN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;down&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;RIGHT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;right&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;LEFT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&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;h3&gt;
  
  
  State and Reference
&lt;/h3&gt;

&lt;p&gt;Declare the reference and state variables.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&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;grid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ROWs&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;COLs&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;snakeCoordinates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&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;direction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;RIGHT&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;snakeCoordinatesMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&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;foodCoords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;col&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPoints&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;gameOver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setGameOver&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isPlaying&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPlaying&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;timer&lt;/code&gt; variable stores the instance of &lt;code&gt;setInterval&lt;/code&gt; that we use to automate the snake's movement. This instance will be used to clear the interval when the game is over.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;grid&lt;/code&gt; variable stores the empty 2D array used to render the game board.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;snakeCoordinates&lt;/code&gt; variable stores the indexes of the snake's body parts, i.e., cell numbers. The &lt;code&gt;0th&lt;/code&gt; index value is the snake's tail, and the last value is the snake's head.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The value of snake coordinates will look like &lt;code&gt;{ row: [Number], col: [Number], isHead: [Boolean] }&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;direction&lt;/code&gt; variable stores the user-selected direction. This value will be the same as the declared constant direction symbols.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;snakeCoordinatesMap&lt;/code&gt; variable stores the set of snake body parts, i.e., cell numbers. This helps in the render method to check which part of the board (grid) we need to render a snake body part on. The variable name includes the word &lt;code&gt;map&lt;/code&gt;, but the value is of type &lt;code&gt;Set&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;foodCoords&lt;/code&gt; variable stores the position of the food ball's cell number.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;points&lt;/code&gt;, &lt;code&gt;gameOver&lt;/code&gt;, and &lt;code&gt;isPlaying&lt;/code&gt; are state variables used to store the score, game over status, and game play status, respectively.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;You might have noticed that &lt;code&gt;isPlaying&lt;/code&gt; is a number, not a boolean. This is due to a specific bypass mechanism we will discuss in the coming sections.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Let's discuss the implementation of snake's body movement along with collision check and food ball consumption.&lt;/p&gt;

&lt;p&gt;We are writing a function &lt;code&gt;moveSnake&lt;/code&gt; to handle the snake movement logic.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;moveSnake&lt;/span&gt; &lt;span class="o"&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="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;gameOver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nf"&gt;setPlaying&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&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;coords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;snakeCoordinates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&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;snakeTail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&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;snakeHead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&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;curr_direction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Check for food ball consumption&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foodConsumed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="nx"&gt;snakeHead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;foodCoords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="nx"&gt;snakeHead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;foodCoords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Update body coords based on direction and its position&lt;/span&gt;
        &lt;span class="nx"&gt;coords&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;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Replace last cell with snake head coords [last is the cell after snake head]&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;idx&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&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="nx"&gt;snakeHead&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
                &lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;isHead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// Replace current cell coords with next cell coords&lt;/span&gt;
            &lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="c1"&gt;// Update snake head coords based on direction&lt;/span&gt;
        &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;curr_direction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;UP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nx"&gt;snakeHead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;DOWN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nx"&gt;snakeHead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;RIGHT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nx"&gt;snakeHead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;LEFT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nx"&gt;snakeHead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// If food ball is consumed, update points and new position of food&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;foodConsumed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setPoints&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;points&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;points&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nf"&gt;populateFoodBall&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// If there is no collision for the movement, continue the game&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;collided&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;collisionCheck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;snakeHead&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;collided&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;stopGame&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Create new coords with new snake head&lt;/span&gt;
        &lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;snakeHead&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;snakeCoordinates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;foodConsumed&lt;/span&gt;
            &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;snakeTail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;syncSnakeCoordinatesMap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Function to create a set from snake body coordinates&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The first check ensures that if the game is over, we don't need to move the snake. It's just an extra precaution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, we derive the current snake coordinates, the snake tail position, and the snake head position.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We then check if the food ball is consumed, meaning the snake head position should match the food ball position.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After that, we iterate over the body parts, excluding the snake head, to determine the new coordinates of the snake body.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The position of each snake body part depends on the position of the next part, as the snake's body parts move in the same path as the head. So, we replace the current body part coordinates with the next body part's coordinates.&lt;/li&gt;
&lt;li&gt;If the body part is the last one, i.e., the neck, it will take the coordinates of the current snake head.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We then update the new snake head position based on the selected direction.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, we check for food consumption and collisions and update the new snake coordinates if there is no collision.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's talk about how we populate the food ball.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;populateFoodBall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&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;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;ROWs&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;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;COLs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nx"&gt;foodCoords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;col&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;p&gt;We generate a random row and column number based on our constants and set them in the reference variable &lt;code&gt;foodCoords&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, let's discuss the collision check function.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;collisionCheck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;snakeHead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Check wall collision&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;snakeHead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;COLs&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
            &lt;span class="nx"&gt;snakeHead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;ROWs&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
            &lt;span class="nx"&gt;snakeHead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
            &lt;span class="nx"&gt;snakeHead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Check body collision&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;coordsKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;snakeHead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;snakeHead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;snakeCoordinatesMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;coordsKey&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&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;p&gt;The function will receive the new snake head coordinates as a parameter.&lt;/p&gt;

&lt;p&gt;First, we check for boundary collisions. If the new snake head's coordinates are greater than the respective constants or less than 0, it means the snake head is going out of range, which is a collision.&lt;/p&gt;

&lt;p&gt;Next, we check for self-collision, meaning the snake head colliding with its own body. We do this by checking if the snake head coordinates are already present in the snake coordinates map.&lt;/p&gt;

&lt;p&gt;Then we have the &lt;code&gt;startGame&lt;/code&gt; and &lt;code&gt;stopGame&lt;/code&gt; functions to control the gameplay.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startGame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&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;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;moveSnake&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;interval&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;stopGame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setGameOver&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="nf"&gt;setPlaying&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&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;timer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&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;p&gt;&lt;code&gt;startGame&lt;/code&gt; triggers a &lt;code&gt;setInterval&lt;/code&gt; with a &lt;code&gt;100ms&lt;/code&gt; interval. After each interval, the &lt;code&gt;moveSnake&lt;/code&gt; method is called.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;stopGame&lt;/code&gt; sets the game over state, updates the gameplay status, and clears the interval instance.&lt;/p&gt;

&lt;p&gt;Then, we have the render method.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getCell&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row_idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;col_idx&lt;/span&gt;&lt;span class="p"&gt;)&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;coords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;row_idx&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;col_idx&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;foodPos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;foodCoords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;foodCoords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;head&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                &lt;span class="nx"&gt;snakeCoordinates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;snakeCoordinates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&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;headPos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;isFood&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;coords&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;foodPos&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;isSnakeBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;snakeCoordinatesMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;coords&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;isHead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headPos&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;coords&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;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cell&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;isFood&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; food&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isSnakeBody&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; body&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isHead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; head&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="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;col_idx&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isPlaying&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app-container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;gameOver&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;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;game-over&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;GAME&lt;/span&gt; &lt;span class="nx"&gt;OVER&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&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;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isPlaying&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;stopGame&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;startGame&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isPlaying&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;STOP&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="s2"&gt;START&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;GAME&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="p"&gt;)}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;board&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;row_idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;row_idx&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;row&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;col_idx&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;getCell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row_idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;col_idx&lt;/span&gt;&lt;span class="p"&gt;))}&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="p"&gt;))}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;score&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;SCORE&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;points&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;getCell&lt;/code&gt; method checks if the cell is empty, part of the snake's body, or food, and updates the CSS class name accordingly.&lt;/p&gt;

&lt;p&gt;We use the &lt;code&gt;useCallback&lt;/code&gt; hook in the &lt;code&gt;getCell&lt;/code&gt; method, with &lt;code&gt;isPlaying&lt;/code&gt; as a dependency. This &lt;code&gt;isPlaying&lt;/code&gt; variable is a number that increases by 1 with each snake movement.&lt;/p&gt;

&lt;p&gt;Here's why we did this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Stale State Issue:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* Initially, many variables were state variables.

* The snake movement logic didn't work well because `setInterval` was calling `moveSnake` but the state values inside `moveSnake` weren't updating properly.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Switch to Reference Variables:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* To fix this, we changed those state variables to reference variables.

* This allowed `moveSnake` to access the latest values.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Re-rendering Problem:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* Reference variables don't trigger re-renders when they change.

* To solve this, we used the `isPlaying` state variable which increments by 1 with each snake movement.

* This increment ensures the `getCell` method has access to the updated reference variable and the component re-renders correctly.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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.amazonaws.com%2Fuploads%2Farticles%2Fnljc22u1rbq12wimgnrd.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%2Fnljc22u1rbq12wimgnrd.png" alt=" " width="800" height="832"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Github: &lt;a href="https://github.com/bibekkakati/snake-game-web" rel="noopener noreferrer"&gt;https://github.com/bibekkakati/snake-game-web&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Demo: &lt;a href="https://snake-ball.netlify.app" rel="noopener noreferrer"&gt;https://snake-ball.netlify.app&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Works best on desktop web.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;I hope this tutorial helps you understand the concept behind implementing a snake game. There are a few alternative approaches as well, but I found this method easier to understand and implement. Please feel free to share your feedback and suggestions.&lt;/p&gt;

&lt;p&gt;Thank you for reading 🙏&lt;/p&gt;

&lt;p&gt;If you enjoyed this article or found it helpful, give it a thumbs-up 👍&lt;/p&gt;

&lt;p&gt;Feel free to connect 👋&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/kakatibibek" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; | &lt;a href="https://instagram.com/bibekkakati" rel="noopener noreferrer"&gt;Instagram&lt;/a&gt; | &lt;a href="https://linkedin.com/in/bibekkakati" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>gamedev</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Navigating React.js SEO Challenges: A Case Study with CoderKit</title>
      <dc:creator>Bibek</dc:creator>
      <pubDate>Sun, 19 Nov 2023 16:19:19 +0000</pubDate>
      <link>https://dev.to/bibekkakati/navigating-reactjs-seo-challenges-a-case-study-with-coderkit-33j6</link>
      <guid>https://dev.to/bibekkakati/navigating-reactjs-seo-challenges-a-case-study-with-coderkit-33j6</guid>
      <description>&lt;h3&gt;
  
  
  Introduction:
&lt;/h3&gt;

&lt;p&gt;Embarking on the journey of launching CoderKit, a React.js application, brought with it the daunting challenge of Search Engine Optimization (SEO). This blog recounts the SEO hurdles faced and the inventive solutions employed to ensure visibility on Google.&lt;/p&gt;

&lt;h3&gt;
  
  
  The SEO Conundrum:
&lt;/h3&gt;

&lt;p&gt;Post-launch, the realization struck that the application wasn't making its way to Google search results. Traditional solutions pointed toward static site generators or frameworks like Next.js, but migrating the project wasn't an option. Delving into SEO implementation nuances and website essentials, initial efforts to update meta descriptions in index.html proved futile.&lt;/p&gt;

&lt;h3&gt;
  
  
  Discovering the Power of Sitemap.xml:
&lt;/h3&gt;

&lt;p&gt;A breakthrough emerged with the revelation of the significance of sitemap.xml. Creating a script to automatically generate this file based on known routes, devoid of dynamic backend-driven URLs, became pivotal. Configuring the Search Console to index these pages marked progress, but a notification soon arrived—indexing failure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Addressing Redirection Woes:
&lt;/h3&gt;

&lt;p&gt;Upon inspection, the issue lay in redirection. React applications default to landing on index.html, hindering search engines from indexing individual pages. An innovative solution materialized: generating HTML pages for each known route during the pre-build phase. These pages mirrored index.html structure but contained distinct meta tags and content pulled from the route config.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making Redirection Seamless:
&lt;/h3&gt;

&lt;p&gt;Concerns about server-level configurations were assuaged by platforms like Netlify, which inherently checked for file name matches with requested URLs. If found, they returned the file; otherwise, they defaulted to redirecting requests to index.html. This seamless redirection is crucial for React applications, ensuring that custom error components function effectively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing and Triumph:
&lt;/h3&gt;

&lt;p&gt;With all configurations updated in the Search Console, the real test began. After a day, a notification arrived—success! All pages were now indexed. However, the ranking was modest due to the application's novelty. A search appended with "coderkit" yielded optimal results, but there was room for improvement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion:
&lt;/h3&gt;

&lt;p&gt;This SEO journey with CoderKit reflects the iterative and adaptive nature of problem-solving in the tech realm. While the current approach has yielded positive results, the ever-evolving landscape of SEO beckons exploration. Feedback and alternative approaches are welcomed. Check out &lt;a href="https://coderkit.dev" rel="noopener noreferrer"&gt;CoderKit&lt;/a&gt; to witness these strategies in action.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Unleash Your Coding Superpowers with CoderKit! 🚀</title>
      <dc:creator>Bibek</dc:creator>
      <pubDate>Fri, 03 Nov 2023 19:34:28 +0000</pubDate>
      <link>https://dev.to/bibekkakati/unleash-your-coding-superpowers-with-coderkit-k9h</link>
      <guid>https://dev.to/bibekkakati/unleash-your-coding-superpowers-with-coderkit-k9h</guid>
      <description>&lt;p&gt;🚀 &lt;strong&gt;The Spark of Inspiration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As a developer, I've been there, facing those repetitive coding tasks day in and day out. That's when the spark ignited. I asked myself, "How can we make this easier?"&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;The Eureka Moment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And just like that, CoderKit was born. I dreamt of a toolbox filled with developer-friendly utilities. A JSON formatter, a text case converter, a code minifier and more – all at your fingertips.&lt;/p&gt;

&lt;p&gt;🛠️ &lt;strong&gt;Building the Arsenal&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The journey was a rollercoaster, crafting tools, and making them work seamlessly. It was just me and my code, hours upon hours. The tools became my coding companions.&lt;/p&gt;

&lt;p&gt;👥 &lt;strong&gt;Inviting You to the Journey&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Today, we're launching CoderKit Beta. It's about time we made your coding life simpler. These tools are designed to make your day-to-day coding tasks a breeze.&lt;/p&gt;

&lt;p&gt;🤝 &lt;strong&gt;Your Feedback, Our Fuel&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CoderKit isn't complete without you. Your feedback, and your insights – they're our guiding stars. This Beta launch is the beginning, and your suggestions will shape the future.&lt;/p&gt;

&lt;p&gt;🔮 &lt;strong&gt;The Future of Coding&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CoderKit is not just about tools; it's about coding with confidence. We're here to empower you – whether you're a pro or just starting.&lt;/p&gt;

&lt;p&gt;🌐 &lt;strong&gt;Join the Journey&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Come, and explore CoderKit Beta with us. Try out the tools, and share your thoughts. Let's make coding a bit more exciting.&lt;/p&gt;

&lt;p&gt;🔧 &lt;strong&gt;Meet the Tools&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;JSON Formatter: Tame unruly JSON data with ease, ensuring readability and error-free code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Text Case Converter: Convert text between various cases (e.g., CamelCase, snake_case) effortlessly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;JavaScript Minifier: Reduce file size and boost website performance by minifying your JavaScript code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;HTML Minifier: Optimize your HTML code for faster loading times and improved user experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CSS Minifier: Streamline your stylesheets to enhance website performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;JavaScript Beautifier: Make your JavaScript code more readable and consistent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;HTML Beautifier: Elevate the aesthetics of your HTML code for better readability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CSS Beautifier: Improve the structure and presentation of your CSS styles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Base64 Encoder/Decoder: Encode and decode data with this versatile utility.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;JWT Decoder: Decode JSON Web Tokens to inspect and verify their content.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lorem Ipsum Generator: Generate placeholder text for content drafting and design prototyping.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;strong&gt;Get Started&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Visit &lt;a href="https://coderkit.dev" rel="noopener noreferrer"&gt;&lt;strong&gt;https://coderkit.dev&lt;/strong&gt;&lt;/a&gt; and see how CoderKit can simplify your coding journey. Welcome to a world where coding just got a whole lot easier.&lt;/p&gt;

&lt;p&gt;Here's to coding adventures with CoderKit! 🎉&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>developer</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>What is Chat GPT</title>
      <dc:creator>Bibek</dc:creator>
      <pubDate>Sat, 07 Jan 2023 15:30:09 +0000</pubDate>
      <link>https://dev.to/bibekkakati/what-is-chat-gpt-3ko6</link>
      <guid>https://dev.to/bibekkakati/what-is-chat-gpt-3ko6</guid>
      <description>&lt;p&gt;GPT, or Generative Pre-training Transformer, is a type of language model developed by OpenAI that has been widely used for various natural language processing tasks. Language models are algorithms that are trained to predict the next word in a sequence of text, based on the words that came before it. GPT takes this a step further by using an attention mechanism, which allows it to consider the entire input context when making predictions.&lt;/p&gt;

&lt;p&gt;One of the main use cases for GPT is text generation. Given a prompt, GPT can generate human-like text that is coherent and flows naturally. This has a wide range of applications, including generating news articles, creating social media posts, and even writing code.&lt;/p&gt;

&lt;p&gt;Another use case for GPT is language translation. By training GPT on a large dataset of parallel text in two different languages, it can learn the relationship between the languages and generate translations that are accurate and fluent.&lt;/p&gt;

&lt;p&gt;GPT can also be used for summarization, by generating a shorter version of a long piece of text that retains the main points and ideas. This can be useful for creating summaries of news articles, research papers, and other lengthy documents.&lt;/p&gt;

&lt;p&gt;One of the most notable use cases for GPT is chatbots. By training GPT on a large dataset of conversation transcripts, it can learn how to carry on a conversation with a user naturally and coherently. Chatbots powered by GPT has been used for customer service, providing information and assistance to users, and even for entertainment.&lt;/p&gt;

&lt;p&gt;Aside from these specific use cases, GPT has also been used for a wide range of other natural language processing tasks, including question answering, text classification, and even creating music.&lt;/p&gt;

&lt;p&gt;Overall, GPT is a powerful and versatile tool for natural language processing, with a wide range of use cases and applications. Its ability to generate human-like text and understand the context of a conversation makes it a valuable asset for a variety of industries and purposes.&lt;/p&gt;

&lt;p&gt;Benefits or advantages of using chat GPT:&lt;/p&gt;

&lt;p&gt;Efficiency: Chatbots powered by GPT can handle a large volume of conversation without getting tired or needing breaks, which can be useful for customer service or other applications where there is a high demand for conversation.&lt;/p&gt;

&lt;p&gt;Personalization: GPT can generate personalized responses based on the input it receives, allowing it to have unique conversations with different users.&lt;/p&gt;

&lt;p&gt;Cost-effectiveness: Using chatbots powered by GPT can be more cost-effective than hiring human employees to handle conversation tasks.&lt;/p&gt;

&lt;p&gt;24/7 availability: Chatbots powered by GPT can be available to chat with users around the clock, which can be convenient for users who need assistance outside of regular business hours.&lt;/p&gt;

&lt;p&gt;Language support: GPT can be trained in multiple languages, allowing it to carry on conversations with users in different languages.&lt;/p&gt;

&lt;p&gt;Drawbacks or disadvantages of using chat GPT:&lt;/p&gt;

&lt;p&gt;Limited understanding of context: While GPT can generate text that flows naturally and considers the input it receives, it is ultimately limited in its understanding of context and may not be able to fully understand the nuances and subtleties of human conversation.&lt;/p&gt;

&lt;p&gt;Lack of empathy: As a machine learning model, GPT cannot feel empathy or understand the emotions of others. This can make it difficult for it to fully engage in empathetic or emotional conversations.&lt;/p&gt;

&lt;p&gt;Limited creativity: GPT is limited by the data it was trained on and the algorithms that power it, which means it may not be able to come up with creative or original responses to certain prompts.&lt;/p&gt;

&lt;p&gt;Lack of accountability: As a machine, GPT cannot take responsibility for its actions or hold itself accountable in the same way a human would. This can be a concern in certain applications, such as customer service.&lt;/p&gt;

&lt;p&gt;Dependence on data quality: The quality of the responses generated by GPT is largely dependent on the quality of the data it was trained on. If the training data is biased or contains errors, the responses generated by GPT may also be biased or inaccurate.&lt;/p&gt;

&lt;p&gt;~ This article was written by Chat GPT.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Originally published on &lt;a href="https://bibekkakati.hashnode.dev/chat-gpt-explained-by-chat-gpt" rel="noopener noreferrer"&gt;bibekkakati.hashnode.dev&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Thank you for reading 🙏&lt;/p&gt;

&lt;p&gt;If you enjoyed this article or found it helpful, give it a thumbs-up 👍&lt;/p&gt;

&lt;p&gt;Feel free to connect 👋&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/kakatibibek" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; | &lt;a href="https://instagram.com/bibekkakati" rel="noopener noreferrer"&gt;Instagram&lt;/a&gt; | &lt;a href="https://linkedin.com/in/bibekkakati" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you like my work and want to support it, you can do it here. I will really appreciate it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/bibekkakati" rel="noopener noreferrer"&gt;&lt;br&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.buymeacoffee.com%2Fbutton-api%2F%3Ftext%3DBuy%2520me%2520a%2520coffee%26emoji%3D%26slug%3Dbibekkakati%26button_colour%3DFF5F5F%26font_colour%3Dffffff%26font_family%3DCookie%26outline_colour%3D000000%26coffee_colour%3DFFDD00" width="235.0" height="50"&gt;&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>productivity</category>
      <category>developer</category>
    </item>
  </channel>
</rss>
