<?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: Darshil Mahraur</title>
    <description>The latest articles on DEV Community by Darshil Mahraur (@darshil89).</description>
    <link>https://dev.to/darshil89</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%2F1455103%2Fc585e407-b918-4b08-9dc2-631ba52de469.jpeg</url>
      <title>DEV Community: Darshil Mahraur</title>
      <link>https://dev.to/darshil89</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/darshil89"/>
    <language>en</language>
    <item>
      <title>Scaling Voice Agents to 10,000+ Calls - Part 2: One Pod, One Call, with Agones</title>
      <dc:creator>Darshil Mahraur</dc:creator>
      <pubDate>Sun, 18 Oct 2026 17:28:12 +0000</pubDate>
      <link>https://dev.to/darshil89/scaling-voice-agents-to-10000-calls-part-2-one-pod-one-call-with-agones-3ldb</link>
      <guid>https://dev.to/darshil89/scaling-voice-agents-to-10000-calls-part-2-one-pod-one-call-with-agones-3ldb</guid>
      <description>&lt;h2&gt;
  
  
  The Game Industry Solved My Problem Years Ago. I Found Out This Year.
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Part 2: how we stopped fighting a multi-tenant Python process and started handing out fresh ones&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where We Left Off
&lt;/h2&gt;

&lt;p&gt;&lt;a href="//./blog-scaling-voice-agents-part-1-problems.md"&gt;Part 1&lt;/a&gt; ended with a table. Three problems, VAD jitter, STT/TTS CPU bursts and a Daily.co native thread leak, and every one of them scaled with the same variable: &lt;strong&gt;how many calls one pod touches.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pod serving several calls:   hundreds of threads, heap at the limit, noisy neighbours, OOMKilled
pod serving one call:        one call's spikes, bounded memory, then it's gone
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"The question that reframed it was simple: what if a pod only ever served one call, like a game server?"&lt;/p&gt;

&lt;p&gt;So I looked at how game servers do it. The answer is &lt;a href="https://agones.dev" rel="noopener noreferrer"&gt;Agones&lt;/a&gt;, a Kubernetes controller from Google and Ubisoft whose whole job is to keep a pool of ready game-server pods, hand exactly one to a match, and make sure nobody kills it mid-game.&lt;/p&gt;

&lt;p&gt;Swap "match" for "call" and read that again. It fits, down to the failure modes.&lt;/p&gt;

&lt;p&gt;This post is the build: the shape, the warm-pool math, the Karpenter settings that will drop a live call if you get them wrong, the two ways a pod leaks out of the pool, and copy-paste configs at the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Shape of It
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqpuk6b4gay8ngt7064i8.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqpuk6b4gay8ngt7064i8.png" alt=" " width="800" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;th&gt;Owns&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Agones Fleet&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;N Ready pods and the &lt;code&gt;Ready → Allocated → Shutdown&lt;/code&gt; state machine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FleetAutoscaler&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;keeps &lt;code&gt;replicas = allocated + bufferSize&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Karpenter NodePool&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;arm64 nodes appear when pods are Pending, vanish when empty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Stark&lt;/strong&gt; (orchestrator)&lt;/td&gt;
&lt;td&gt;allocates a pod, talks to it directly at &lt;code&gt;nodeIP:hostPort&lt;/code&gt;, remembers the address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Jarvis&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Ready()&lt;/code&gt; when warm, &lt;code&gt;Health()&lt;/code&gt; heartbeats, &lt;code&gt;Shutdown()&lt;/code&gt; when the call ends&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Gone: the Istio &lt;code&gt;DestinationRule&lt;/code&gt; from my last post, the Service as the call path, the HPA, the Redis routing map. Affinity stopped being a hash ring and became a stored address. Stark writes down the address it was given and &lt;code&gt;end-call&lt;/code&gt; goes there.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lifecycle Is the Whole Design
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Scheduled ──▶ Ready ──▶ Allocated ──▶ Shutdown
   boot        warm      in a call      deleted, backfilled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two properties make this safe for calls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Allocation is atomic.&lt;/strong&gt; &lt;code&gt;Ready → Allocated&lt;/code&gt; flips once. Agones never hands the same pod to two callers, so "one pod one call" is an invariant, not a convention. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Release is cooperative.&lt;/strong&gt; Only the pod can leave &lt;code&gt;Allocated&lt;/code&gt;, by calling &lt;code&gt;Shutdown()&lt;/code&gt;. Agones never reclaims an Allocated pod for a scale-down or a rollout. A scale-down can never hang up on a user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the jarvis side that's three verbs on the SDK, &lt;code&gt;ready()&lt;/code&gt;, &lt;code&gt;health()&lt;/code&gt; and &lt;code&gt;shutdown()&lt;/code&gt;, plus one rule that took me a while to internalize: &lt;strong&gt;the pod never exits itself.&lt;/strong&gt; It calls &lt;code&gt;Shutdown()&lt;/code&gt;, Agones deletes it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Warm Pool: N Ready Pods, Always
&lt;/h2&gt;

&lt;p&gt;The first question everyone asks is "how many idle pods do you keep?" The intuitive answer, "enough for concurrent calls", is wrong. The Fleet already grows to &lt;code&gt;allocated + N&lt;/code&gt;. Concurrency is handled by growth. The warm pool only has to cover &lt;strong&gt;the calls that arrive while a replacement pod is still booting.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So N is a function of two things: how fast calls arrive, and how long a fresh pod takes to reach Ready. Today N is a fixed number for us, tuned from load tests with headroom on top. Making it follow arrival rate automatically is the next step, and the FleetAutoscaler has a webhook policy for exactly that.&lt;/p&gt;

&lt;p&gt;What this says about cost: &lt;strong&gt;cold start is the cost driver, not traffic.&lt;/strong&gt; Halve the time to Ready and you halve the idle pool. So that is where the effort went:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cold-start item&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;pipecat import&lt;/td&gt;
&lt;td&gt;lazy, on the first call&lt;/td&gt;
&lt;td&gt;eager, at boot, before &lt;code&gt;Ready()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Silero VAD load&lt;/td&gt;
&lt;td&gt;on the start-call path&lt;/td&gt;
&lt;td&gt;loaded at boot, first call adopts it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Daily room + token&lt;/td&gt;
&lt;td&gt;REST round-trip on every start-call&lt;/td&gt;
&lt;td&gt;prewarmed at boot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GC&lt;/td&gt;
&lt;td&gt;everything tracked&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gc.collect(); gc.freeze()&lt;/code&gt; after boot, so per-call collects scan only per-call garbage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node provision&lt;/td&gt;
&lt;td&gt;about a minute on top of pod boot&lt;/td&gt;
&lt;td&gt;still about a minute, which is what the pool is sized for&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In production, picking a pod takes tens of milliseconds at p95. The user doesn't know the pod didn't exist for them a moment ago.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sizing a Pod, and Then a Node
&lt;/h2&gt;

&lt;p&gt;Part 1's lesson was that CPU trouble lives in the spikes, not the average, and spikes from neighbouring calls collide. One pod per call removes the neighbours. What's left is sizing the pod so its own spikes never get throttled:&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="c1"&gt;# Guaranteed QoS: requests == limits, set from one call profiled on its own.&lt;/span&gt;
&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;&amp;lt;one call's burst&amp;gt;&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;&amp;lt;one call's peak working set&amp;gt;&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;   &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;&amp;lt;one call's burst&amp;gt;&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;&amp;lt;one call's peak working set&amp;gt;&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The node shape was a decision, not a default. One call's profile is lopsided: a meaningful slice of CPU for a modest amount of memory, roughly a 1:2 ratio of cores to GiB once the pod is sized Guaranteed. General-purpose instances come at 1:4, so a node packed with jarvis pods runs out of CPU with half its memory still empty, and you pay for RAM nobody uses. Compute-optimized Graviton, the C family, is 1:2. &lt;/p&gt;

&lt;p&gt;Burstable (small request, bigger limit) packs about twice as many pods per node, and puts far more spike demand on the node than it has cores. The extra nodes are the price of never throttling a live call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Karpenter: Four Settings That Will Drop a Live Call
&lt;/h2&gt;

&lt;p&gt;A NodePool is a rule: "if a pod needs capacity like this, you may build a node like this." Nodes appear when pods are Pending and vanish when they empty.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Only remove a node when it is empty.&lt;/strong&gt; Karpenter has two modes for cleaning up nodes. &lt;code&gt;WhenEmptyOrUnderutilized&lt;/code&gt; says: if a node is only half used, move its pods somewhere else and delete it. That works for web servers, because any pod can be replaced by any other. It does not work here. "Moving" a jarvis pod means killing it, and there is a person on the call. So we use &lt;code&gt;WhenEmpty&lt;/code&gt;: Karpenter may delete a node only when nothing is running on it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Fill nodes up before starting new ones.&lt;/strong&gt; Rule 1 has a catch. If Agones hands out calls evenly across all nodes, no node ever becomes empty, so no node is ever removed, and you keep paying for every node you ever created. &lt;code&gt;scheduling: Packed&lt;/code&gt; on the Fleet tells Agones to put new calls on the fullest node first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Tell Karpenter directly: do not touch this pod.&lt;/strong&gt; Agones already marks a pod in a call as "do not evict", but it uses the annotation the old cluster-autoscaler understands. Karpenter ignores that one. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. No spot instances.&lt;/strong&gt; Spot gives about two minutes of warning before AWS takes the machine back. A warm pod turns into a live call in milliseconds, and a call lasts longer than two minutes. There is no pod in this pool that is safe to lose, so every node is on-demand.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Two Ways a Pod Leaks Out of the Pool
&lt;/h2&gt;

&lt;p&gt;"Only the pod can release itself" is a feature right up until the pod doesn't. A missed &lt;code&gt;Shutdown()&lt;/code&gt; is permanent. The GameServer stays &lt;code&gt;Allocated&lt;/code&gt;, still counts toward &lt;code&gt;allocatedReplicas&lt;/code&gt;, and the autoscaler provisions a replacement for it. &lt;/p&gt;

&lt;p&gt;How often does a pod get claimed and then not used? More than you'd guess. Here's one week of prod, about ten thousand calls started versus calls where the user actually reached the room:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyjfjbzpmocobp7k54903.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyjfjbzpmocobp7k54903.png" alt=" " width="799" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The gap has two causes, and we see both every day:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(a) Started, but never joined.&lt;/strong&gt; Stark allocated the pod, start-call landed, the pipeline is up and the Daily room is waiting. The participant never arrives. The idle timeout is what saves it, the pod tears the session down and calls &lt;code&gt;shutdown()&lt;/code&gt; itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(b) Joined, then hung up before the call finished starting.&lt;/strong&gt; The participant comes in and leaves while the pipeline is still being built, so end-call races start-call.&lt;/p&gt;

&lt;p&gt;The alert that catches both: &lt;code&gt;Allocated&lt;/code&gt; count versus Stark's live-call count. A persistent gap is a leaked pod.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Changed
&lt;/h2&gt;

