<?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: Teja</title>
    <description>The latest articles on DEV Community by Teja (@teja_7a39cf3c9baffdbdf100).</description>
    <link>https://dev.to/teja_7a39cf3c9baffdbdf100</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%2F3998298%2Ff1dd1066-7639-4d2b-b713-757b9e20fcc4.png</url>
      <title>DEV Community: Teja</title>
      <link>https://dev.to/teja_7a39cf3c9baffdbdf100</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/teja_7a39cf3c9baffdbdf100"/>
    <language>en</language>
    <item>
      <title>Stop Prop Drilling: Rendering Deeply Nested Dynamic Roadmaps in React and Node.js</title>
      <dc:creator>Teja</dc:creator>
      <pubDate>Tue, 23 Jun 2026 09:36:57 +0000</pubDate>
      <link>https://dev.to/teja_7a39cf3c9baffdbdf100/stop-prop-drilling-rendering-deeply-nested-dynamic-roadmaps-in-react-and-nodejs-ng3</link>
      <guid>https://dev.to/teja_7a39cf3c9baffdbdf100/stop-prop-drilling-rendering-deeply-nested-dynamic-roadmaps-in-react-and-nodejs-ng3</guid>
      <description>&lt;p&gt;Rendering flat lists in React is trivial. Rendering a deeply nested, dynamically generated UI tree without crashing the browser is a completely different nightmare.&lt;/p&gt;

&lt;p&gt;When I was building Skill Path—an application that generates dynamically structured learning roadmaps—I quickly ran into major state management bottlenecks. Passing data down seven levels of a visual roadmap creates an unmaintainable mess of prop drilling.&lt;/p&gt;

&lt;p&gt;Here is the architecture I ended up using to bridge a Flask algorithm, a Node.js API, and a React frontend utilizing CSS Grid and glassmorphism.&lt;/p&gt;

&lt;p&gt;The Two-Brain Backend Pipeline&lt;br&gt;
Instead of forcing one framework to do everything, I split the backend into two distinct services.&lt;/p&gt;

&lt;p&gt;The Engine (Flask): Python is significantly better for handling the complex algorithms needed to build the learning paths. The Flask service generates the raw node relationships.&lt;/p&gt;

&lt;p&gt;The API Gateway (Node.js/Express): Node.js handles the client requests, authentication, and caching. It fetches the heavy JSON from Flask, flattens it, and sends it to the frontend.&lt;/p&gt;

&lt;p&gt;The JSON Payload Structure&lt;br&gt;
The absolute best trick to making React render fast is formatting your backend payload as a flat dictionary with parent-child ID references, rather than a deeply nested JSON object.&lt;/p&gt;