&lt;p&gt;Same production environment, shared pods before, one-call pods after:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Threads per pod&lt;/td&gt;
&lt;td&gt;hundreds&lt;/td&gt;
&lt;td&gt;dozens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Heap per pod&lt;/td&gt;
&lt;td&gt;at the limit, OOMKilled&lt;/td&gt;
&lt;td&gt;bounded, no OOMKills since cutover&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CPU&lt;/td&gt;
&lt;td&gt;spikes colliding across calls&lt;/td&gt;
&lt;td&gt;one call's spikes, Guaranteed QoS, no neighbours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pod affinity&lt;/td&gt;
&lt;td&gt;Istio hash ring, reshuffles on scale&lt;/td&gt;
&lt;td&gt;the address Agones returned&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Allocation latency&lt;/td&gt;
&lt;td&gt;n/a, Service round-robin&lt;/td&gt;
&lt;td&gt;tens of ms at p95&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Capacity model&lt;/td&gt;
&lt;td&gt;"how many calls fit in a pod?"&lt;/td&gt;
&lt;td&gt;pods per node, linear&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Risk to live calls from scaling&lt;/td&gt;
&lt;td&gt;HPA + default scheduling&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;WhenEmpty&lt;/code&gt; + &lt;code&gt;Packed&lt;/code&gt; + &lt;code&gt;do-not-disrupt&lt;/code&gt; + on-demand&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The architecture didn't fix the thread leak. The shielded &lt;code&gt;release()&lt;/code&gt; from Part 1 did. What the architecture did is make the class of bug irrelevant. A process that serves one call and dies can't accumulate anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Things I Got Wrong
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. &lt;code&gt;initialDelaySeconds&lt;/code&gt; lower than the cold start.&lt;/strong&gt; The Agones health check counts from pod start. The heartbeat starts when lifespan startup finishes, tens of seconds in. Agones started checking, saw nothing, and killed every pod a few seconds before it would have gone Ready. No error anywhere. Just a Fleet at 0 Ready, forever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Leaving the managed node group next to the Karpenter pool.&lt;/strong&gt; In dev we kept an old node group with the same label and taint "while it's phased out". Nothing scales a managed node group, so overflow landed on Karpenter and Karpenter nodes stuck around because &lt;code&gt;Packed&lt;/code&gt; kept filling them. Two schedulers, one label. Pick one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Agones' Helm pre-delete hook.&lt;/strong&gt; Upstream ships a hook that deletes every GameServer in the managed namespaces on chart delete. ArgoCD runs it whenever the Application is deleted, including an ApplicationSet regenerating it, and &lt;code&gt;preserveResourcesOnDeletion&lt;/code&gt; doesn't stop hooks. On prod that is every live call, ended by a GitOps refactor. &lt;code&gt;agones.crds.cleanupOnDelete: false&lt;/code&gt;, for good.&lt;/p&gt;

&lt;h2&gt;
  
  
  If You're In My Shoes
&lt;/h2&gt;

&lt;p&gt;If you run realtime, stateful, one-user-at-a-time workloads, voice agents, video rooms, browser sessions, anything with a native SDK that holds threads, stop trying to make a multi-tenant process behave and look at Agones. It was built for exactly "hand out one fresh process per session and never kill it mid-session".&lt;/p&gt;

&lt;p&gt;Three rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The pod never exits itself.&lt;/strong&gt; &lt;code&gt;Shutdown()&lt;/code&gt;, then let SIGTERM run your teardown.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every path to an Allocated pod ends in &lt;code&gt;Shutdown()&lt;/code&gt;.&lt;/strong&gt; Failed starts included. Alert on &lt;code&gt;Allocated&lt;/code&gt; versus your own live-session count.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;WhenEmpty&lt;/code&gt; + &lt;code&gt;Packed&lt;/code&gt; + &lt;code&gt;do-not-disrupt&lt;/code&gt; + on-demand.&lt;/strong&gt; Drop any one and Karpenter will eventually hang up on someone.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Jarvis: the lifecycle.&lt;/strong&gt; Python, the shape of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lifespan startup
&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;transport_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prewarm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;     &lt;span class="c1"&gt;# Daily room + token, off the critical path
&lt;/span&gt;&lt;span class="nf"&gt;prewarm_vad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                          &lt;span class="c1"&gt;# Silero, off the critical path
&lt;/span&gt;&lt;span class="n"&gt;gc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;gc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agones&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                   &lt;span class="c1"&gt;# LAST: joins the pool only when actually warm
&lt;/span&gt;
&lt;span class="c1"&gt;# every call-ending path converges here
&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;publish_call_terminated&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;     &lt;span class="c1"&gt;# the end event first, billing depends on it
&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;cleanup_session&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;             &lt;span class="c1"&gt;# EndFrame → Daily release(), shielded, never cancelled
&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agones&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shutdown&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                &lt;span class="c1"&gt;# hand the GameServer back. Do NOT os._exit.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Watch these
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# warm pool depth, alert when it gets thin
sum(agones_gameservers_count{fleet_name="&amp;lt;fleet&amp;gt;", type="Ready"})

# leaked Allocated pods, alert when this stays above your live-call count
sum(agones_gameservers_count{fleet_name="&amp;lt;fleet&amp;gt;", type="Allocated"})

# the autoscaler is actually allowed to scale (0 = frozen at current replicas)
min(agones_fleet_autoscalers_able_to_scale)

# throttling on a Guaranteed pod should be ~0
sum(rate(container_cpu_cfs_throttled_periods_total{container="&amp;lt;app&amp;gt;"}[5m]))
  / sum(rate(container_cpu_cfs_periods_total{container="&amp;lt;app&amp;gt;"}[5m]))

# nodes the fleet is holding
count(count by (node) (container_memory_working_set_bytes{container="&amp;lt;app&amp;gt;"}))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Two posts ago the answer was "hash the session header". One post ago it was "count the threads". This time it was "stop sharing the process".&lt;/p&gt;

&lt;p&gt;Every one of those was right for the problem in front of me. None was the last answer. That's how infrastructure evolves, and honestly, watching a Fleet backfill a pod in the time it takes to say hello is a pretty good feeling.&lt;/p&gt;

</description>
      <category>agones</category>
      <category>karpenter</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Scaling Voice Agents to 10K+ Calls: Jarvis’s 3 Biggest Challenges: Part 1</title>
      <dc:creator>Darshil Mahraur</dc:creator>
      <pubDate>Sun, 18 Oct 2026 12:21:05 +0000</pubDate>
      <link>https://dev.to/darshil89/scaling-voice-agents-to-10k-calls-jarviss-3-biggest-challenges-part-1-2111</link>
      <guid>https://dev.to/darshil89/scaling-voice-agents-to-10k-calls-jarviss-3-biggest-challenges-part-1-2111</guid>
      <description>&lt;h2&gt;
  
  
  I Fixed Routing. Then I Found Out Routing Was Never the Real Problem
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;From "the pods keep dying" to "oh, it's the architecture"&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where We Left Off
&lt;/h2&gt;

&lt;p&gt;In my &lt;a href="https://dev.to/darshil89/saving-300month-while-fixing-webrtc-drops-how-istios-consistent-hashing-beat-redis-4j7i"&gt;last post&lt;/a&gt; I replaced a Redis session-affinity lookup with Istio consistent hashing. WebRTC drops stopped. We saved money. I felt clever.&lt;/p&gt;

&lt;p&gt;Then we tried to actually scale Jarvis.&lt;/p&gt;

&lt;p&gt;Jarvis is our real-time voice agent. It brokers a &lt;a href="https://daily.co" rel="noopener noreferrer"&gt;Daily.co&lt;/a&gt; WebRTC room per call and runs a &lt;a href="https://github.com/pipecat-ai/pipecat" rel="noopener noreferrer"&gt;pipecat&lt;/a&gt; pipeline: &lt;strong&gt;user speaks → VAD → STT → LLM → TTS → bot speaks&lt;/strong&gt;. The LLM lives in Stark, our orchestrator. Jarvis is the audio edge. One pod served several calls at once, like any normal web service.&lt;/p&gt;

&lt;p&gt;Here is what "normal web service" thinking got us:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jarvis-xxxxx   RESTARTS: 1   LAST STATE: OOMKilled
  heap:        pressing against the memory limit
  OS threads:  in the hundreds
  live calls:  a handful
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A handful of calls. Hundreds of threads. Consistent hashing had nothing to do with it.&lt;/p&gt;

&lt;p&gt;This post is the autopsy: three problems, what each one did to CPU and memory, and the one variable they all share. Part 2 is the rebuild with Agones and Karpenter, one pod per call.&lt;/p&gt;

&lt;h2&gt;
  
  
  What One Call Costs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F82ah74fymtgzhe844xu5.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F82ah74fymtgzhe844xu5.png" alt="One jarvis pod handling one call: audio comes in over WebRTC through the Daily native client, passes Silero VAD, streams to a speech-to-text vendor over WebSocket, the transcript goes to Stark for the LLM turn over HTTP/SSE, text goes out to a text-to-speech vendor, and the PCM comes back through the native client to the user" width="800" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Per call: one WebRTC peer, two vendor WebSockets, one SSE stream, one ONNX model scoring audio about 30 times a second, and a pile of resampling. All inside one Python process, under one CPU limit, sharing one memory limit.&lt;/p&gt;

&lt;p&gt;That limit was small. A few hundred millicores and well under a gigabyte, because that's what a web service pod looks like. Everything below is a fight over it.&lt;/p&gt;

&lt;p&gt;Here is what that fight looked like in prod, back when jarvis was a plain Deployment. Three pods sharing calls, two days, real data:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkeww3sxdp86uapxbq65q.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkeww3sxdp86uapxbq65q.png" alt="Three jarvis pods over two days: CPU is a flat line with short spikes, while working set and RSS memory climb in a staircase and never come back down" width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two things to hold onto. The CPU panel sits near zero and jumps in short spikes, and every spike is a call doing something: someone talking, a call starting, a TTS burst going out. The memory panels are a staircase. We'll come back to both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 1: VAD Isn't CPU-Hungry. It's CPU-Sensitive.
&lt;/h2&gt;

&lt;p&gt;VAD decides when the user has stopped talking. In pipecat that's Silero, an ONNX model scoring every short chunk, plus a &lt;code&gt;stop_secs&lt;/code&gt; timer: once the score drops below &lt;code&gt;confidence&lt;/code&gt; for &lt;code&gt;stop_secs&lt;/code&gt; seconds, the turn ends and the transcript goes to the LLM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VAD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;   &lt;span class="c1"&gt;# how sure the that this is speech
&lt;/span&gt;    &lt;span class="n"&gt;start_secs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;   &lt;span class="c1"&gt;# how long speech must persist before "user started"
&lt;/span&gt;    &lt;span class="n"&gt;stop_secs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nb"&gt;float&lt;/span&gt;   &lt;span class="c1"&gt;# how long silence must persist before "user stopped"
&lt;/span&gt;    &lt;span class="n"&gt;min_volume&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;   &lt;span class="c1"&gt;# below this, don't even ask the model
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The catch: &lt;strong&gt;&lt;code&gt;stop_secs&lt;/code&gt; is wall-clock time, but the chunks arrive through a process that can be throttled.&lt;/strong&gt; Late chunks look like silence.&lt;/p&gt;

&lt;p&gt;What happened on our pods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Loading Silero&lt;/strong&gt; costs tens of ms of CPU per call. Under the pod's CPU limit that stretched to several times longer in wall time, on the start-call path. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Look at the CPU panel again.&lt;/strong&gt; Between turns a pod sits near zero. When someone talks it spikes, and the spike is short. The kernel doesn't bill the average. It bills 100 ms slices against the quota.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When that happens,&lt;/strong&gt; the logs look like this:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[VAD] user stopped speaking      (stop_secs of "silence": really stop_secs of late chunks)
[STT] flush → LLM                "I was going to say that"
[VAD] user started speaking      (the chunks finally arrive)
[STT] flush → LLM                "we should probably"
→ two LLM turns for one sentence. User hears two replies.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We called these "duplicate messages". The first fix is in git history and I'm not proud of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bump STTToTextProcessor response timeout (band-aid for duplicate messages)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Over the next few months we also loosened &lt;code&gt;confidence&lt;/code&gt; and &lt;code&gt;min_volume&lt;/code&gt; and shortened &lt;code&gt;stop_secs&lt;/code&gt;, because VAD "wasn't firing". Some of that was real. Some of it was us tuning a model to compensate for a starved process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CPU:&lt;/strong&gt; VAD's own cost is small. Its sensitivity to throttling is total. It's the canary.&lt;br&gt;
&lt;strong&gt;RAM:&lt;/strong&gt; a few MB per analyzer. Not the memory problem.&lt;/p&gt;
&lt;h2&gt;
  
  
  Problem 2: STT/TTS Traffic Is Where the CPU Goes
&lt;/h2&gt;

&lt;p&gt;My first theory was Python. Single-threaded, GIL, two calls step on each other, done. I had that paragraph written. Then I remembered we'd run TTS to a bunch of devices off one process without anything choking.&lt;/p&gt;

&lt;p&gt;So I measured it. Two threads of pure Python loops take turns, textbook GIL. But the audio work a call does, resampling and VAD inference, is C and C++ underneath. It drops the GIL and runs on two cores just fine. The Daily client's threads don't ask Python at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Python wasn't the bottleneck.&lt;/strong&gt; The pod's CPU budget was. Parallel threads don't get around a budget. They spend it faster.&lt;/p&gt;

&lt;p&gt;Where a call's CPU goes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;Work&lt;/th&gt;
&lt;th&gt;When&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mic → STT&lt;/td&gt;
&lt;td&gt;chunk, frame, send, parse transcripts, decide when to flush&lt;/td&gt;
&lt;td&gt;while the user speaks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TTS → pod&lt;/td&gt;
&lt;td&gt;receive, resample, cut into 20 ms frames, hand to the native client&lt;/td&gt;
&lt;td&gt;while the bot speaks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native client&lt;/td&gt;
&lt;td&gt;Opus encode/decode, jitter buffer, WebRTC&lt;/td&gt;
&lt;td&gt;always, both legs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vendor failover&lt;/td&gt;
&lt;td&gt;tear down one WebSocket, open another, mid-turn&lt;/td&gt;
&lt;td&gt;rare, expensive&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;None of it is heavy alone. Each one is a spike on that CPU panel. Put calls together on one pod and it goes like this:&lt;/p&gt;

&lt;p&gt;Our load tester Voldemort, exists because of this table. One Locust user is one whole call: real STT, mock TTS and LLM with measured vendor latencies baked in. An instant mock makes a pod look several times more capable than it is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CPU:&lt;/strong&gt; the bulk of the in-call burst.&lt;br&gt;
&lt;strong&gt;RAM:&lt;/strong&gt; a bounded working set per live call. If this were the only memory cost we'd never have OOMed.&lt;/p&gt;

&lt;p&gt;So why did we OOM?&lt;/p&gt;
&lt;h2&gt;
  
  
  Problem 3: The Daily.co Thread Leak
&lt;/h2&gt;

&lt;p&gt;Python asyncio code doesn't make hundreds of threads. Something native does.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;daily-python&lt;/code&gt; wraps Daily's C++ WebRTC client. Every call creates one, and every client starts roughly ten OS threads. You'll see names like &lt;code&gt;SoupSignalling&lt;/code&gt; and &lt;code&gt;mediasoup-manag&lt;/code&gt; in &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/task/*/comm&lt;/code&gt;. Those threads and the client's audio buffers are freed by exactly one thing: &lt;code&gt;daily.release()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In pipecat, &lt;code&gt;release()&lt;/code&gt; runs at the very end of pipeline teardown, after an &lt;code&gt;EndFrame&lt;/code&gt; has flowed through every processor. Our teardown under load:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;end-call arrives
  → stop_pipeline()
    → queue EndFrame
    → wait for runner ... timeout ...
    → task.cancel()          ← "fallback if the pipeline does not finish"
  → drop transport reference
  → gc.collect()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;task.cancel()&lt;/code&gt; cancels the Python coroutine. It does not call &lt;code&gt;release()&lt;/code&gt; on the C++ client. The Python object gets collected. The ten threads and the buffers don't. They were never Python's to collect.&lt;/p&gt;

&lt;p&gt;And once we dropped our reference, our "active transports" gauge went back to zero. Our metric said clean. The kernel said hundreds of threads.&lt;/p&gt;

&lt;p&gt;Back to the screenshot from the top. CPU is quiet. Memory is a staircase, and there isn't a single step down in two days. Every step is a call that ended and left something behind. Three pods, same slope, so not one bad pod or one bad user.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fixes That Weren't
&lt;/h2&gt;

&lt;p&gt;Every one of these felt like progress at the time:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attempt&lt;/th&gt;
&lt;th&gt;What it did&lt;/th&gt;
&lt;th&gt;Why it wasn't enough&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Double the memory limit&lt;/td&gt;
&lt;td&gt;OOMed slower&lt;/td&gt;
&lt;td&gt;Leak is unbounded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;memray&lt;/code&gt; in prod&lt;/td&gt;
&lt;td&gt;Clean heap snapshots of Python objects&lt;/td&gt;
&lt;td&gt;Leak was native&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;gc.collect()&lt;/code&gt; after every cleanup&lt;/td&gt;
&lt;td&gt;Reclaimed the Python cycle&lt;/td&gt;
&lt;td&gt;No effect on C++ threads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jemalloc&lt;/td&gt;
&lt;td&gt;RSS tracked real usage&lt;/td&gt;
&lt;td&gt;Can't free what was never freed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redis snapshots + &lt;code&gt;/resume-call&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Calls survived a pod crash&lt;/td&gt;
&lt;td&gt;We built resume-on-crash instead of not crashing. Deleted later&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Istio consistent hashing&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;end-call&lt;/code&gt; reaches the right pod&lt;/td&gt;
&lt;td&gt;Until a scale event moves the ring. Then &lt;code&gt;end-call&lt;/code&gt; lands on the wrong pod and the call runs to the watchdog&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That last row is my previous post. Hashing was correct. It only mattered because one pod held state for many calls. We solved routing to a stateful pod without asking why the pod was stateful for more than one call.&lt;/p&gt;

&lt;p&gt;The actual leak fix is small:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# daily.release() is the only thing that reclaims the native client's
# threads and buffers. Never cancel it.
&lt;/span&gt;&lt;span class="n"&gt;release&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cleanup&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;daily-release-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_RELEASE_TIMEOUT_SECONDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_RELEASE_GRACE_SECONDS&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="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;TimeoutError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[MEMORY] Daily release slow, still waiting&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shield the release. Prune the transport entry only after it completes, so the gauge stays honest. That stopped the bleeding. It didn't change the fact that one pod was juggling several realtime pipelines on a web-service CPU limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Comparison That Changed the Architecture
&lt;/h2&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;Bottleneck&lt;/th&gt;
&lt;th&gt;Per call&lt;/th&gt;
&lt;th&gt;Scales with&lt;/th&gt;
&lt;th&gt;Shows up as&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VAD jitter&lt;/td&gt;
&lt;td&gt;CPU (sensitivity)&lt;/td&gt;
&lt;td&gt;tiny, first to feel a throttle&lt;/td&gt;
&lt;td&gt;calls per pod, superlinearly&lt;/td&gt;
&lt;td&gt;duplicate turns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;STT/TTS traffic&lt;/td&gt;
&lt;td&gt;CPU (volume)&lt;/td&gt;
&lt;td&gt;most of the burst&lt;/td&gt;
&lt;td&gt;calls per pod, linearly&lt;/td&gt;
&lt;td&gt;throttled periods, late TTS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Daily thread leak&lt;/td&gt;
&lt;td&gt;RAM + threads&lt;/td&gt;
&lt;td&gt;tens of MiB, ~10 threads per leaked call&lt;/td&gt;
&lt;td&gt;calls ever served by the pod&lt;/td&gt;
&lt;td&gt;OOMKilled&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This reframed it to: &lt;br&gt;
"What if a pod only ever served one call? Like a game server. One match, then it exits."&lt;/p&gt;

&lt;p&gt;Then nothing leaks across calls, because there is no across calls. VAD never competes with another call's TTS, because there are no neighbours. CPU per pod is one call's spikes and nothing else. Memory per pod is one call's working set, and then the process is gone. Routing is "the pod I was given".&lt;/p&gt;

&lt;p&gt;The problem collapses from "make a multi-tenant realtime Python process behave" to "hand out fresh processes fast enough". That's a scheduling problem, and the game industry solved it years ago.&lt;/p&gt;
&lt;h2&gt;
  
  
  If You're In My Shoes
&lt;/h2&gt;

&lt;p&gt;If you run a native SDK in Python on Kubernetes and you see threads creeping up while your metrics say clean, memory that only goes up, or endpointing that's flaky only under load, don't start with the model params. Count the threads.&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;# 1. threads, not memory&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &amp;lt;pod&amp;gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; /proc/1/task | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;

&lt;span class="c"&gt;# 2. what the threads are&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &amp;lt;pod&amp;gt; &lt;span class="nt"&gt;--&lt;/span&gt; sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'cat /proc/1/task/*/comm | sort | uniq -c | sort -rn | head'&lt;/span&gt;

&lt;span class="c"&gt;# 3. real heap vs cache&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &amp;lt;pod&amp;gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'^(anon|file) '&lt;/span&gt; /sys/fs/cgroup/memory.stat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For CPU, watch throttled periods, not the usage average. The average is what the spikes look like after Grafana flattens them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rate(container_cpu_cfs_throttled_periods_total{container="&amp;lt;app&amp;gt;"}[5m])
  / rate(container_cpu_cfs_periods_total{container="&amp;lt;app&amp;gt;"}[5m])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And one more, because &lt;code&gt;container_oom_events_total&lt;/code&gt; read zero in our cluster even for pods that were genuinely OOMKilled:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;max_over_time(kube_pod_container_status_last_terminated_reason{reason="OOMKilled"}[14d]) &amp;gt; 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Part 2:&lt;/strong&gt; how we rebuilt Jarvis as a one-pod-one-call fleet on Agones with Karpenter supplying nodes, the warm-pool formula &lt;code&gt;N = x + 3√x&lt;/code&gt;, the three ways a pod can leak out of the pool, and the arithmetic to 10,000 concurrent calls.&lt;/p&gt;

&lt;p&gt;It's not as clever as consistent hashing. It's a lot more boring. In the best way.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>devops</category>
      <category>kubernetes</category>
      <category>python</category>
    </item>
    <item>
      <title>Saving $300/Month While Fixing WebRTC Drops: How Istio's Consistent Hashing Beat Redis</title>
      <dc:creator>Darshil Mahraur</dc:creator>
      <pubDate>Mon, 30 Mar 2026 12:39:05 +0000</pubDate>
      <link>https://dev.to/darshil89/saving-300month-while-fixing-webrtc-drops-how-istios-consistent-hashing-beat-redis-4j7i</link>
      <guid>https://dev.to/darshil89/saving-300month-while-fixing-webrtc-drops-how-istios-consistent-hashing-beat-redis-4j7i</guid>
      <description>&lt;h2&gt;
  
  
  I Spent hours Debugging Sessions Until I Discovered Istio Consistent Hashing
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;A developer's journey from late-night debugging to elegant infrastructure solutions&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem That Started a Journey
&lt;/h2&gt;