&lt;p&gt;JSON&lt;br&gt;
// How our Node.js server formats the payload for React&lt;br&gt;
{&lt;br&gt;
  "roadmap_id": "fullstack_2026",&lt;br&gt;
  "nodes": {&lt;br&gt;
    "node_1": { "title": "HTML/CSS", "children": ["node_2", "node_3"] },&lt;br&gt;
    "node_2": { "title": "CSS Grid", "children": [] },&lt;br&gt;
    "node_3": { "title": "JavaScript Basics", "children": ["node_4"] }&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
The Frontend: Avoiding the Re-render Trap&lt;br&gt;
If you try to map over a massive nested array in React, any state change (like clicking "Mark as Complete" on a skill) triggers a re-render of the entire tree.&lt;/p&gt;

&lt;p&gt;To fix this, I used a centralized state store and rendered individual node components that only care about their specific ID.&lt;/p&gt;

&lt;p&gt;The Component Setup&lt;br&gt;
Instead of passing the entire tree down, the top-level component just renders the root node.&lt;/p&gt;

&lt;p&gt;JavaScript&lt;br&gt;
import React, { useState } from 'react';&lt;br&gt;
import RoadmapNode from './RoadmapNode';&lt;/p&gt;

&lt;p&gt;const SkillPathViewer = ({ roadmapData }) =&amp;gt; {&lt;br&gt;
  // roadmapData is the flattened JSON from our Node.js backend&lt;br&gt;
  const [completedNodes, setCompletedNodes] = useState(new Set());&lt;/p&gt;

&lt;p&gt;const toggleComplete = (nodeId) =&amp;gt; {&lt;br&gt;
    setCompletedNodes(prev =&amp;gt; {&lt;br&gt;
        const newSet = new Set(prev);&lt;br&gt;
        newSet.has(nodeId) ? newSet.delete(nodeId) : newSet.add(nodeId);&lt;br&gt;
        return newSet;&lt;br&gt;
    });&lt;br&gt;
  };&lt;/p&gt;

&lt;p&gt;return (&lt;br&gt;
    &lt;/p&gt;
&lt;br&gt;
       {/* We only render the starting node. It handles its own children. */}&lt;br&gt;
       &lt;br&gt;
    &lt;br&gt;
  );&lt;br&gt;
};&lt;br&gt;
The Recursive Layout&lt;br&gt;
Because the layout relies on a modern SaaS aesthetic, I used CSS Grid combined with a glassmorphism wrapper for the UI cards. The component is recursive—it calls itself if it detects children.

&lt;p&gt;JavaScript&lt;br&gt;
const RoadmapNode = ({ nodeId, data, toggleComplete }) =&amp;gt; {&lt;br&gt;
  const node = data[nodeId];&lt;br&gt;
  if (!node) return null;&lt;/p&gt;

&lt;p&gt;return (&lt;br&gt;
    &lt;/p&gt;
&lt;br&gt;
       toggleComplete(nodeId)}&amp;gt;&lt;br&gt;
        &lt;h3&gt;{node.title}&lt;/h3&gt;
&lt;br&gt;
      

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  {/* Recursively render children in a CSS Grid row */}
  {node.children.length &amp;gt; 0 &amp;amp;&amp;amp; (
    &amp;lt;div className="grid-children-container"&amp;gt;
      {node.children.map(childId =&amp;gt; (
        &amp;lt;RoadmapNode data={data} key={childId} nodeId={childId} toggleComplete={toggleComplete} /&amp;gt;
      ))}
    &amp;lt;/div&amp;gt;
  )}
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;);&lt;br&gt;
};&lt;br&gt;
Why This Works&lt;br&gt;
By flattening the state shape on the Node.js server before it ever hits the browser, React only has to execute shallow lookups. Combining this with CSS Grid allowed the visual tree to expand dynamically without requiring messy JavaScript height calculations.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>node</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Hardware is Messy: Building DravyaSense, an ESP32 IoT Purity Testing Pipeline</title>
      <dc:creator>Teja</dc:creator>
      <pubDate>Tue, 23 Jun 2026 09:29:27 +0000</pubDate>
      <link>https://dev.to/teja_7a39cf3c9baffdbdf100/hardware-is-messy-building-dravyasense-an-esp32-iot-purity-testing-pipeline-ed2</link>
      <guid>https://dev.to/teja_7a39cf3c9baffdbdf100/hardware-is-messy-building-dravyasense-an-esp32-iot-purity-testing-pipeline-ed2</guid>
      <description>&lt;p&gt;Building software is relatively predictable. Building IoT hardware pipelines that merge physical sensors with cloud-based machine learning is a complete nightmare of noisy data, dropped packets, and memory leaks.&lt;/p&gt;

&lt;p&gt;I recently built &lt;strong&gt;DravyaSense&lt;/strong&gt;, an IoT-based purity testing platform designed to evaluate herbal and chemical samples. The goal was to stream data from multiple physical sensors through an ESP32, pipe it into a cloud dashboard, and run an ML classification model to determine the purity of the sample in real-time.&lt;/p&gt;

&lt;p&gt;Here is the architecture I used to keep the ESP32 from crashing while maintaining a deterministic data stream.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hardware Constraint (ESP32)
&lt;/h2&gt;

&lt;p&gt;The ESP32 is incredibly powerful for its size, but if you try to read analog sensors, run a WiFi stack, and push MQTT messages all on a single synchronous loop, the watchdog timer will panic and reset the board.&lt;/p&gt;

&lt;p&gt;To solve this, I decoupled the sensor reading from the network transmission using a FIFO (First-In, First-Out) buffer and FreeRTOS tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Architecture
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Task 1 (Core 0):&lt;/strong&gt; Dedicated entirely to polling the multi-sensor array at a strict 1 kHz frequency. It pushes the raw telemetry into a thread-safe buffer.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Task 2 (Core 1):&lt;/strong&gt; Handles the WiFi connection, pulls data from the buffer, and publishes it to the cloud dashboard.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Sensor Polling Logic (C++)
&lt;/h3&gt;

&lt;p&gt;Here is a simplified look at how to handle the deterministic sensor reads without blocking the network layer:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
cpp
#include &amp;lt;freertos/FreeRTOS.h&amp;gt;
#include &amp;lt;freertos/task.h&amp;gt;
#include &amp;lt;freertos/queue.h&amp;gt;

QueueHandle_t sensorQueue;

// Structure to hold our multi-sensor payload
struct SensorData {
  float opticalDensity;
  float moistureLevel;
  uint32_t timestamp;
};

void readSensorsTask(void *pvParameters) {
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = pdMS_TO_TICKS(1); // 1 kHz loop

  while(true) {
    SensorData currentRead;
    // Simulate reading analog pins
    currentRead.opticalDensity = analogRead(34) * (3.3 / 4095.0);
    currentRead.moistureLevel = analogRead(35) * (3.3 / 4095.0);
    currentRead.timestamp = millis();

    // Push to the queue without blocking
    xQueueSend(sensorQueue, &amp;amp;currentRead, 0);

    // Ensure strict timing
    vTaskDelayUntil(&amp;amp;xLastWakeTime, xFrequency);
  }
}
The Cloud Pipeline &amp;amp; ML Classification
Once the ESP32 successfully packages the raw telemetry, it is pushed to a cloud dashboard. But raw voltage data is useless to an end user.

Instead of trying to run heavy TensorFlow Lite models directly on the ESP32 (which was eating up too much SRAM), I offloaded the inference to the cloud.

How the Pipeline Flows:
Ingestion: The ESP32 publishes the JSON payload to an MQTT broker.

Processing: A Node.js worker service subscribes to the MQTT topic, normalizes the noisy hardware data (applying a simple moving average filter), and stores it in a time-series database.

Inference: A Python backend running a pre-trained scikit-learn Random Forest model pulls the last 5 seconds of data and classifies the sample's purity percentage.

Dashboard: The React frontend updates in real-time, showing the live sensor graphs alongside the ML confidence score.

The Takeaway
When I first prototyped DravyaSense, I tried to do everything on the ESP32—reading, filtering, and classifying. It was a disaster.

The biggest lesson I learned in IoT architecture is to keep the edge device as "dumb" as possible. Let the microcontroller do what it does best (gathering raw electrical signals rapidly) and let the cloud handle the heavy mathematical lifting.
***

**Final Steps for this article:**
1. Copy and paste it into DEV.to.
2. Hit **Preview** to ensure the C++ code block looks clean.
3. Add a cover image if you have a photo of your ESP32 board or your DravyaSense dashboard!
4. **Publish!**

Once this is live, you will officially have three high-quality, deeply technical, and human-sounding articles. 

&amp;lt;FollowUp label="Ready for Draft.dev?" query="Let me know as soon as you hit publish on this third one, so we can go over exactly how to fill out the Draft.dev application to ensure you get accepted!"/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>iot</category>
      <category>esp32</category>
      <category>machinelearning</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Killing Latency: Wiring a Voice-Activated Cyber Triage Bot with Gemini and Deepgram</title>
      <dc:creator>Teja</dc:creator>
      <pubDate>Tue, 23 Jun 2026 09:25:18 +0000</pubDate>
      <link>https://dev.to/teja_7a39cf3c9baffdbdf100/killing-latency-wiring-a-voice-activated-cyber-triage-bot-with-gemini-and-deepgram-2o71</link>
      <guid>https://dev.to/teja_7a39cf3c9baffdbdf100/killing-latency-wiring-a-voice-activated-cyber-triage-bot-with-gemini-and-deepgram-2o71</guid>
      <description>&lt;p&gt;Typing out incident reports while a server is actively under attack is a massive waste of time. I wanted a way to triage network threats using just my microphone, so I built Aegis-Twin. &lt;/p&gt;

&lt;p&gt;Aegis-Twin is a voice-activated AI digital twin specifically engineered for cybersecurity triage. The concept is straightforward: I describe the anomaly out loud, the AI processes the threat context, and it speaks back immediate mitigation steps. &lt;/p&gt;

&lt;p&gt;To make this work without lag, I had to completely ditch standard REST APIs for the audio ingestion and wire together Deepgram, Google Gemini, and Murf AI. Here is how the actual pipeline looks under the hood.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Latency Problem (And Why REST Fails)
&lt;/h2&gt;

&lt;p&gt;If you try to record a WAV file, save it locally, POST it to a transcription API, wait for a response, and then send &lt;em&gt;that&lt;/em&gt; to an LLM, your bot is going to take 10 seconds to reply. In a SOC environment, that is useless.&lt;/p&gt;

&lt;p&gt;The only way to make conversational AI feel real is by using WebSockets to stream raw PCM audio chunks in real-time. &lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 1: Streaming Audio to Deepgram
&lt;/h2&gt;

&lt;p&gt;I used Deepgram for the speech-to-text layer because their WebSocket integration is incredibly fast. Instead of waiting for me to stop speaking, it transcribes the audio stream on the fly.&lt;/p&gt;

&lt;p&gt;Here is the core async connection loop using Python:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
python
import asyncio
from deepgram import DeepgramClient, LiveTranscriptionEvents, LiveOptions

async def stream_mic_audio():
    # Never hardcode this in production, grab it from your .env
    client = DeepgramClient("YOUR_DEEPGRAM_AFFILIATE_KEY")
    dg_connection = client.listen.live.v("1")

    # This fires the millisecond Deepgram detects a spoken word
    def on_transcript(self, result, **kwargs):
        sentence = result.channel.alternatives[0].transcript
        if sentence:
            print(f"Analyst Input: {sentence}")
            asyncio.run(trigger_gemini_reasoning(sentence))

    dg_connection.on(LiveTranscriptionEvents.TranscriptReceived, on_transcript)

    # nova-2 is currently their fastest model for tech jargon
    options = LiveOptions(model="nova-2", language="en-US")
    await dg_connection.start(options)

##  Phase 2: Constraining Google Gemini
import google.generativeai as genai

async def trigger_gemini_reasoning(threat_text):
    genai.configure(api_key="YOUR_GEMINI_API_KEY")

    # Force the LLM to act like a Tier 3 SOC Engineer
    system_rules = """
    You are a cybersecurity triage AI. 
    Do not use conversational filler. 
    Analyze the threat, state the severity, and output exactly two immediate mitigation steps.
    """

    model = genai.GenerativeModel(
        model_name="gemini-1.5-pro",
        system_instruction=system_rules
    )

    response = model.generate_content(threat_text)
    print(f"Aegis-Twin: {response.text}")
    return response.text

## Phase 3: Giving It a Voice with Murf AI
import requests

def speak_mitigation(triage_text):
    url = "[https://api.murf.ai/v1/speech/generate](https://api.murf.ai/v1/speech/generate)"
    headers = {
        "token": "YOUR_MURF_API_KEY",
        "Content-Type": "application/json"
    }
    # Using a crisp, professional voice model
    payload = {
        "voiceId": "en-US-marcus", 
        "text": triage_text
    }

    response = requests.post(url, json=payload, headers=headers)
    if response.status_code == 200:
        audio_url = response.json().get("audioUrl")
        # Pipe this URL to your system's audio output device

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>cybersecurity</category>
      <category>ai</category>
      <category>python</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