&lt;p&gt;We had a scaling problem that wouldn't go away.&lt;/p&gt;

&lt;p&gt;Our Jarvis service needed to grow. We were scaling from 3 pods to handle more AI inference requests and audio interactions. But there was a critical issue: each Jarvis pod maintained state—model weights loaded in memory, WebRTC connections via daily.co for live audio calls, cached inference results.&lt;/p&gt;

&lt;p&gt;When requests bounced randomly between pods (thanks, round-robin load balancer), things broke:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request 1 (user-123) → Jarvis-Pod-1
  ✓ Model weights loaded, WebRTC connection active

Request 2 (user-123) → Jarvis-Pod-2 (different pod!)
  ✗ "Connection lost" - WebRTC drops
  ✗ Model weights reloaded - 500ms latency spike
  ✗ User's audio call freezes mid-session

Request 3 (user-123) → Jarvis-Pod-1
  ✓ Works again, but connection restarted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Month 1: We implemented Redis&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The natural solution was to implement session affinity with Redis. Smaran-v2 would query Redis: "which Jarvis pod for this user?" and route accordingly. It worked well. WebRTC connections stayed alive, latencies improved, users were happy.&lt;/p&gt;

&lt;p&gt;But as we scaled, the economics changed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cost:&lt;/strong&gt; $300/month for a Redis cluster&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latency overhead:&lt;/strong&gt; Every request made a network hop to Redis (5-10ms per request)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operational toil:&lt;/strong&gt; TTL management, replica failovers, cache invalidation edge cases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Redis solved the problem, but the cost-benefit ratio wasn't sustainable. We were paying premium dollars for a solution that was becoming a bottleneck. There had to be a more elegant way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After some R&amp;amp;D: We discovered Istio&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Digging through Kubernetes networking docs, I found something elegant: &lt;strong&gt;Istio's consistent hashing&lt;/strong&gt;. No external service. No Redis. Just hash the session ID, map it to a pod—all built into the load balancer.&lt;/p&gt;

&lt;p&gt;"Wait, we can remove Redis?" I asked.&lt;/p&gt;

&lt;p&gt;"Apparently. Let's build a POC."&lt;/p&gt;

&lt;p&gt;What started as a "maybe this could work" conversation turned into a proof-of-concept that would reshape our infrastructure.&lt;/p&gt;

&lt;p&gt;My first thought: &lt;em&gt;This is going to be a long night.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem I Didn't Know I Had
&lt;/h2&gt;

&lt;p&gt;Here's the setup. We have two main services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Request
    │
    ▼
┌─────────────────────────┐
│   Smaran-v2             │ (coordinator)
│   Routing requests to   │
└──────────┬──────────────┘
           │
           ▼
   ┌───────┴────────┐
   │                │
 Pod-1          Pod-2          Pod-3
 Jarvis         Jarvis         Jarvis
 (w/ state)     (w/ state)     (w/ state)
 (WebRTC)       (WebRTC)       (WebRTC)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jarvis is the workhorse—it runs AI inference, maintains WebRTC connections via daily.co, and caches model state. We needed to scale it to many pods, which introduced the session affinity problem.&lt;/p&gt;

&lt;p&gt;The Jarvis pods weren't just serving requests—they were &lt;em&gt;stateful&lt;/em&gt;. Each pod maintained:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Model weights in memory&lt;/strong&gt; (500MB loaded per pod)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-user WebRTC connections&lt;/strong&gt; via daily.co for audio calls&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That last one was critical. When a user started a audio call with daily.co, the Jarvis pod opened a WebRTC connection to participate in that session. If the next request hit a &lt;em&gt;different&lt;/em&gt; pod, that connection was completely lost. The WebRTC peer would see a disconnect. The user would see: "Connection lost."&lt;/p&gt;

&lt;p&gt;So here's what was happening with Jarvis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User starts audio call:
Request 1 → Jarvis-Pod-1
  ✓ Creates daily.co WebRTC connection
  ✓ Stream is live

User sends inference request:
Request 2 → Jarvis-Pod-2 (different pod!)
  ✗ Pod-2 has no WebRTC connection
  ✗ Connection drops
  ✗ audio feed freezes

User tries again:
Request 3 → Jarvis-Pod-1
  ✓ Pod-1 still has the connection
  ✓ audio works again (but connection restarted)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that wasn't even counting the raw performance penalty when a request hit a different Jarvis pod just because Kubernetes's default load balancer said "hey, let's send this request to a different Jarvis pod today."&lt;/p&gt;

&lt;p&gt;I definitely knew something was wrong now. That's not something you ignore.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Debugging Session from Hell
&lt;/h2&gt;

&lt;p&gt;I spent the next few days chasing ghosts:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Day 1:&lt;/strong&gt; "Must be a database performance issue." Checked query logs. Queries were fine.&lt;br&gt;
&lt;strong&gt;Day 2:&lt;/strong&gt; "Models are degrading?" Profiled inference on a single pod. Blazingly fast.&lt;br&gt;
&lt;strong&gt;Day 3:&lt;/strong&gt; "Network latency?" Ran iperf between pods. Nothing unusual.&lt;br&gt;
&lt;strong&gt;Day 4:&lt;/strong&gt; I added logging to see &lt;em&gt;which&lt;/em&gt; pod each request was hitting. That's when it clicked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request 1: user-12345 → Pod-1 (100ms) ✓
Request 2: user-12345 → Pod-2 (850ms) ✗ CACHE MISS
Request 3: user-12345 → Pod-3 (900ms) ✗ COLD START
Request 4: user-12345 → Pod-1 (100ms) ✓
Request 5: user-12345 → Pod-2 (850ms) ✗ CACHE MISS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pattern was unmistakable. The same user's requests were bouncing around like a pinball machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Attempt: The Redis Solution
&lt;/h2&gt;

&lt;p&gt;Need to pin users to pods.&lt;/p&gt;

&lt;p&gt;So we built a Redis solution. The idea was straightforward: maintain a mapping of &lt;code&gt;user_id → pod_name&lt;/code&gt; (stateful) (where we know the pod name) in Redis.&lt;/p&gt;

&lt;p&gt;It worked. Users stopped getting disconnected. WebRTC connections stayed alive. We felt clever.&lt;/p&gt;

&lt;p&gt;Then we started scaling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Redis Problem:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Every request hit Redis&lt;/strong&gt; - All traffic went through Redis first. With 10k req/sec, that's 10k Redis lookups per second.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Redis became a bottleneck&lt;/strong&gt; - We had to add read replicas, tune connection pools, add caching layers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost was insane&lt;/strong&gt; - A large Redis cluster to handle our traffic? That's several hundred dollars per month.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Failover was sketchy&lt;/strong&gt; - When Redis went down, pod assignment failed. Users got randomly routed. WebRTC connections dropped again.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;TTL management was tricky&lt;/strong&gt; - Set it too short and sessions expire mid-interaction. Set it too long and stale mappings pile up. We were constantly tuning this.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;We could've coded it, but why?&lt;/strong&gt; - Implementing session affinity logic directly in Smaran-v2 (consistent hashing code, pod registry, health checks, failover logic). But that would mean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Infrastructure logic bleeding into application code&lt;/li&gt;
&lt;li&gt;Every service that needs affinity has to reimplement this&lt;/li&gt;
&lt;li&gt;Scaling to new services means copy-paste the same logic again&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We realized: "This isn't an application concern. This is infrastructure's job."&lt;/p&gt;

&lt;p&gt;After two months of fighting Redis, our tech lead ARP said:&lt;/p&gt;

&lt;p&gt;"Have you looked at service meshes? Specifically Istio?"&lt;/p&gt;

&lt;p&gt;I hadn't. But ARP's mention was enough to get me digging.&lt;/p&gt;

&lt;p&gt;That evening, I started exploring Istio's documentation. The concept of consistent hashing at the networking layer—no Redis, no external state, everything baked into the load balancer—kept gnawing at me.&lt;/p&gt;

&lt;p&gt;I read through how DestinationRules work, how Envoy proxies handle traffic routing, and what consistent hashing actually means in practice. The deeper I dug, the more a question crystallized in my mind:&lt;/p&gt;

&lt;p&gt;"Wait... so Istio could handle session affinity for us? Without any application code changes? Just configuration?"&lt;/p&gt;

&lt;p&gt;Every resource I read pointed to the same answer: yes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploring Istio for Our Use Case
&lt;/h2&gt;

&lt;p&gt;I wasn't immediately convinced this would work for us. Our architecture was specific: Smaran-v2 needed to route requests to specific Jarvis pods based on user session. I had to figure out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How does consistent hashing actually work in Istio?&lt;/strong&gt; Dug into the DestinationRule spec and Envoy documentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How do we map our user session to a hashing key?&lt;/strong&gt; We'd need to send a header (like &lt;code&gt;x-call-session-id&lt;/code&gt;) that Istio could hash.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Will it actually solve the WebRTC affinity problem?&lt;/strong&gt; Traced through the request flow to confirm pods would stay consistent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What are the operational implications?&lt;/strong&gt; Could we fail over gracefully? What happens when we scale pods?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How fast could we POC this?&lt;/strong&gt; Estimated timeline for testing without impacting production.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The more I explored, the more elegant it seemed. Not a quick patch like Redis, but a real architectural improvement.&lt;/p&gt;

&lt;p&gt;By the end of that week, I was convinced. Here's what made it click:&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;No external Redis cluster&lt;/li&gt;
&lt;li&gt;Session affinity baked into the load balancer&lt;/li&gt;
&lt;li&gt;Lower latency (no Redis hop)&lt;/li&gt;
&lt;li&gt;Lower cost (no monthly bill)&lt;/li&gt;
&lt;li&gt;Reduced operational complexity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Technical Elegance:&lt;/strong&gt;&lt;br&gt;
Instead of "all requests from this IP go to Pod-1" (which breaks for our users behind a VPN), Istio offers: "all requests with &lt;code&gt;x-call-session-id: user-12345&lt;/code&gt; go to Pod-2."&lt;/p&gt;

&lt;p&gt;And the brilliant part? The hashing is &lt;em&gt;consistent&lt;/em&gt;. When we scale from 3 to 10 pods, most requests still map to the same pod. Only ~30% of traffic rebalances. Compare that to round-robin, where &lt;em&gt;all&lt;/em&gt; traffic redistributes.&lt;/p&gt;

&lt;p&gt;"Let's build a POC," I told the team. "If this works, we can retire Redis."&lt;/p&gt;
&lt;h2&gt;
  
  
  The Key Insight: DestinationRule
&lt;/h2&gt;

&lt;p&gt;Here's the magic piece. In Istio, you define how traffic should be &lt;em&gt;handled&lt;/em&gt; with a &lt;code&gt;DestinationRule&lt;/code&gt;. Instead of maintaining Redis mappings, Istio computes the pod assignment on-the-fly using consistent hashing.&lt;/p&gt;

&lt;p&gt;I created one for Jarvis:&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;networking.istio.io/v1beta1&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;DestinationRule&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;jarvis-consistent-hash&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev&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;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jarvis-service.dev.svc.cluster.local&lt;/span&gt;
  &lt;span class="na"&gt;trafficPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;loadBalancer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;consistentHash&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;httpHeaderName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-call-session-id"&lt;/span&gt;
    &lt;span class="na"&gt;connectionPool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;h2UpgradePolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UPGRADE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me break down what I was actually doing here:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;httpHeaderName: "x-call-session-id"&lt;/code&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This is the magic. Istio looks at the &lt;code&gt;x-call-session-id&lt;/code&gt; header in each request, hashes it, and maps it to a pod. Same header value = same pod, always.&lt;/p&gt;

&lt;p&gt;Unlike Redis, there's no external lookup. No network hop. No TTL management. The hash is deterministic and instant. If we have 3 pods and hash the value &lt;code&gt;user-12345&lt;/code&gt;, it always maps to Pod-2. If we add a 4th pod tomorrow, most requests still map to the same pod (that's the magic of consistent hashing).&lt;/p&gt;

&lt;p&gt;Compare to our Redis approach:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Redis Solution&lt;/th&gt;
&lt;th&gt;Istio Consistent Hash&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~5-10ms lookup time&lt;/td&gt;
&lt;td&gt;&amp;lt;1ms hash computation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$300+/month for Redis cluster&lt;/td&gt;
&lt;td&gt;Built-in, $0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Failover&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Redis goes down = broken&lt;/td&gt;
&lt;td&gt;No external dependency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scaling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All traffic rebalances&lt;/td&gt;
&lt;td&gt;~1/N rebalance on N→N+1 pods&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operational burden&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tune TTL, manage replicas&lt;/td&gt;
&lt;td&gt;Write YAML, forget about it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We literally saved money and got better performance by removing a dependency.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;h2UpgradePolicy: UPGRADE&lt;/code&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This one I learned the hard way. Without it, HTTP/1.1 connections weren't upgrading to HTTP/2. This meant connection pooling wasn't working as expected, and latencies were still higher than they should be. Added this line, and suddenly connection reuse kicked in.&lt;/p&gt;

&lt;p&gt;This was especially important for our daily.co WebRTC connections—keeping TCP connections alive and reusing them meant the WebRTC establishment was faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  The VirtualService: Routing Rules
&lt;/h2&gt;

&lt;p&gt;But wait, where does the header actually come from? I had to ensure Smaran-v2 was &lt;em&gt;sending&lt;/em&gt; that header to Jarvis.&lt;/p&gt;

&lt;p&gt;I added a &lt;code&gt;VirtualService&lt;/code&gt; to route traffic intelligently:&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;networking.istio.io/v1beta1&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;VirtualService&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;jarvis-routing&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev&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;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;jarvis-service.dev.svc.cluster.local&lt;/span&gt;
  &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Route with header (gets consistent hashing)&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&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="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;x-call-session-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;regex&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.+"&lt;/span&gt;
      &lt;span class="na"&gt;route&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jarvis-service.dev.svc.cluster.local&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;number&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;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;300s&lt;/span&gt;
    &lt;span class="c1"&gt;# Fallback without header (round-robin)&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&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="na"&gt;route&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jarvis-service.dev.svc.cluster.local&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;number&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;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;300s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first block handles requests &lt;em&gt;with&lt;/em&gt; the header (these get consistent hashing). The second block is a fallback for requests &lt;em&gt;without&lt;/em&gt; the header (they just get round-robin load balancing).&lt;/p&gt;

&lt;p&gt;I added that fallback after almost shipping without it. Then I thought: "What if Smaran-v2 forgets the header? What happens?" With the fallback, they still work—they're just not affinity-pinned. That felt reasonable.&lt;/p&gt;

&lt;h2&gt;
  
  
  mTLS: The Security Layer I Didn't Expect to Need
&lt;/h2&gt;

&lt;p&gt;While setting all this up, our security team (finally) looked at the architecture. They asked a simple question: "Are services talking over plain HTTP?"&lt;/p&gt;

&lt;p&gt;Uh. Yes.&lt;/p&gt;

&lt;p&gt;Their response was essentially: "Fix that."&lt;/p&gt;

&lt;p&gt;Istio made this stupidly easy. One more YAML file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;security.istio.io/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;PeerAuthentication&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;default&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;mtls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;STRICT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;STRICT&lt;/code&gt; mode means: if you try to talk to our services over plaintext, it gets rejected. Mutual TLS is enforced everywhere.&lt;/p&gt;

&lt;p&gt;I was nervous about this breaking things. Turned out Istio handles the certificate generation and rotation automatically. Zero intervention from us. By the next morning, all inter-service traffic was encrypted.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works: The Request Flow (Redis vs. Istio)
&lt;/h2&gt;

&lt;p&gt;Now here's where Istio became elegant. Let me trace a real request through our system, comparing the two approaches:&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="s"&gt;OLD REDIS APPROACH (Worked well, but had trade-offs)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="s"&gt;1. Client sends request to Smaran-v2 with user-12345 and audio call&lt;/span&gt;
&lt;span class="na"&gt;2. Smaran-v2 queries Redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;which&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Jarvis&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;pod&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;this&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user?"&lt;/span&gt;
&lt;span class="na"&gt;3. Redis lookup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5-10ms latency&lt;/span&gt;
&lt;span class="na"&gt;4. Returns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;jarvis-pod-1"&lt;/span&gt;
&lt;span class="s"&gt;5. Smaran-v2 routes to jarvis-pod-1 directly&lt;/span&gt;
&lt;span class="s"&gt;6. jarvis-pod-1 has the WebRTC connection and session state&lt;/span&gt;
&lt;span class="s"&gt;✓ Works reliably, but adds latency and operational overhead&lt;/span&gt;

&lt;span class="s"&gt;NEW ISTIO APPROACH (Current, way better)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;1. Client makes request with session header&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="s"&gt;GET /inference&lt;/span&gt;
   &lt;span class="s"&gt;Headers&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;
     &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-call-session-id"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user-12345-session-audio"&lt;/span&gt;
   &lt;span class="pi"&gt;}&lt;/span&gt;

&lt;span class="s"&gt;2. Smaran-v2 receives it&lt;/span&gt;
   &lt;span class="s"&gt;✓ Extracts x-call-session-id&lt;/span&gt;
   &lt;span class="s"&gt;✓ Forwards to Jarvis service with header intact&lt;/span&gt;
   &lt;span class="s"&gt;(No Redis query needed!)&lt;/span&gt;

&lt;span class="s"&gt;3. Istio's Envoy Proxy (sidecar in Smaran-v2 or at service boundary) intercepts&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;✓ Reads x-call-session-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user-12345-session-audio"&lt;/span&gt;
   &lt;span class="na"&gt;✓ Hashes the value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hash("user-12345-session-audio") = &lt;/span&gt;&lt;span class="m"&gt;8421&lt;/span&gt;
   &lt;span class="na"&gt;✓ Maps to pod ring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;8421 % N_pods = Jarvis-Pod-1&lt;/span&gt;
   &lt;span class="s"&gt;✓ Routes request to jarvis-pod-1&lt;/span&gt;
   &lt;span class="s"&gt;(All done in &amp;lt;1ms, no external calls!)&lt;/span&gt;

&lt;span class="na"&gt;4. Jarvis Pod-1 processes request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="s"&gt;✓ Session state is hot in memory&lt;/span&gt;
   &lt;span class="s"&gt;✓ Model weights already loaded (500MB)&lt;/span&gt;
   &lt;span class="s"&gt;✓ WebRTC connection to daily.co is ALIVE&lt;/span&gt;
   &lt;span class="s"&gt;✓ Inference completes in ~95ms&lt;/span&gt;

&lt;span class="s"&gt;5. User continues audio call, sends next inference request&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
   &lt;span class="s"&gt;Same x-call-session-id header → Jarvis-Pod-1 again&lt;/span&gt;
   &lt;span class="s"&gt;✓ WebRTC connection stays open&lt;/span&gt;
   &lt;span class="s"&gt;✓ Session context preserved&lt;/span&gt;
   &lt;span class="s"&gt;✓ No cold starts, no reconnections&lt;/span&gt;
   &lt;span class="s"&gt;✓ Smooth user experience&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference? Istio eliminates the Redis hop entirely. Same consistent routing, but with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No external service dependency&lt;/li&gt;
&lt;li&gt;Sub-millisecond routing decisions&lt;/li&gt;
&lt;li&gt;Zero additional cost&lt;/li&gt;
&lt;li&gt;Cleaner architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the WebRTC connections? They stay alive now. The latency improvement alone was worth the migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Things I Got Wrong (and Learned)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Thinking about hashing too much
&lt;/h3&gt;

&lt;p&gt;I spent hours worrying about hash collisions, ring rebalancing, edge cases. In practice? Istio just &lt;em&gt;works&lt;/em&gt;. The consistent hash algorithm is proven, and Envoy has optimized it to death. I was overthinking.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Not understanding the fallback behavior
&lt;/h3&gt;

&lt;p&gt;I added the VirtualService fallback thinking "this is fine, they'll just get round-robin." Turns out, I should have been more explicit about &lt;em&gt;requiring&lt;/em&gt; the header.&lt;/p&gt;

&lt;p&gt;In production, we now validate that &lt;code&gt;x-call-session-id&lt;/code&gt; is present in Smaran-v2 before it forwards anything to Jarvis. If it's missing, we reject it with a clear error. That's much better than silently degrading to round-robin load balancing and potentially breaking WebRTC connections.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Forgetting that Istio adds latency (sometimes)
&lt;/h3&gt;

&lt;p&gt;The Envoy proxy running in each pod adds... actually, negligible latency. Maybe 1-2ms per request for header parsing and routing decisions. But I was paranoid about it anyway. Added observability metrics to track proxy latency specifically. Turned out I was worry for nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  When We Scale to 10 Jarvis Pods
&lt;/h2&gt;

&lt;p&gt;This is where the real test will come.&lt;/p&gt;

&lt;p&gt;When we scale from 3 to 10 Jarvis pods, I won't expect chaos—but I'll be watching closely. Here's what should happen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traffic will redistribute smoothly&lt;/li&gt;
&lt;li&gt;No request storms&lt;/li&gt;
&lt;li&gt;Existing WebRTC connections will stay pinned to their original pods&lt;/li&gt;
&lt;li&gt;New requests will get distributed to the new pods based on their session IDs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It should be... boring. Anticlimactically boring. In the best way.&lt;/p&gt;

&lt;p&gt;Pod utilization will spread evenly. Latencies will stay low. The on-call engineer (me) won't get paged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redis vs. Istio: The Comparison
&lt;/h2&gt;

&lt;p&gt;After six months running both in different parts of our infrastructure, the choice became unmistakable. Here's how they compare side-by-side:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Redis Solution&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Istio Consistent Hashing&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Architecture&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;External state store (Redis cluster)&lt;/td&gt;
&lt;td&gt;Built into load balancer (no external service)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$300+/month&lt;/td&gt;
&lt;td&gt;$0 (included with Istio)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Latency per Request&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5-10ms (Redis lookup)&lt;/td&gt;
&lt;td&gt;&amp;lt;1ms (hash computation)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Setup Complexity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Moderate (Redis deployment, tuning)&lt;/td&gt;
&lt;td&gt;Low (2 YAML files)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operational Burden&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High (failover, TTL tuning, replicas)&lt;/td&gt;
&lt;td&gt;Minimal (Istio manages it)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Network Calls per Request&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Every request → Redis&lt;/td&gt;
&lt;td&gt;Zero (local routing)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Failure Mode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Redis down → random routing → WebRTC drops&lt;/td&gt;
&lt;td&gt;Graceful, no single point of failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WebRTC Reliability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;15-20 disconnects/hour&lt;/td&gt;
&lt;td&gt;&amp;lt;1 disconnect/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scaling 3→10 pods&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100% traffic rebalances (TTL expires)&lt;/td&gt;
&lt;td&gt;~30% traffic rebalances (hash ring)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Developer Experience&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"Query Redis, route" (app code)&lt;/td&gt;
&lt;td&gt;"Send x-call-session-id header" (config)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Testing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires Redis mock + K8s API mock&lt;/td&gt;
&lt;td&gt;No mocks needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scalability Limit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Redis throughput limits growth&lt;/td&gt;
&lt;td&gt;Scales linearly with pods&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The Verdict:&lt;/strong&gt; Redis solved the immediate problem. Istio solved it &lt;em&gt;better&lt;/em&gt;. Why maintain a separate service for something the routing layer can handle elegantly?&lt;/p&gt;

&lt;p&gt;We haven't touched Redis since the migration. Consistent hashing is now foundational to our system—it's in the runbooks, baked into deployments, and new team members learn about it early. WebRTC stability through daily.co is rock solid.&lt;/p&gt;

&lt;p&gt;The lesson: you solve a problem one way, it works, you move forward. Then someone shows you a smarter approach, and you realize the trade-offs weren't necessary. That's how infrastructure evolves.&lt;/p&gt;

&lt;h2&gt;
  
  
  If You're In My Shoes
&lt;/h2&gt;

&lt;p&gt;If you're running stateful services in Kubernetes with WebRTC or persistent connections, or if you're seeing weird latency patterns that don't make sense, or if you're scaling and watching your p99 latencies explode—look into Istio's consistent hashing.&lt;/p&gt;

&lt;p&gt;It might save you a 3 AM debugging session (and a lot of frustrated users with dropped audio calls).&lt;/p&gt;

&lt;h3&gt;
  
  
  The Configs (Copy-Paste Ready)
&lt;/h3&gt;

&lt;p&gt;Save these three files and apply them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;destination-rule.yaml:&lt;/strong&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;networking.istio.io/v1beta1&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;DestinationRule&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;jarvis-consistent-hash&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev&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;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jarvis-service.dev.svc.cluster.local&lt;/span&gt;
  &lt;span class="na"&gt;trafficPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;loadBalancer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;consistentHash&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;httpHeaderName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-call-session-id"&lt;/span&gt;
    &lt;span class="na"&gt;connectionPool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;h2UpgradePolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UPGRADE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;virtual-service.yaml:&lt;/strong&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;networking.istio.io/v1beta1&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;VirtualService&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;jarvis-routing&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev&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;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;jarvis-service.dev.svc.cluster.local&lt;/span&gt;
  &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&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="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;x-call-session-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;regex&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.+"&lt;/span&gt;
      &lt;span class="na"&gt;route&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jarvis-service.dev.svc.cluster.local&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;number&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;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;300s&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&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="na"&gt;route&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jarvis-service.dev.svc.cluster.local&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;number&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;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;300s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;peer-authentication.yaml:&lt;/strong&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;security.istio.io/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;PeerAuthentication&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;default&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;mtls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;STRICT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploy:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install Istio (if needed)&lt;/span&gt;
istioctl &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="nv"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;demo &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="c"&gt;# Label namespace for auto-injection&lt;/span&gt;
kubectl label namespace dev istio-injection&lt;span class="o"&gt;=&lt;/span&gt;enabled

&lt;span class="c"&gt;# Apply configs&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; destination-rule.yaml virtual-service.yaml peer-authentication.yaml

&lt;span class="c"&gt;# Restart deployments to pick up new routing&lt;/span&gt;
kubectl rollout restart deployment/smaran-v2 &lt;span class="nt"&gt;-n&lt;/span&gt; dev
kubectl rollout restart deployment/jarvis &lt;span class="nt"&gt;-n&lt;/span&gt; dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test it:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# From Smaran-v2 or a test pod, send multiple requests with the same header&lt;/span&gt;
kubectl run &lt;span class="nt"&gt;-it&lt;/span&gt; debug &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curlimages/curl &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="nt"&gt;--&lt;/span&gt; sh

&lt;span class="c"&gt;# Then:&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;1..5&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"x-call-session-id: test-user-123"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       http://jarvis-service:80/inference
  &lt;span class="nb"&gt;sleep &lt;/span&gt;1
&lt;span class="k"&gt;done&lt;/span&gt;

&lt;span class="c"&gt;# Watch the Jarvis pod logs and you'll see each request hitting the same pod&lt;/span&gt;
&lt;span class="c"&gt;# Each request should be fast (no cold starts)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;That's the story. From 3 AM panic to elegant infrastructure. From debugging in the dark to understanding &lt;em&gt;why&lt;/em&gt; the system works.&lt;/p&gt;

&lt;p&gt;It's a pretty good feeling.&lt;/p&gt;

</description>
      <category>istio</category>
      <category>devops</category>
      <category>redis</category>
      <category>aws</category>
    </item>
    <item>
      <title>Go Programming: A Beginner's Guide</title>
      <dc:creator>Darshil Mahraur</dc:creator>
      <pubDate>Thu, 26 Jun 2025 21:00:12 +0000</pubDate>
      <link>https://dev.to/darshil89/go-programming-a-beginners-guide-58l1</link>
      <guid>https://dev.to/darshil89/go-programming-a-beginners-guide-58l1</guid>
      <description>&lt;p&gt;This is a placeholder for the article body.  It would contain introductory material on Go programming.&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a Smart Task Manager with JavaScript: From Concept to Code</title>
      <dc:creator>Darshil Mahraur</dc:creator>
      <pubDate>Thu, 26 Jun 2025 20:55:44 +0000</pubDate>
      <link>https://dev.to/darshil89/building-a-smart-task-manager-with-javascript-from-concept-to-code-2dn</link>
      <guid>https://dev.to/darshil89/building-a-smart-task-manager-with-javascript-from-concept-to-code-2dn</guid>
      <description>&lt;h1&gt;
  
  
  Building a Smart Task Manager with JavaScript: From Concept to Code
&lt;/h1&gt;

&lt;p&gt;In this tutorial, we'll build a feature-rich task manager application using vanilla JavaScript. This project will demonstrate key JavaScript concepts including DOM manipulation, local storage, event handling, and modern ES6+ features.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎯 What We're Building
&lt;/h2&gt;

&lt;p&gt;Our task manager will include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add, edit, and delete tasks&lt;/li&gt;
&lt;li&gt;Task categories and priorities&lt;/li&gt;
&lt;li&gt;Due date tracking&lt;/li&gt;
&lt;li&gt;Local storage persistence&lt;/li&gt;
&lt;li&gt;Search and filter functionality&lt;/li&gt;
&lt;li&gt;Responsive design&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🏗️ Project Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;task-manager/
├── index.html
├── styles.css
├── script.js
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  💻 The JavaScript Implementation
&lt;/h2&gt;

&lt;p&gt;Let's dive into the core JavaScript functionality:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Task Class and Data Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dueDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;completed&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="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;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;id&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;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;title&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;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;description&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;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;category&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;priority&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;priority&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;dueDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dueDate&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;completed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;completed&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;createdAt&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;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Method to check if task is overdue&lt;/span&gt;
  &lt;span class="nf"&gt;isOverdue&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="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dueDate&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&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;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&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;dueDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Method to get days until due&lt;/span&gt;
  &lt;span class="nf"&gt;getDaysUntilDue&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="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dueDate&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;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;diffTime&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;Date&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;dueDate&lt;/span&gt;&lt;span class="p"&gt;)&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;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&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;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;diffTime&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&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;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. TaskManager Class - The Heart of Our Application
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TaskManager&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&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;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadTasks&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;currentFilter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;all&lt;/span&gt;&lt;span class="dl"&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;currentSort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dueDate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializeEventListeners&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderTasks&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Load tasks from localStorage&lt;/span&gt;
  &lt;span class="nf"&gt;loadTasks&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;savedTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tasks&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;savedTasks&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="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;savedTasks&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;taskData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nx"&gt;taskData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;taskData&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="nx"&gt;taskData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;taskData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;taskData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;taskData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dueDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;taskData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&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;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;// Save tasks to localStorage&lt;/span&gt;
  &lt;span class="nf"&gt;saveTasks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&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;tasks&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Add a new task&lt;/span&gt;
  &lt;span class="nf"&gt;addTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;taskData&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;task&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;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nx"&gt;taskData&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="nx"&gt;taskData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;taskData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;taskData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;taskData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dueDate&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;tasks&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;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveTasks&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderTasks&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Show success notification&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Task added successfully!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&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="c1"&gt;// Update an existing task&lt;/span&gt;
  &lt;span class="nf"&gt;updateTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updates&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;taskIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&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;taskIndex&lt;/span&gt; &lt;span class="o"&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="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&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;tasks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;taskIndex&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveTasks&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderTasks&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Task updated successfully!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&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="c1"&gt;// Delete a task&lt;/span&gt;
  &lt;span class="nf"&gt;deleteTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveTasks&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderTasks&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Task deleted successfully!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;info&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="c1"&gt;// Toggle task completion&lt;/span&gt;
  &lt;span class="nf"&gt;toggleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&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;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveTasks&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderTasks&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="c1"&gt;// Filter tasks based on status&lt;/span&gt;
  &lt;span class="nf"&gt;filterTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filter&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;currentFilter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderTasks&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Get filtered tasks&lt;/span&gt;
  &lt;span class="nf"&gt;getFilteredTasks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;filteredTasks&lt;/span&gt; &lt;span class="o"&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;tasks&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// Apply status filter&lt;/span&gt;
    &lt;span class="k"&gt;switch &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;currentFilter&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;filteredTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filteredTasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&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;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;filteredTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filteredTasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;overdue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;filteredTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filteredTasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isOverdue&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;// Sort tasks&lt;/span&gt;
    &lt;span class="nx"&gt;filteredTasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&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;switch &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;currentSort&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dueDate&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dueDate&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dueDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dueDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dueDate&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;-&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;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dueDate&lt;/span&gt;&lt;span class="p"&gt;)&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dueDate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;priority&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;priorityOrder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;high&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;medium&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="na"&gt;low&lt;/span&gt;&lt;span class="p"&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;return&lt;/span&gt; &lt;span class="nx"&gt;priorityOrder&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;priorityOrder&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;created&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;)&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="k"&gt;return&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;filteredTasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. DOM Manipulation and Rendering
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Render tasks to the DOM&lt;/span&gt;
&lt;span class="nf"&gt;renderTasks&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;taskList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task-list&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;filteredTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFilteredTasks&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;taskList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filteredTasks&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;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;taskList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
      &amp;lt;div class="empty-state"&amp;gt;
        &amp;lt;h3&amp;gt;No tasks found&amp;lt;/h3&amp;gt;
        &amp;lt;p&amp;gt;Add a new task to get started!&amp;lt;/p&amp;gt;
      &amp;lt;/div&amp;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;filteredTasks&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;task&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;taskElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTaskElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;taskList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;taskElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateTaskStats&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 individual task element&lt;/span&gt;
&lt;span class="nf"&gt;createTaskElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&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;taskEl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;taskEl&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="s2"&gt;`task-item &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;completed&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="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;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isOverdue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;overdue&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="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;taskEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;taskId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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;daysUntilDue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDaysUntilDue&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;dueDateDisplay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dueDate&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; 
    &lt;span class="s2"&gt;`&amp;lt;span class="due-date &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isOverdue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;overdue&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="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;
      &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isOverdue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Overdue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;daysUntilDue&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Due today&lt;/span&gt;&lt;span class="dl"&gt;'&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;daysUntilDue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; days left`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
    &amp;lt;/span&amp;gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;taskEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;div class="task-content"&amp;gt;
      &amp;lt;div class="task-header"&amp;gt;
        &amp;lt;input type="checkbox" class="task-checkbox" &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checked&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="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;
        &amp;lt;h3 class="task-title"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;task&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="s2"&gt;&amp;lt;/h3&amp;gt;
        &amp;lt;span class="task-priority priority-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/span&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;p class="task-description"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&amp;gt;
      &amp;lt;div class="task-meta"&amp;gt;
        &amp;lt;span class="task-category"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/span&amp;gt;
        &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;dueDateDisplay&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class="task-actions"&amp;gt;
      &amp;lt;button class="btn btn-sm btn-secondary edit-task"&amp;gt;Edit&amp;lt;/button&amp;gt;
      &amp;lt;button class="btn btn-sm btn-danger delete-task"&amp;gt;Delete&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  `&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;taskEl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Event Handling
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Initialize all event listeners&lt;/span&gt;
&lt;span class="nf"&gt;initializeEventListeners&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Task form submission&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submit&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="nx"&gt;e&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleTaskSubmission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Filter buttons&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.filter-btn&lt;/span&gt;&lt;span class="dl"&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;btn&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;btn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&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="nx"&gt;e&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.filter-btn&lt;/span&gt;&lt;span class="dl"&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;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filterTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&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="c1"&gt;// Sort dropdown&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sort-select&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&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="nx"&gt;e&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentSort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderTasks&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Search functionality&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search-input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&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="nx"&gt;e&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;searchTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Task list event delegation&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task-list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&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="nx"&gt;e&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;taskItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;closest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.task-item&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;taskItem&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;taskId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;taskItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;taskId&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task-checkbox&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggleTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;taskId&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;edit-task&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;editTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;taskId&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete-task&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;confirmDeleteTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;taskId&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;h3&gt;
  
  
  5. Advanced Features
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Search functionality&lt;/span&gt;
&lt;span class="nf"&gt;searchTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderTasks&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class="nx"&gt;task&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="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderFilteredTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchResults&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Task statistics&lt;/span&gt;
&lt;span class="nf"&gt;updateTaskStats&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;totalTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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;completedTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&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;overdueTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isOverdue&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;total-tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;totalTasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;completed-tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;completedTasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;overdue-tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;overdueTasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Notification system&lt;/span&gt;
&lt;span class="nf"&gt;showNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;info&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;notification&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="s2"&gt;`notification notification-&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Trigger animation&lt;/span&gt;
  &lt;span class="nf"&gt;setTimeout&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;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;show&lt;/span&gt;&lt;span class="dl"&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="c1"&gt;// Remove notification after 3 seconds&lt;/span&gt;
  &lt;span class="nf"&gt;setTimeout&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;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;show&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&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;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;3000&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;
  
  
  🚀 Initialization and Usage
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Initialize the task manager when DOM is loaded&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DOMContentLoaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;taskManager&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;TaskManager&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Make it globally accessible for debugging&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;taskManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;taskManager&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="s1"&gt;Task Manager initialized successfully!&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;h2&gt;
  
  
  🎨 Key JavaScript Concepts Demonstrated
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;ES6+ Classes&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We use modern class syntax to organize our code into reusable, maintainable components.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Array Methods&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Extensive use of &lt;code&gt;filter()&lt;/code&gt;, &lt;code&gt;map()&lt;/code&gt;, &lt;code&gt;find()&lt;/code&gt;, &lt;code&gt;sort()&lt;/code&gt;, and other array methods for data manipulation.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Local Storage&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Persistent data storage using the browser's localStorage API.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Event Delegation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Efficient event handling using event delegation for dynamic content.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Template Literals&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Clean string interpolation and multi-line strings for HTML generation.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. &lt;strong&gt;Destructuring and Spread Operator&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Modern JavaScript syntax for cleaner, more readable code.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔧 Performance Optimizations
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Event Delegation&lt;/strong&gt;: Instead of adding listeners to each task, we use a single listener on the container.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Efficient Rendering&lt;/strong&gt;: Only re-render when necessary and use document fragments for multiple DOM insertions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Debounced Search&lt;/strong&gt;: Implement debouncing for search functionality to improve performance.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Debounced search implementation&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;debounce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;wait&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;let&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;executedFunction&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&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;later&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="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;later&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;wait&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="c1"&gt;// Usage&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;debouncedSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;query&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;searchTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🎯 What You've Learned
&lt;/h2&gt;

&lt;p&gt;Building this task manager teaches you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Object-Oriented Programming&lt;/strong&gt; in JavaScript&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DOM manipulation&lt;/strong&gt; techniques&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event handling&lt;/strong&gt; and delegation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local storage&lt;/strong&gt; for data persistence&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Array methods&lt;/strong&gt; for data processing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern JavaScript&lt;/strong&gt; features (ES6+)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance optimization&lt;/strong&gt; techniques&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🚀 Next Steps
&lt;/h2&gt;

&lt;p&gt;To extend this project, consider adding:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Drag and drop&lt;/strong&gt; for task reordering&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task categories&lt;/strong&gt; with color coding&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export/import&lt;/strong&gt; functionality&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reminder notifications&lt;/strong&gt; using the Notification API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaborative features&lt;/strong&gt; with real-time sync&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progressive Web App&lt;/strong&gt; capabilities&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;This task manager demonstrates the power of vanilla JavaScript for building interactive web applications. By understanding these core concepts, you'll be well-equipped to tackle more complex JavaScript projects and frameworks.&lt;/p&gt;

&lt;p&gt;The complete source code is available on &lt;a href="https://github.com/example/js-task-manager" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Feel free to fork, modify, and make it your own!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What's your favorite JavaScript feature used in this project? Let me know in the comments below! 👇&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tags&lt;/strong&gt;: #javascript #webdev #tutorial #programming #beginners&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>Python Programming</title>
      <dc:creator>Darshil Mahraur</dc:creator>
      <pubDate>Thu, 26 Jun 2025 20:53:20 +0000</pubDate>
      <link>https://dev.to/darshil89/python-programming-4i9l</link>
      <guid>https://dev.to/darshil89/python-programming-4i9l</guid>
      <description>&lt;p&gt;This is a blog post about Python programming.  Please replace this with your actual content.&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building a Weather App: A Complete Guide to Weather APIs and Data Visualization</title>
      <dc:creator>Darshil Mahraur</dc:creator>
      <pubDate>Thu, 26 Jun 2025 18:57:32 +0000</pubDate>
      <link>https://dev.to/darshil89/building-a-weather-app-a-complete-guide-to-weather-apis-and-data-visualization-15mc</link>
      <guid>https://dev.to/darshil89/building-a-weather-app-a-complete-guide-to-weather-apis-and-data-visualization-15mc</guid>
      <description>&lt;h1&gt;
  
  
  Building a Weather App: A Complete Guide to Weather APIs and Data Visualization
&lt;/h1&gt;

&lt;p&gt;Weather applications are among the most popular and useful apps we use daily. Whether you're checking if you need an umbrella or planning a weekend trip, weather data plays a crucial role in our decision-making. In this comprehensive guide, we'll explore how to build a weather application from scratch using modern web technologies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Build a Weather App?
&lt;/h2&gt;

&lt;p&gt;Weather apps are excellent projects for developers because they involve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API Integration&lt;/strong&gt;: Working with real-time data from weather services&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Visualization&lt;/strong&gt;: Displaying complex information in user-friendly formats&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geolocation&lt;/strong&gt;: Understanding location-based services&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive Design&lt;/strong&gt;: Creating apps that work across different devices&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Updates&lt;/strong&gt;: Handling dynamic data that changes frequently&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Popular Weather APIs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. OpenWeatherMap API
&lt;/h3&gt;

&lt;p&gt;OpenWeatherMap is one of the most popular choices for developers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free tier&lt;/strong&gt;: 1,000 calls/day&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Current weather, forecasts, historical data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global coverage&lt;/strong&gt;: Worldwide weather data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt;: Excellent API documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. WeatherAPI
&lt;/h3&gt;

&lt;p&gt;A developer-friendly alternative:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free tier&lt;/strong&gt;: 1 million calls/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Features&lt;/strong&gt;: Real-time weather, forecasts, astronomy data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON/XML&lt;/strong&gt;: Multiple response formats&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy integration&lt;/strong&gt;: Simple REST API&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. AccuWeather API
&lt;/h3&gt;

&lt;p&gt;Enterprise-grade weather data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High accuracy&lt;/strong&gt;: Professional weather forecasting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limited free tier&lt;/strong&gt;: 50 calls/day&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced features&lt;/strong&gt;: Severe weather alerts, air quality data&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building Your First Weather App
&lt;/h2&gt;

&lt;p&gt;Let's create a simple weather app using JavaScript and the OpenWeatherMap API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: HTML Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Weather App&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"style.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;🌤️ Weather App&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"search-container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"cityInput"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Enter city name..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"searchBtn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Search&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"weather-container"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"weatherContainer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="c"&gt;&amp;lt;!-- Weather data will be displayed here --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: CSS Styling
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'Arial'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;linear-gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;135deg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;#74b9ff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;#0984e3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.95&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;15px&lt;/span&gt; &lt;span class="m"&gt;35px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.search-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;#cityInput&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#ddd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;#searchBtn&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#0984e3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.weather-info&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.temperature&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#2d3436&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.description&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#636e72&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.details&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.detail-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f8f9fa&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: JavaScript Logic
&lt;/h3&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;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_API_KEY_HERE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Get from OpenWeatherMap&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;API_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.openweathermap.org/data/2.5/weather&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;searchBtn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getWeather&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cityInput&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keypress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enter&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="nf"&gt;getWeather&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getWeather&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;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cityInput&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please enter a city name&lt;/span&gt;&lt;span class="dl"&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="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="nf"&gt;fetch&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;API_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?q=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;appid=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;units=metric`&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="o"&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;ok&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="s1"&gt;City not found&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;displayWeather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error fetching weather data: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&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;message&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;function&lt;/span&gt; &lt;span class="nf"&gt;displayWeather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;weatherContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;weatherContainer&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;weatherHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
        &amp;lt;div class="weather-info"&amp;gt;
            &amp;lt;h2&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h2&amp;gt;
            &amp;lt;div class="temperature"&amp;gt;&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;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;°C&amp;lt;/div&amp;gt;
            &amp;lt;div class="description"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;weather&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="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/div&amp;gt;
            &amp;lt;div class="details"&amp;gt;
                &amp;lt;div class="detail-item"&amp;gt;
                    &amp;lt;strong&amp;gt;Feels like&amp;lt;/strong&amp;gt;&amp;lt;br&amp;gt;
                    &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;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;feels_like&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;°C
                &amp;lt;/div&amp;gt;
                &amp;lt;div class="detail-item"&amp;gt;
                    &amp;lt;strong&amp;gt;Humidity&amp;lt;/strong&amp;gt;&amp;lt;br&amp;gt;
                    &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;humidity&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%
                &amp;lt;/div&amp;gt;
                &amp;lt;div class="detail-item"&amp;gt;
                    &amp;lt;strong&amp;gt;Wind Speed&amp;lt;/strong&amp;gt;&amp;lt;br&amp;gt;
                    &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;wind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; m/s
                &amp;lt;/div&amp;gt;
                &amp;lt;div class="detail-item"&amp;gt;
                    &amp;lt;strong&amp;gt;Pressure&amp;lt;/strong&amp;gt;&amp;lt;br&amp;gt;
                    &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pressure&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; hPa
                &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;weatherContainer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;weatherHTML&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Get user's location weather on page load&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="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="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geolocation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geolocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCurrentPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;position&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;longitude&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;position&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;getWeatherByCoords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nx"&gt;error&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;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="s1"&gt;Geolocation error:&lt;/span&gt;&lt;span class="dl"&gt;'&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="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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getWeatherByCoords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lon&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="nf"&gt;fetch&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;API_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?lat=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;lon=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lon&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;appid=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;units=metric`&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;data&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;displayWeather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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="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="s1"&gt;Error fetching weather by coordinates:&lt;/span&gt;&lt;span class="dl"&gt;'&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Advanced Features to Consider
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Weather Forecasts
&lt;/h3&gt;

&lt;p&gt;Extend your app to show 5-day forecasts:&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;FORECAST_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.openweathermap.org/data/2.5/forecast&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getForecast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;city&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&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;FORECAST_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?q=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;appid=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;units=metric`&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;data&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Process forecast data&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dailyForecasts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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;index&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dailyForecasts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Weather Maps
&lt;/h3&gt;

&lt;p&gt;Integrate weather maps using services like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenWeatherMap Maps&lt;/li&gt;
&lt;li&gt;Mapbox with weather layers&lt;/li&gt;
&lt;li&gt;Google Maps with weather overlays&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Push Notifications
&lt;/h3&gt;

&lt;p&gt;Add weather alerts and daily forecasts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Request notification permission&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Notification&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestPermission&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;permission&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;permission&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;granted&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="c1"&gt;// Schedule weather notifications&lt;/span&gt;
            &lt;span class="nf"&gt;scheduleWeatherNotifications&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;h3&gt;
  
  
  4. Offline Support
&lt;/h3&gt;

&lt;p&gt;Implement service workers for offline functionality:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Register service worker&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;serviceWorker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/sw.js&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;registration&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="s1"&gt;SW registered&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;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="s1"&gt;SW registration 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;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. API Key Security
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Never expose API keys in client-side code&lt;/li&gt;
&lt;li&gt;Use environment variables&lt;/li&gt;
&lt;li&gt;Implement server-side proxy for API calls&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Error Handling
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Handle network failures gracefully&lt;/li&gt;
&lt;li&gt;Provide meaningful error messages&lt;/li&gt;
&lt;li&gt;Implement retry mechanisms&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Performance Optimization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Cache weather data to reduce API calls&lt;/li&gt;
&lt;li&gt;Implement debouncing for search inputs&lt;/li&gt;
&lt;li&gt;Use lazy loading for forecast data&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. User Experience
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Show loading states during API calls&lt;/li&gt;
&lt;li&gt;Implement smooth transitions&lt;/li&gt;
&lt;li&gt;Provide fallback content for errors&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Building a weather app is an excellent way to learn modern web development concepts while creating something genuinely useful. From basic API integration to advanced features like push notifications and offline support, weather apps offer countless opportunities for learning and improvement.&lt;/p&gt;

&lt;p&gt;The key to a successful weather app lies in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reliable data sources&lt;/strong&gt;: Choose APIs with good uptime and accuracy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intuitive design&lt;/strong&gt;: Make weather information easy to understand at a glance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Ensure fast loading times and smooth interactions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: Design for users with different needs and devices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start with a simple implementation and gradually add features as you become more comfortable with the concepts. Remember that the best weather apps are those that solve real problems for real users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://openweathermap.org/api" rel="noopener noreferrer"&gt;OpenWeatherMap API Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.weatherapi.com/docs/" rel="noopener noreferrer"&gt;WeatherAPI Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API" rel="noopener noreferrer"&gt;MDN Geolocation API Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/web/fundamentals/primers/service-workers" rel="noopener noreferrer"&gt;Service Workers Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy coding! 🌦️&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Convert http to https in AWS</title>
      <dc:creator>Darshil Mahraur</dc:creator>
      <pubDate>Sat, 16 Nov 2024 12:13:25 +0000</pubDate>
      <link>https://dev.to/darshil89/convert-http-to-https-in-aws-3ecj</link>
      <guid>https://dev.to/darshil89/convert-http-to-https-in-aws-3ecj</guid>
      <description>&lt;h2&gt;
  
  
  Upgrade Your EC2 Instance: A Step-by-Step Guide to Securing Your Site with HTTPS!
&lt;/h2&gt;




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

&lt;p&gt;&lt;em&gt;To secure the public URL provided by a load balancer when connecting to an EC2 instance within the same VPC, it’s crucial to follow a structured approach. Start by acquiring a registered domain name from a trusted provider like GoDaddy. Next, configure your EC2 instance to function behind an Application Load Balancer (ALB) within the same VPC. Upload your domain to AWS Certificate Manager to obtain a verified SSL/TLS certificate. Finally, integrate this certificate into Route 53 and map it to your load balancer. This setup not only secures your connection but lays the foundation for seamless and reliable traffic management. Let’s dive deeper into the steps—you’re just a few clicks away from an airtight setup!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisite
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Domain Name Registration&lt;/strong&gt; &lt;br&gt;
Obtain a domain name from a trusted third-party provider say GoDaddy for mapping your load balancer's public URL.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration with ALB&lt;/strong&gt;&lt;br&gt;
Ensure your EC2 instance is connected to an Application Load Balancer within the same VPC to manage traffic securely and efficiently.&lt;br&gt;
You can attain this by referring to this &lt;a href="https://www.linkedin.com/posts/darshil-mahraur-821216259_awscloud-ec2-autoscaling-activity-7171233523679395841-_KQA?utm_source=share&amp;amp;utm_medium=member_desktop" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt; post.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Verify Your Domain with AWS Certificate Manager
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to AWS console and select ACM.&lt;/li&gt;
&lt;li&gt;Request a new certificate and keep it public.&lt;/li&gt;
&lt;/ul&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%2F7hvw9v5dkad91tpw99nh.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%2F7hvw9v5dkad91tpw99nh.png" alt="Requesting Certificate" width="800" height="395"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Here enter your domain name and keep the setting as selected below. By selecting DNS validation you will get the cname and and it's value.&lt;/li&gt;
&lt;/ul&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%2Fzmm6gr8ed3y3mu803sjv.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%2Fzmm6gr8ed3y3mu803sjv.png" alt="Enter Domain Name" width="800" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copy paste the cname and value to Go Daddy DNS Records. By doing this the certificate will get verified in few minutes.&lt;/li&gt;
&lt;/ul&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%2Fjtthyemwjrzr2thw626k.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%2Fjtthyemwjrzr2thw626k.png" alt="CNAME" width="798" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once your certificate is successfully issued, the AWS Certificate Manager (ACM) process is complete.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Configure Route 53 and Update Nameservers in GoDaddy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to AWS Route53 and create your hosted zone with your domain and keep it public zone.&lt;/li&gt;
&lt;/ul&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%2Fuxjkaztpwgv6xt8r4u2d.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%2Fuxjkaztpwgv6xt8r4u2d.png" alt="AWS Route53" width="800" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once the zone is created you will get NS records as shown.&lt;/li&gt;
&lt;/ul&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%2F7imsq72mk0owx0yfaz67.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%2F7imsq72mk0owx0yfaz67.png" alt="Get NS Records" width="799" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to Go Daddy and select nameservers and then change nameservers.&lt;/li&gt;
&lt;li&gt;Select the option 'I'll use my own nameservers' and paste the nameserver we got previously from Route53.&lt;/li&gt;
&lt;/ul&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%2Fhnff7f6onx3qyem8mjta.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%2Fhnff7f6onx3qyem8mjta.png" alt="Copy ns records from Route53" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once this is done then your Go Daddy will no more responsible for managing your nameservers. It will look something like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7tkimr174ezne9uom169.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%2F7tkimr174ezne9uom169.png" alt="Go Daddy Console" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once this is successfully done, the AWS Route53 process is complete.&lt;/p&gt;

&lt;h3&gt;
  
  
  General Knowledge
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Nameservers&lt;/strong&gt; are part of the &lt;strong&gt;Domain Name System (DNS)&lt;/strong&gt; that translate domain names (like example.com) into IP addresses that computers use to identify each other. They are essential because they direct internet traffic to the correct server, ensuring users can access your website or application seamlessly.&lt;br&gt;
&lt;strong&gt;Amazon Route 53&lt;/strong&gt; is a scalable DNS web service that connects user requests to internet resources like websites or applications. It manages domain names, routes traffic efficiently, and integrates with AWS services to provide secure, reliable, and highly available routing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Connect your Route53 to Application load balancer.
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create a A record for your domain to connect your Route53 to Application Load Balancer and select 'switch to wizard'&lt;/li&gt;
&lt;/ul&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%2Fdw39e7m78gtw4fgnxpep.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%2Fdw39e7m78gtw4fgnxpep.png" alt="Creating 'A' record" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select simple routing and proceed.&lt;/li&gt;
&lt;/ul&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%2F9vpebr6ha28ezuru2pd4.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%2F9vpebr6ha28ezuru2pd4.png" alt="Simple Routing" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select 'Define Simple Record' and a pop up menu will appear like this.&lt;/li&gt;
&lt;/ul&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%2Fmduvnirc5403brkggmap.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%2Fmduvnirc5403brkggmap.png" alt="Simple Record" width="800" height="787"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select Application and Classic Load Balancer , the region where it is located and choose the load balancer you have created previously.&lt;/li&gt;
&lt;/ul&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%2Fj1nc4fkbjkpcowxuj5uf.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%2Fj1nc4fkbjkpcowxuj5uf.png" alt="Select these options" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once completed, you'll be able to connect your application using your IP address, but only via HTTP, not HTTPS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Final Step (Make it Https)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to Certificate Manager , select your issued certificate and click 'Create record in Route53'. This will link a cname record of this certificate with Route53.&lt;/li&gt;
&lt;/ul&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%2Fvgifo9rh7s3v1zq07kod.jpeg" 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%2Fvgifo9rh7s3v1zq07kod.jpeg" alt="Linking certificate to route53" width="800" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Now link the certificate to the load balancer. Go to your load balancer and add a listener for HTTPS:443.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Under Secure listener settings link your issued certificate from ACM.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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%2Fjjci3kc8bpnb3mlswbgr.jpeg" 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%2Fjjci3kc8bpnb3mlswbgr.jpeg" alt="Linking certificate to Load Balancer" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once completed, you'll be able to connect your application using HTTPS.&lt;/p&gt;

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

&lt;p&gt;Congratulations! 🎉 You have successfully completed the HTTP to HTTPS tutorial. Your website is now securely encrypted, providing a safer browsing experience for your users. Great job!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzu3v0bszrndcwouxtnrn.jpeg" 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%2Fzu3v0bszrndcwouxtnrn.jpeg" alt="Result" width="800" height="581"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Additionals
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Make sure your security groups inbound rules are accepting https traffic.&lt;/li&gt;
&lt;li&gt;You can redirect your http traffic to https in the rules section.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>route53</category>
      <category>nameserver</category>
      <category>godaddy</category>
    </item>
    <item>
      <title>New here ,</title>
      <dc:creator>Darshil Mahraur</dc:creator>
      <pubDate>Sun, 28 Apr 2024 19:50:42 +0000</pubDate>
      <link>https://dev.to/darshil89/new-here--10p9</link>
      <guid>https://dev.to/darshil89/new-here--10p9</guid>
      <description>&lt;p&gt;&lt;strong&gt;Hello everyone , I am new to this platform.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>hello</category>
    </item>
  </channel>
</rss>
