<?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: Hrishikesh Dalal</title>
    <description>The latest articles on DEV Community by Hrishikesh Dalal (@hrishikesh_dalal_ced8f95e).</description>
    <link>https://dev.to/hrishikesh_dalal_ced8f95e</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%2F3564172%2F53b92bbb-b5a6-4a39-bbe0-b13f02839490.png</url>
      <title>DEV Community: Hrishikesh Dalal</title>
      <link>https://dev.to/hrishikesh_dalal_ced8f95e</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hrishikesh_dalal_ced8f95e"/>
    <language>en</language>
    <item>
      <title>Dawai-Dost: A Private, Local Medicine Companion</title>
      <dc:creator>Hrishikesh Dalal</dc:creator>
      <pubDate>Wed, 14 Oct 2026 14:06:50 +0000</pubDate>
      <link>https://dev.to/hrishikesh_dalal_ced8f95e/dawai-dost-a-private-local-medicine-companion-1oj2</link>
      <guid>https://dev.to/hrishikesh_dalal_ced8f95e/dawai-dost-a-private-local-medicine-companion-1oj2</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Dawai-Dost ("medicine friend") is a local-first app for families who look after elderly parents or grandparents. It does three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reads the prescription.&lt;/strong&gt; Photograph a doctor's handwritten or printed prescription. A vision-language model extracts each medicine, dose, timing and duration, and turns it into a simple daily schedule in English, Hindi or Marathi with large, readable text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remembers the history.&lt;/strong&gt; Every prescription, refill and reported symptom is stored in a small on-device database, so the app builds a medication timeline for each family member.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Predicts and flags, using that history.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Refill prediction: "Amlodipine runs out in 4 days. Order now."&lt;/li&gt;
&lt;li&gt;Missed-dose patterns: "Evening doses are missed 3 days out of 7."&lt;/li&gt;
&lt;li&gt;Change summaries: "This new prescription adds a medicine that was not in the last 3 visits."&lt;/li&gt;
&lt;li&gt;Interaction checks: it flags when two medicines from different doctors may clash, and tells you to confirm with a pharmacist.&lt;/li&gt;
&lt;li&gt;A one-page visit summary to hand to the doctor, so a 10-minute consultation is not spent trying to remember what changed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Who would pay: families with elderly parents, especially adult children living in a different city, and small pharmacies or clinics that want to offer a "prescription companion" to regular patients. The problem is real. Prescriptions are hard to read, parents take medicines from several doctors, and nobody has a clear view of the whole picture. A family would reasonably pay a small monthly fee, roughly the price of a single doctor consultation per year, for peace of mind.&lt;/p&gt;

&lt;p&gt;Safety note: Dawai-Dost is an assistant, not a doctor. Every output carries a "confirm with your doctor or pharmacist" notice, and low-confidence extractions are highlighted for human review instead of being guessed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;Core of the pipeline:&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ollama&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sqlite3&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;

&lt;span class="n"&gt;PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Read this prescription image. Return ONLY JSON:
{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medicines&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dose&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;times&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;morning|noon|night&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;],&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;days&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:0,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:0.0}]}
If text is unclear, lower the confidence. Never guess.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_prescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ollama&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen2.5vl:7b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PROMPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;images&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;image_path&lt;/span&gt;&lt;span class="p"&gt;]}])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medicines&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;meds&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;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;meds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;INSERT INTO rx(patient,name,dose,times,start,days) VALUES(?,?,?,?,?,?)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;patient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dose&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;times&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                    &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;days&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;refill_alerts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;within&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT name,start,days FROM rx WHERE patient=?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;patient&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: runs out &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromisoformat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromisoformat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;within&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;history_insight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patient&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;hist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT name,dose,start FROM rx WHERE patient=? ORDER BY start&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;patient&lt;/span&gt;&lt;span class="p"&gt;,)).&lt;/span&gt;&lt;span class="nf"&gt;fetchall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;q&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;Summarise changes across this medication history and flag possible interactions. Be cautious, advise confirming with a pharmacist: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hist&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ollama&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;llama3.1:8b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;}])[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&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;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Everything runs on the user's own machine or a small home server, with no cloud AI calls.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vision model: Qwen2.5-VL (open-weight), served with Ollama.&lt;/strong&gt; It reads the prescription photo and returns structured JSON. Each medicine gets a confidence score, and anything below a threshold is shown to the user as "please verify" rather than silently accepted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reasoning model: Llama 3.1 8B (open-weight), also via Ollama.&lt;/strong&gt; It writes the plain-language schedule in English, Hindi or Marathi, and turns the stored history into summaries and cautious interaction notes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage: SQLite.&lt;/strong&gt; One small file holds every prescription, refill and dose log.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prediction layer: simple, transparent logic.&lt;/strong&gt; Refill dates come from start date plus days supplied. Missed-dose patterns come from counting skipped reminders by time of day. I kept this rule-based on purpose. Predictions about health should be explainable, and the LLM only turns the numbers into readable language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interface: a lightweight web UI&lt;/strong&gt; with large fonts, plus an optional WhatsApp-style reminder flow for parents.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Design choice: the LLM never decides anything medical on its own. It extracts and explains. Dates and alerts come from deterministic code, and risky outputs always point the user back to a doctor or pharmacist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy is the product.&lt;/strong&gt; Prescriptions and medication history are some of the most sensitive data a family has. With open-weight models running locally, that data never leaves the device. With a closed API, every photo would be uploaded to someone else's servers. For a health tool, "your data stays on your machine" is the main reason people would trust and pay for it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The economics work.&lt;/strong&gt; A family uploads many prescription photos and gets daily summaries and reminders. Per-image and per-token API pricing would turn that into a recurring cost that grows with every user. Local inference has a flat cost, so a low monthly price still leaves a margin.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Niche fine-tuning.&lt;/strong&gt; Indian prescriptions are messy: abbreviations like "1-0-1", mixed English and Hindi, and doctor handwriting. Open weights can be fine-tuned on these patterns and on regional-language output, which a general-purpose closed API handles inconsistently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No lock-in.&lt;/strong&gt; If a model is deprecated or a vendor changes its pricing or policy, a health product built on it breaks. With open weights, I can swap in a better model, pin a version that is known to be reliable, and keep the app working for years.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works offline.&lt;/strong&gt; It still works in areas with poor connectivity, which matters for elderly users and smaller towns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

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

&lt;p&gt;None&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Where does my mind wonder?</title>
      <dc:creator>Hrishikesh Dalal</dc:creator>
      <pubDate>Fri, 09 Oct 2026 16:01:10 +0000</pubDate>
      <link>https://dev.to/hrishikesh_dalal_ced8f95e/where-does-my-mind-wonder-3ag2</link>
      <guid>https://dev.to/hrishikesh_dalal_ced8f95e/where-does-my-mind-wonder-3ag2</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Building an open source AI Powered, Social and Outing finder. Works without any net, so no matter where you are - ALWAYS HAS YOUR BACK! The best part about this is that it learns more about you as you interact with it. &lt;/p&gt;

&lt;p&gt;It is hyper-personalised so that more you interact with it more it knows about you, better it can recommend what you should do / go out for what mood.&lt;/p&gt;

&lt;p&gt;If you are sad -&amp;gt; Give you comforting places&lt;br&gt;
If you are energetic -&amp;gt; Recommends you outdoor activities as per your hobbies&lt;br&gt;
If its end of the month &amp;amp; you have a tight budget -&amp;gt; Recommends you pocket friendly options&lt;/p&gt;

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

&lt;p&gt;Couldn't get time to make a demo or a deployed link:(&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;Still in the building process, will update once completed!&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;The workflow goes like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Spatial Ingestion &amp;amp; Candidate Retrival &lt;br&gt;
We first fetch the geo-spatial co-ordinates from the users device. &lt;br&gt;
The client transmits (latitude, longitude) along with device state metadata. The backend executes a geospatial query fetching candidate POIs within a specified radius ($r$).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Semantic Context Synthesis&lt;br&gt;
After we have our candidate, we fetch the users past records. The candidate venues are merged with the users vector embeddings. A lightweight ranker scores candidate POIs based on proximity, ambient context (time of day, day of week), and user activity history.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inferenced Structured Generation&lt;br&gt;
Find the top-k spots and give our what the candidate actuals has based on the intersection of the user likings, mood, budget &amp;amp; location. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;User provides Feedback&lt;br&gt;
Simple thumbs up thumbs down to tell if the LLM has worked properly or not.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Used Gemma 4 for building this interface. Further used the SERP API to get the locations and the surrounds activities. Used Mongo DB for vector embeddings.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;People would only go out if there is something in it for them. This can be the activities that they like doing. If we give them something that is way difficult or requires a lot of extra effort without a reward then they won't do it.&lt;/p&gt;

&lt;p&gt;And why make this open source? &lt;/p&gt;

&lt;p&gt;More users can improve this and we can get to what we want to do for free rather than spending just to figure out what we want to do. Closed APIs would incur cost and that eventually comes down to the user.&lt;/p&gt;

&lt;p&gt;I love reading psychology too!&lt;/p&gt;

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

&lt;p&gt;None, I have not submitted code yet. Will update this when I submit the code.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Brutalist House: A 3D Spatial Wall &amp; Local AI Color Palette Inspector</title>
      <dc:creator>Hrishikesh Dalal</dc:creator>
      <pubDate>Fri, 02 Oct 2026 12:37:50 +0000</pubDate>
      <link>https://dev.to/hrishikesh_dalal_ced8f95e/brutalist-house-a-3d-spatial-wall-local-ai-color-palette-inspector-242e</link>
      <guid>https://dev.to/hrishikesh_dalal_ced8f95e/brutalist-house-a-3d-spatial-wall-local-ai-color-palette-inspector-242e</guid>
      <description>&lt;p&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;I built &lt;strong&gt;Brutalist House&lt;/strong&gt;—a local AI-powered interior color palette generator and interactive 3D spatial room inspector.&lt;/p&gt;

&lt;p&gt;I built this for a friend who is an interior design enthusiast and architect. They love brutalist architectural aesthetics—unprocessed concrete bases, raw functional zoning, and high-visibility accent pops—but constantly struggled to visualize how a 4-color palette translates onto actual 3D walls in a room. Plain HEX swatches on a flat screen just don't tell you how a room will &lt;em&gt;feel&lt;/em&gt; when light hits specific surfaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Brutalist House&lt;/strong&gt; solves this problem by taking local AI-generated color palettes (powered by &lt;strong&gt;Gemma 4 via Ollama&lt;/strong&gt;) and applying them directly across:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;An Interactive 3D Room Box Inspector:&lt;/strong&gt; View each room (Living Room, Bedroom, Kitchen, Bathroom) as an interactive 3D box. Rotate the camera along $X$ and $Y$ axes, inspect individual walls (&lt;strong&gt;North, East, South, West, and Floor&lt;/strong&gt;), and reassign specific colors to individual walls on the fly.&lt;/li&gt;
&lt;/ol&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%2Fogfmimt8tt9veptr0lte.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%2Fogfmimt8tt9veptr0lte.png" alt=" " width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A 2D Architectural Floorplan:&lt;/strong&gt; A high-contrast SVG plan view showing scale, room transitions, furniture accents, and door swings.&lt;/li&gt;
&lt;/ol&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%2F5m4al1l8u9gh8zywoug7.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%2F5m4al1l8u9gh8zywoug7.png" alt=" " width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Local Storage History:&lt;/strong&gt; Saves every generated palette and wall configuration locally so my friend can switch back and forth between design iterations with a single click.&lt;/li&gt;
&lt;/ol&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%2Ficj8p88rszgtd90f4ewj.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%2Ficj8p88rszgtd90f4ewj.png" alt=" " width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/Hrishikesh-Dalal/painting" rel="noopener noreferrer"&gt;Painting&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;Below is a snippet of how the &lt;strong&gt;3D Spatial Box&lt;/strong&gt; handles pure CSS 3D matrix transforms and per-wall color assignments without requiring heavy external 3D engine bundles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; 
  &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"relative w-[280px] h-[220px] transition-transform duration-300 ease-out"&lt;/span&gt;
  &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;transformStyle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preserve-3d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`rotateX(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tiltX&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;deg) rotateY(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rotationY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;deg)`&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* NORTH WALL */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; 
    &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nf"&gt;setSelectedWall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;north&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"absolute inset-0 border-4 flex flex-col items-center justify-center cursor-pointer"&lt;/span&gt;
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentRoomWalls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;north&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;borderColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;translateZ(-140px) rotateY(180deg)&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="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-xs font-black uppercase bg-white px-2 py-1 border border-black"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;NORTH WALL&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* FLOOR */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; 
    &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nf"&gt;setSelectedWall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;floor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"absolute w-[280px] h-[280px] border-4 flex flex-col items-center justify-center cursor-pointer"&lt;/span&gt;
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentRoomWalls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;borderColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;translateY(70px) rotateX(90deg)&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="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-xs font-black uppercase bg-white px-2 py-1 border border-black"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;FLOOR&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local Open-Weight AI Model:&lt;/strong&gt; Powered by &lt;strong&gt;Gemma 4&lt;/strong&gt; running locally through &lt;strong&gt;Ollama&lt;/strong&gt; (&lt;code&gt;/api/ollama&lt;/code&gt;). The model acts as the "brutalist design consultant," returning structured JSON containing color variables (&lt;code&gt;background&lt;/code&gt;, &lt;code&gt;primary&lt;/code&gt;, &lt;code&gt;secondary&lt;/code&gt;, &lt;code&gt;accent&lt;/code&gt;) and an architectural design rationale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend Framework:&lt;/strong&gt; Built with &lt;strong&gt;Next.js (App Router)&lt;/strong&gt;, &lt;strong&gt;TypeScript&lt;/strong&gt;, and &lt;strong&gt;Tailwind CSS&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3D Engine:&lt;/strong&gt; Implemented using pure CSS 3D transforms (&lt;code&gt;perspective&lt;/code&gt;, &lt;code&gt;preserve-3d&lt;/code&gt;, &lt;code&gt;rotateX&lt;/code&gt;, &lt;code&gt;rotateY&lt;/code&gt;, &lt;code&gt;translateZ&lt;/code&gt;) to deliver fluid 60FPS room rotations without adding heavy 3D library dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence Layer:&lt;/strong&gt; Integrated standard &lt;code&gt;localStorage&lt;/code&gt; pipelines so that custom wall color tweaks and past palette history persist seamlessly across sessions.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Local-First Privacy &amp;amp; Zero Vendor Lock-in:&lt;/strong&gt; Design concepts, room ideas, and creative prompts stay 100% on the user's local machine. Running open-weight models like Gemma 4 via Ollama ensures complete data ownership.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero API Costs &amp;amp; Unlimited Iteration:&lt;/strong&gt; Traditional proprietary APIs charge per token, making rapid palette generation and real-time prompt experimenting costly. Open-weight inference allows infinite generation cycles without rate limits or subscription paywalls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fine-Tuned Control:&lt;/strong&gt; Open models allow developers to inspect, fine-tune, and customize prompt structures directly, tailoring responses to niche aesthetic movements (like brutalism or minimalism) without closed-system alignment filters over-sanitizing creative output.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Build for a Friend&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Best Use of Local AI / Open Weights (Gemma &amp;amp; Ollama)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Drupal x Google Summer of Code - Week 3: Reuse &amp; Previews</title>
      <dc:creator>Hrishikesh Dalal</dc:creator>
      <pubDate>Tue, 07 Jul 2026 07:17:42 +0000</pubDate>
      <link>https://dev.to/hrishikesh_dalal_ced8f95e/drupal-x-google-summer-of-code-week-3-reuse-previews-1470</link>
      <guid>https://dev.to/hrishikesh_dalal_ced8f95e/drupal-x-google-summer-of-code-week-3-reuse-previews-1470</guid>
      <description>&lt;p&gt;&lt;strong&gt;WELLLLCOMMEE to Week 3 of this series!&lt;/strong&gt;&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%2Fvzrtddmyo94iok6led4w.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%2Fvzrtddmyo94iok6led4w.png" alt="Drupal x Google Summer of Code - Week 3: Reuse &amp;amp; Previews" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the last week made quite a few structural changes that will help us. Have created the YAML extractor and parser which can extract the YAML component form any response of the LLM using Symfony to validate it. Made a Utility for this thereby making the code reusable. &lt;/p&gt;

&lt;p&gt;Official Issue Tracker: &lt;a href="https://www.drupal.org/project/ai_recipe_generator/issues/3594062" rel="noopener noreferrer"&gt;Week 3 Tracker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me now give me glimpse for this. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=7sH6pv2Vyns" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=7sH6pv2Vyns&lt;/a&gt;&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%2Ftwko3jwu176a313bzl5c.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%2Ftwko3jwu176a313bzl5c.png" alt="The Output Preview &amp;amp; Validator" width="799" height="398"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The Output Preview &amp;amp; Validator&lt;/em&gt;&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%2Fffq0xwxjhvkkjt2fbalb.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%2Fffq0xwxjhvkkjt2fbalb.png" alt="UI Changes" width="800" height="243"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Tiny UI Changes&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Time to Dive Deep into this&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  YAML Validator &amp;amp; Extractor
&lt;/h2&gt;

&lt;p&gt;Created a Utility folder under src and created a file named Yaml Processor. The concept of this file was simple, when you get an output from LLM, from whichever Service or Function you pull this from this will extract the YAML and give it to you.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here it uses this : use Drupal\Component\Serialization\Yaml&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This under the hood uses Symfony which helps to validate and extraction.  Symfony is the underlying PHP framework that powers modern Drupal ( this is just one of the usecase)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Drupal\ai_recipe_generator\Utility&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Drupal\Component\Serialization\Yaml&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/**
 * Utility class to parse and extract YAML from AI responses.
 */&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;YamlProcessor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="cd"&gt;/**
   * Cleans a response down to YAML text when possible.
   *
   * @param string $response
   *   The raw model response.
   *
   * @return string
   *   A normalized YAML string or the response with code fences removed.
   */&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;extractAndParse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&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;is_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$parsed&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="nb"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Yaml&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$parsed&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$cleaned&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;preg_replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/```

(?:yaml|yml)?\s*|

```/i'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nv"&gt;$response&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;trim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$cleaned&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cd"&gt;/**
   * Attempts to extract and validate YAML from a given string.
   *
   * @param string $response
   *   The raw string response.
   *
   * @return array|null
   *   The parsed YAML as an array, or null if no valid YAML could be extracted.
   */&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;extractAndParse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;?array&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// First try parsing the entire response as YAML.&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nv"&gt;$parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Yaml&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&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;is_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$parsed&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="nv"&gt;$parsed&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;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;\Exception&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Not valid YAML, continue with extraction.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Extract YAML from markdown code blocks.&lt;/span&gt;
    &lt;span class="nv"&gt;$pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'/```

(?:yaml|yml)?\s*(.*?)

```/is'&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;preg_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$matches&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nv"&gt;$yaml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$matches&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;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Yaml&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$yaml&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;is_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$parsed&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="nv"&gt;$parsed&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;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;\Exception&lt;/span&gt; &lt;span class="nv"&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;return&lt;/span&gt; &lt;span class="kc"&gt;NULL&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="kc"&gt;NULL&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;
  
  
  Reusable YAML Previewer
&lt;/h2&gt;

&lt;p&gt;If you have seen my previous blog, the older YAML previewers they were not upto the mark. So improved that with having better parsers and lines. What I used for this was a template, using a html.twig format which helped to render properly anywhere, anyhow!&lt;/p&gt;

&lt;p&gt;This is slightly difficult to think and then implement (tedious slightly) but since highly reusable, highly useful!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{#
/**
 * @file
 * Template for the fluid YAML previewer component with line numbers.
 */
#}
&amp;lt;div class="ai-yaml-preview-container" {{ attributes }}&amp;gt;
  &amp;lt;div class="ai-yaml-preview-header"&amp;gt;
    &amp;lt;span class="ai-yaml-preview-title"&amp;gt;{{ title|default('YAML Output Preview') }}&amp;lt;/span&amp;gt;

    &amp;lt;button class="ai-yaml-copy-btn" onclick="
      const container = this.closest('.ai-yaml-preview-container');
      const code = container.querySelector('code').innerText;
      navigator.clipboard.writeText(code);
      const originalText = this.innerText;
      this.innerText = 'Copied!';
      setTimeout(() =&amp;gt; this.innerText = originalText, 2000);
    "&amp;gt;Copy YAML&amp;lt;/button&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div class="ai-yaml-preview-body"&amp;gt;
    {# This empty div will be filled with numbers by the JS below #}
    &amp;lt;div class="ai-yaml-line-numbers" aria-hidden="true"&amp;gt;&amp;lt;/div&amp;gt;

    &amp;lt;pre class="ai-yaml-preview-content"&amp;gt;&amp;lt;code class="language-yaml"&amp;gt;{{ yaml_string }}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

{# Inline script to generate line numbers based on the code length #}
&amp;lt;script&amp;gt;
  (function() {
    // Find all preview containers on the page
    const containers = document.querySelectorAll('.ai-yaml-preview-container');

    containers.forEach(container =&amp;gt; {
      const codeBlock = container.querySelector('code');
      const linesContainer = container.querySelector('.ai-yaml-line-numbers');

      // Only process if it hasn't been filled yet
      if (codeBlock &amp;amp;&amp;amp; linesContainer &amp;amp;&amp;amp; linesContainer.innerHTML === '') {
        // Split by newline to get total lines
        const lines = codeBlock.innerText.split('\n');

        // Handle the case where the AI leaves a trailing empty line at the end
        const lineCount = lines[lines.length - 1] === '' ? lines.length - 1 : lines.length;

        let numbersHTML = '';
        for (let i = 1; i &amp;lt;= Math.max(1, lineCount); i++) {
          numbersHTML += i + '&amp;lt;br&amp;gt;';
        }
        linesContainer.innerHTML = numbersHTML;
      }
    });
  })();
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Code Reduction
&lt;/h2&gt;

&lt;p&gt;Let's understand the problem, we had 3 files for calling the LLM models &amp;amp; providers. All of them had separate functions. So if I ever wanted to change anything, I would have to change in all the three files : (&lt;/p&gt;

&lt;p&gt;So we changed the calling part. for 2 (ArenaService &amp;amp; RecipeGenerationService) of them as they were the same replicas the third one at BenchmarkDashboardService was a different one. Clubbing them was fairly simple, just had to change the function calls. &lt;/p&gt;

&lt;h2&gt;
  
  
  Started fixing the Pipeline
&lt;/h2&gt;

&lt;p&gt;Did the cspell checking and then the phpcs checking which was initially failing but then started fixing the same. For fixing the cspell introduced a file called: .cspell.json. This needed to have all the words in the document which I wanted to exclude form the checking.&lt;/p&gt;

&lt;p&gt;Will write a separate blog on testing!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"words"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"ai_recipe_generator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"chartjs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"crosshairs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"dalal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"fontawesome"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"hrishikesh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"llm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"llms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"multichat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"onclick"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Starshot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"tempstore"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"unconfigured"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  
        &lt;/span&gt;&lt;span class="s2"&gt;"xaxis"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"xmark"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"yaml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"yaxis"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ignorePaths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"vendor/**"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"node_modules/**"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"*.min.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"*.min.css"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Thank you &amp;amp; catch you up next time!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Follow me at &lt;a href="https://www.linkedin.com/in/hrishikeshdalal/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/hrishikeshdalal/&lt;/a&gt;&lt;br&gt;
Portfolio: &lt;a href="https://www.hrishikeshdalal.dev/" rel="noopener noreferrer"&gt;https://www.hrishikeshdalal.dev/&lt;/a&gt;&lt;br&gt;
Alt Portfolio: &lt;a href="https://hrishikesh-dalal.vercel.app/" rel="noopener noreferrer"&gt;https://hrishikesh-dalal.vercel.app/&lt;/a&gt;&lt;/em&gt;&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%2Fdgmgzs340ww1xy4cdl3b.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%2Fdgmgzs340ww1xy4cdl3b.png" alt="Image" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Google Summer of Code (GSoC) x Drupal: Week 2 - Mapping the Dashboards</title>
      <dc:creator>Hrishikesh Dalal</dc:creator>
      <pubDate>Tue, 07 Jul 2026 07:09:11 +0000</pubDate>
      <link>https://dev.to/hrishikesh_dalal_ced8f95e/google-summer-of-code-gsoc-x-drupal-week-2-mapping-the-dashboards-3gm1</link>
      <guid>https://dev.to/hrishikesh_dalal_ced8f95e/google-summer-of-code-gsoc-x-drupal-week-2-mapping-the-dashboards-3gm1</guid>
      <description>&lt;p&gt;&lt;strong&gt;WELCOMMMEEEE to another episode of Weekly Recap of my project&lt;/strong&gt;&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%2F2qqxl6lvq6y3h48xi3hd.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%2F2qqxl6lvq6y3h48xi3hd.png" alt="Google Summer of Code (GSoC) x Drupal: Week 2 - Mapping the Dashboards" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This week we have built two things: LLM Benchmarking Dashboard &amp;amp; LLM Arena to show you which ones are the best. Both of these will be super useful while building our final product. &lt;/p&gt;

&lt;p&gt;The Offical Issue Tracker: &lt;a href="https://www.drupal.org/project/ai_recipe_generator/issues/3593030" rel="noopener noreferrer"&gt;Week 2 Issues Tackled&lt;/a&gt;&lt;br&gt;
Let me give you a glipmse of what our output will look like. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=FWhz2f81urQ" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=FWhz2f81urQ&lt;/a&gt;&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%2F8vr14yqiu8oeacjc7g59.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%2F8vr14yqiu8oeacjc7g59.png" alt="Dashboard" width="800" height="373"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Dashboard (Part 1)&lt;/em&gt;&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%2Fcwcze542104arp0lbd5s.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%2Fcwcze542104arp0lbd5s.png" alt="Dashboard " width="800" height="227"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Dashboard (Part 2)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;The Benchmarking Dashboard&lt;/h2&gt;

&lt;p&gt;In order to capture the true essence of which model performs the best in the long run, had made a LLM benchmarking dashboard. Someone just by looking at charts can capture which model is most suitable for their usecase. &lt;/p&gt;

&lt;blockquote&gt;Metrics that provided the overall picture&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;1). The Top Banner&lt;/strong&gt;: It had the total runs so far, along with the average response time and the average accuracy for the recipe generated. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2). The Visuals&lt;/strong&gt;: Any dashboard is incomplete without a good visual. The first graph which shows the latency for the previous runs mapped across models is useful for finding the trend for model hits. The second graph is for using a bar graph for visualising the model avg. latency to compare which model is the faster as compared to others. Used the Chart module for the same. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3). Key Metric Table&lt;/strong&gt;: This is the detailed table for per prompt summary. It covers: &lt;em&gt;the provider, the model, the speed, whether the YAML is valid or not, whether the Schema proper or not as per Drupal Symfony, &amp;amp; finally tells us about the accuracy along with timestamps&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;What is useful in this is that you can filter it along with sort the columns in ascending or descending order. Is if further &lt;strong&gt;colour coded&lt;/strong&gt; so that you can quickly view the page at a glance. &lt;/p&gt;

&lt;p&gt;Things I used to build this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Chart.js / Drupal Chart Module: To render the responsive, interactive graphs.&lt;/li&gt;
  &lt;li&gt;Custom Database Schema (.install): To reliably save and query the historical benchmarking data.&lt;/li&gt;
  &lt;li&gt;Drupal AJAX API: To ensure the table filters and dynamic sorting update seamlessly.&lt;/li&gt;
  &lt;li&gt;Font Awesome Library: To have cool icons in the dashboard&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdo14az3kn9qrvytfe20d.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%2Fdo14az3kn9qrvytfe20d.png" alt="LLM Arena" width="799" height="361"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;LLM Arena&lt;/em&gt;&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%2Fa23sqqh0y4cu1vg1o6nh.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%2Fa23sqqh0y4cu1vg1o6nh.png" alt="Image" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;The LLM Arena &lt;/h2&gt;

&lt;p&gt;This was particularly fun to build as this was for comparing the different responses. You get to type the custom prompt and then fire it across all the different models and providers. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can have all the different models &amp;amp; providers, there is NO LIMIT!!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Further these is also an option to store the responses in the database so that they reflected in the schema. There is also a delete button for the same. If you want to remove some model-provider.  Further you will see a very familiar screen that, while firing the prompts, it will look like new module install screen, this is because of the Batch API Screen. &lt;/p&gt;

&lt;p&gt;Sources I used:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;AJAX API: Model - Provider dropdown&lt;/li&gt;
  &lt;li&gt;Batch API: For firing all the prompts together&lt;/li&gt;
  &lt;li&gt;Font Awesome Icons: For the icons there&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Laying out the Structure&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%2Ft8y7ekszmugr4zoncdie.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%2Ft8y7ekszmugr4zoncdie.png" alt="System Diagram" width="800" height="386"&gt;&lt;/a&gt;&lt;br&gt;
*System Diagram *&lt;/p&gt;

&lt;p&gt;Just like a good Drupal Practice (have to mention), have used AI to generate the image above. &lt;/p&gt;

&lt;h3&gt;
  
  
  1. Client (User Browser) Layer
&lt;/h3&gt;

&lt;p&gt;Handles the user interface and visual presentation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User (Arena/Dashboard Interface):&lt;/strong&gt; Renders the comparison forms, interactive data tables, and metrics dashboards.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frontend Components:&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript:&lt;/strong&gt; Uses &lt;code&gt;Chart.js&lt;/code&gt; to render interactive line and bar charts for model latency trends.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Icons:&lt;/strong&gt; Integrates &lt;strong&gt;Font Awesome&lt;/strong&gt; for immediate visual cues (success/failure statuses).&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CSS:&lt;/strong&gt; Uses &lt;code&gt;css/arena.css&lt;/code&gt; and &lt;code&gt;css/dashboard.css&lt;/code&gt; via &lt;code&gt;.libraries.yml&lt;/code&gt; for custom, polished layouts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Client-Server Communication:&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AJAX API:&lt;/strong&gt; Controls non-blocking form updates, dynamic filtering, and column sorting without page reloads.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Batch API (Client-Side):&lt;/strong&gt; Drives the real-time progress bar (similar to the module installation screen) during execution.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Drupal Application Logic Layer
&lt;/h3&gt;

&lt;p&gt;The PHP backend that processes requests and orchestrates module logic.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Form API (&lt;code&gt;ArenaForm.php&lt;/code&gt;, &lt;code&gt;BenchmarkDashboardForm.php&lt;/code&gt;):&lt;/strong&gt; Handles form submissions and handles backend execution triggers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Services Layer (&lt;code&gt;ArenaService.php&lt;/code&gt;, &lt;code&gt;BenchmarkDashboardService.php&lt;/code&gt;):&lt;/strong&gt; Houses decoupled, reusable core logic registered via &lt;code&gt;ai_recipe_generator.services.yml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API Integration Engine:&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drupal Batch API:&lt;/strong&gt; Splits concurrent LLM requests into isolated chunks to prevent gateway timeouts and server lockups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drupal AJAX API:&lt;/strong&gt; Manages seamless, lightweight data passing between backend services and frontend components.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Data &amp;amp; External Integrations Layer
&lt;/h3&gt;

&lt;p&gt;Manages persistent storage and outbound network requests.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local Database (&lt;code&gt;.install&lt;/code&gt;):&lt;/strong&gt; Uses a custom schema defined in the install file to save historical run stats, latency, timestamps, and schema validation flags.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;External LLM APIs:&lt;/strong&gt; Handles outbound calls to external models (OpenAI, Anthropic, Gemini). Isolated by the Batch API so a timeout on one provider doesn't crash the session.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Thanks a lot for reading!!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Follow me at &lt;a href="https://www.linkedin.com/in/hrishikeshdalal/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/hrishikeshdalal/&lt;/a&gt;&lt;br&gt;
Portfolio: &lt;a href="https://www.hrishikeshdalal.dev/" rel="noopener noreferrer"&gt;https://www.hrishikeshdalal.dev/&lt;/a&gt;&lt;br&gt;
Alt Portfolio: &lt;a href="https://hrishikesh-dalal.vercel.app/" rel="noopener noreferrer"&gt;https://hrishikesh-dalal.vercel.app/&lt;/a&gt;&lt;/em&gt;&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%2Fai0xgwt4923adg70r2ku.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%2Fai0xgwt4923adg70r2ku.png" alt="Image" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Drupal x GSoC: Week 1 - Building the Base</title>
      <dc:creator>Hrishikesh Dalal</dc:creator>
      <pubDate>Tue, 07 Jul 2026 07:02:24 +0000</pubDate>
      <link>https://dev.to/hrishikesh_dalal_ced8f95e/drupal-x-gsoc-week-1-building-the-base-42j9</link>
      <guid>https://dev.to/hrishikesh_dalal_ced8f95e/drupal-x-gsoc-week-1-building-the-base-42j9</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fslqp63w9cio97mfh71kh.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%2Fslqp63w9cio97mfh71kh.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WELLLLLLCOMMEE To Week 1 of GSoC x Drupal.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Over the first week my focus was on establishing a proper base for the project. This was particularly fun as you can see your project come to life. These are some other chapters of the journal that you should definitely read!&lt;/p&gt;

&lt;p&gt;I created a project: &lt;a href="https://blog.hrishikeshdalal.dev/drupal/6a1bbb83a9efe6ea5bb97c16" rel="noopener noreferrer"&gt;Creating a Module Project on Drupal (NO CODE) (With BONUS Section)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I learnt about &lt;a href="https://blog.hrishikeshdalal.dev/drupal/6a200d7d5f3958f4a28782d7" rel="noopener noreferrer"&gt;PIRLS - Drupal's Core .yml files&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before you proceed any further, you should have a drupal project set up. If not, you can check it out here: &lt;a href="https://blog.hrishikeshdalal.dev/drupal/6a21075f8d7f810de39a3084" rel="noopener noreferrer"&gt;Installing Drupal&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have added a bit more changes too, you can check it our here: &lt;a href="https://www.drupal.org/project/ai_recipe_generator/issues/3592993" rel="noopener noreferrer"&gt;Week 1 Official Tracker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=2IcKTPBoyqc" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=2IcKTPBoyqc&lt;/a&gt;&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%2Ftw9hzzj8mhquyx32nq3z.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%2Ftw9hzzj8mhquyx32nq3z.png" alt="Week 1 Issues Tackled" width="800" height="584"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Week 1 Issues Tackled&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let's zoom out and see what we have built. UI might not be that great yet but that was not the focus of the first week.&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%2Fmj3q8uclbo561nfyv65w.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%2Fmj3q8uclbo561nfyv65w.png" alt="Image" width="799" height="344"&gt;&lt;/a&gt;&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%2Fe6juxkb1aeeooa67flfi.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%2Fe6juxkb1aeeooa67flfi.png" alt="Image" width="799" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should clone the basic repo of the module and paste it in: &lt;strong&gt;web/modules/custom/ai_recipe_generator&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You might need to create this folder &amp;amp; add all the files. We use custom as we haven't made a deployment of the project yet. So once I did this I made. Now I have added ai_recipe_generator.info.yml, ai_recipe_generator_services.yml, ai_recipe_generator.routing.yml. I have made a blog on these files and what do these mean, you can check that out too. &lt;/p&gt;

&lt;p&gt;I then created 2 things in src folder - Form &amp;amp; Services. &lt;/p&gt;

&lt;p&gt;So we have two pages as you saw above. Let's understand the routing or the file urls&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%2Fvekze81htm1fkxxh7h0w.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%2Fvekze81htm1fkxxh7h0w.png" alt="Our File Structure" width="358" height="357"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Our File Structure&lt;/em&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;ai_recipe_generator.test_form&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/admin/config/development/ai-recipe-test'&lt;/span&gt;
  &lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;_form&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\Drupal\ai_recipe_generator\Form\RecipeGeneratorTestForm'&lt;/span&gt;
    &lt;span class="na"&gt;_title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AI&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Recipe&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Generator&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(Test&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;UI)'&lt;/span&gt;
  &lt;span class="na"&gt;requirements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;_permission&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;administer&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;site&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;configuration'&lt;/span&gt;

&lt;span class="na"&gt;ai_recipe_generator.settings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/admin/config/ai-recipe/settings'&lt;/span&gt;
  &lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;_form&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\Drupal\ai_recipe_generator\Form\SettingsForm'&lt;/span&gt;
    &lt;span class="na"&gt;_title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AI&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Recipe&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Generator&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Settings'&lt;/span&gt;
  &lt;span class="na"&gt;requirements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;_permission&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;administer&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;site&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;configuration'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each entry has the following&lt;/p&gt;

&lt;p&gt;1 The URL Path&lt;/p&gt;

&lt;p&gt;2 The Form File which it should render&lt;/p&gt;

&lt;p&gt;3 The title of the Page&lt;/p&gt;

&lt;p&gt;4 Permission Requirements&lt;/p&gt;




&lt;p&gt;We have dependecies as well. This module as of now depends on the AI Module, Gemini Provider Module as well as the Key Module for managing all the keys. You have to install and enable all these modules for the AI Recipe Generator to function. This is actually cool as we are using the Drupal Ecosystem to do our tasks. &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%2Frtj68z9opl2a8jtmfooc.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%2Frtj68z9opl2a8jtmfooc.png" alt="Flow Diagram" width="799" height="436"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Flow Diagram&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 1: The Setup (Settings Form)
&lt;/h3&gt;

&lt;p&gt;Before a user can generate a recipe, an administrator sets the rules.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Setting the Ground Rules:&lt;/strong&gt; An admin visits the "AI Recipe Generator Settings" form and enters the &lt;strong&gt;System Instructions&lt;/strong&gt; (e.g., "You are a senior Drupal developer...").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Saving to the Database:&lt;/strong&gt; When the admin clicks "Save configuration," Drupal uses its configuration service (&lt;code&gt;@config.factory&lt;/code&gt;) to safely store these instructions in the database for later use.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Phase 2: The User Request (Test UI Form)
&lt;/h3&gt;

&lt;p&gt;This is where the actual generation happens.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;User Input:&lt;/strong&gt; A user opens the "AI Recipe Generator (Test UI)" form. They select their preferred &lt;strong&gt;AI Provider&lt;/strong&gt; (like Gemini) and type exactly what they want to build into the &lt;strong&gt;Recipe Prompt&lt;/strong&gt; box.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Triggering the AJAX Call:&lt;/strong&gt; The user clicks the &lt;strong&gt;Generate Recipe&lt;/strong&gt; button. Instead of reloading the whole webpage, the browser sends a quiet, background message (an &lt;strong&gt;AJAX Request&lt;/strong&gt;) to the Drupal server containing the user's prompt and their chosen AI provider.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Phase 3: The Backend Brain (Drupal Services)
&lt;/h3&gt;

&lt;p&gt;Once Drupal receives the AJAX request, it hands the work over to the custom services defined in your &lt;code&gt;.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Gathering the Pieces:&lt;/strong&gt; The main service (&lt;code&gt;RecipeGenerationService&lt;/code&gt;) goes to work collecting three crucial pieces of information:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Rules:&lt;/strong&gt; It pulls the saved "System Instructions" using &lt;code&gt;@config.factory&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Context:&lt;/strong&gt; It asks the &lt;code&gt;ContextExtractor&lt;/code&gt; service to pull any relevant background information about your specific Drupal site.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Request:&lt;/strong&gt; It takes the user's specific "Recipe Prompt" from the AJAX call.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Talking to the AI:&lt;/strong&gt; The &lt;code&gt;RecipeGenerationService&lt;/code&gt; combines the rules, the context, and the user's request into one massive prompt. It then uses the &lt;code&gt;@ai.provider&lt;/code&gt; service to send this combined package over the internet to the external AI (e.g., Gemini).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Phase 4: The Result (AJAX Response)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Receiving the Recipe:&lt;/strong&gt; The external AI processes the prompt, generates the Starshot Recipe YAML file, and sends it back to your Drupal server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Updating the Screen:&lt;/strong&gt; Drupal packages this generated recipe into an &lt;strong&gt;AJAX Response&lt;/strong&gt; and sends it back to the user's browser. The browser reads this response and instantly displays the new recipe on the screen, completing the process without ever forcing the user to refresh the page.&lt;/li&gt;
&lt;/ol&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%2Focku72hoj511sb35xrd4.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%2Focku72hoj511sb35xrd4.png" alt="Image" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Adding your first piece of code to Drupal Project!</title>
      <dc:creator>Hrishikesh Dalal</dc:creator>
      <pubDate>Tue, 09 Jun 2026 02:33:54 +0000</pubDate>
      <link>https://dev.to/hrishikesh_dalal_ced8f95e/adding-your-first-piece-of-code-to-drupal-project-4925</link>
      <guid>https://dev.to/hrishikesh_dalal_ced8f95e/adding-your-first-piece-of-code-to-drupal-project-4925</guid>
      <description>&lt;p&gt;Setting up the codebase on Drupal is &lt;strong&gt;EASY!&lt;/strong&gt; Only you need a little bit of patience. Let's dive deep into it.&lt;/p&gt;

&lt;p&gt;So previously we had set up a project. Now we are going to initialise the git repo and add a few changes. First if you have created your project, you can move on into the Version Control section. This will contain instructions of what we should do further. &lt;/p&gt;

&lt;p&gt;This was my link: &lt;a href="https://www.drupal.org/project/ai_recipe_generator/git-instructions" rel="noopener noreferrer"&gt;Version Control&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Ai0n_9vG_Ig"&gt;
  &lt;/iframe&gt;
&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%2Fmfwhwyadarhlv2g8g63q.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%2Fmfwhwyadarhlv2g8g63q.png" alt="Version Control " width="543" height="61"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Version Control&lt;/em&gt;&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="nb"&gt;mkdir &lt;/span&gt;ai_recipe_generator

&lt;span class="nb"&gt;cd &lt;/span&gt;ai_recipe_generator

git init

git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; 1.0.x

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"AI Recipe Generator"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; README.txt

git add README.txt

git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Initial commit."&lt;/span&gt;

git remote add origin git@git.drupal.org:project/ai_recipe_generator.git

git push origin 1.0.x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They are the explicit instructions of what we are going to do.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Copying without understanding is useless. Let's go through each step one by one. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Why we do it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;mkdir ai_recipe_generator&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Creates a new directory named &lt;code&gt;ai_recipe_generator&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;Allocates a dedicated local space for your project files.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;cd ai_recipe_generator&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Moves your terminal path into the new folder.&lt;/td&gt;
&lt;td&gt;Ensures all future commands execute inside the project context.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;git init&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Initializes a hidden local &lt;code&gt;.git&lt;/code&gt; repository.&lt;/td&gt;
&lt;td&gt;Turns the plain folder into a version-controlled project.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;git checkout -b 1.0.x&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Creates and switches to a new branch named &lt;code&gt;1.0.x&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;Bypasses standard &lt;code&gt;main&lt;/code&gt;/&lt;code&gt;master&lt;/code&gt; to match Drupal's release branch rules.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;echo "AI..." &amp;gt; README.txt&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Generates a &lt;code&gt;README.txt&lt;/code&gt; file with project text.&lt;/td&gt;
&lt;td&gt;Creates an initial asset to track, as Git cannot track empty folders.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;git add README.txt&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stages the file to the Git index.&lt;/td&gt;
&lt;td&gt;Explicitly marks the new file to be included in the next snapshot.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;git commit -m "Text"&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Saves the staged file with a historic log message.&lt;/td&gt;
&lt;td&gt;Establishes the official baseline/first snapshot of your codebase.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;git remote add origin &amp;lt;url&amp;gt;&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Links your local Git setup to the Drupal.org repository.&lt;/td&gt;
&lt;td&gt;Establishes the secure target destination path on Drupal's servers.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;git push origin 1.0.x&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Uploads the local branch and commit to the server.&lt;/td&gt;
&lt;td&gt;Publishes your code online so your mentors can access and review it.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Post this we had committed 3 more files of out own, which are equally crucial for the module development. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1 ai_recipe_generator.module.info&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2 composer.json&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3 .gitignore&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Resources&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Module Creation &amp;amp; .info.yml Documentation
&lt;a href="https://www.drupal.org/docs/develop/creating-modules" rel="noopener noreferrer"&gt;Creating Custom Modules (Main Hub):&lt;/a&gt; This is the central landing page for all module development tutorials in modern Drupal, covering everything from routing to creating custom blocks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://www.drupal.org/docs/develop/creating-modules/let-drupal-know-about-your-module-with-an-infoyml-file" rel="noopener noreferrer"&gt;Defining the .info.yml File:&lt;/a&gt; This page provides the exact specifications, required properties, and core version requirement syntax for your module's metadata.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Composer Documentation for Modules
&lt;a href="https://www.drupal.org/docs/develop/using-composer/add-a-composerjson-file" rel="noopener noreferrer"&gt;Adding a composer.json File to a Module:&lt;/a&gt; This explains exactly why and how to add a composer.json file to your custom or contributed module, including the composer init steps specifically tailored for Drupal package types.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AI Recipe Generator&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Creates recipes using AI.&lt;/span&gt;
&lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AI&lt;/span&gt;

&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;module&lt;/span&gt;
&lt;span class="na"&gt;core_version_requirement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^10.5 || ^11.2&lt;/span&gt;

&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ai:ai&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"drupal/ai_recipe_generator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Creates recipes using AI."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"drupal-module"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"license"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GPL-2.0-or-later"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"authors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hrishikesh Dalal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"204620-hrishikesh-dalal@users.noreply.drupalcode.org"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"require"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;h3&gt;Somewhere where I struggled and made mistakes&lt;/h3&gt;

&lt;p&gt;If you have seen the video, you would know I had made a mistake initializing the git repo 😅. I made a commit to the main brand before setting up the 1.0.x which is crucial for creating forks and deployments.  Well it sucked but it was a great source of learning. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding the Concept of Remote in Git&lt;/strong&gt;&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%2Fefm52xs06acv0kvzl2wi.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%2Fefm52xs06acv0kvzl2wi.png" alt="Git Remote" width="799" height="436"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Git Remote&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Think of Git &lt;strong&gt;Remotes&lt;/strong&gt; as a &lt;strong&gt;Cloud Backup or a Shared Office.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine you are writing a book on your own private desk at home (&lt;strong&gt;Local Repository&lt;/strong&gt;). You can write, delete, and organize pages however you want.&lt;/p&gt;

&lt;p&gt;However, your publisher and co-authors are in a different building. To show them your work, you have a &lt;strong&gt;Shared Drafting Table&lt;/strong&gt; (&lt;strong&gt;Remote Repository&lt;/strong&gt;) in their office.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. A "Remote":&lt;/strong&gt; It's just a bookmark or a "saved contact" in your computer's address book that tells Git exactly where that Shared Table is located on the internet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Origin:&lt;/strong&gt; This is just the default nickname for that Shared Table. (But you could call it anything, backup, publish etc)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Managing Remotes: The Commands&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sometimes you need to change where your code is going (e.g., commit to a different fork or repository).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Check your current remotes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before changing anything, see where your project is currently "talking" to.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The &lt;code&gt;-v&lt;/code&gt; stands for "verbose." It shows you the URLs for fetching (downloading) and pushing (uploading).&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Change a remote's URL&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the server location changes, but you want to keep the same nickname (&lt;code&gt;origin&lt;/code&gt;), use this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote set-url origin https://git.drupalcode.org/issue/ai_recipe_generator-3592994.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Use this if you accidentally typed the wrong URL during setup or if the project moved to a new server.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;3. Add a second remote&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can have more than one! You might have one for a private backup and one for the public Drupal project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add backup https://git.drupalcode.org/issue/ai_recipe_generator-000001.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Rename a remote&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you don't like the name &lt;code&gt;origin&lt;/code&gt; and want to call it something else: (here drupal_server)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;remote&lt;/span&gt; &lt;span class="nx"&gt;rename&lt;/span&gt; &lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="nx"&gt;drupal_server&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Remove a remote&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to cut ties with a specific server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;remote&lt;/span&gt; &lt;span class="nx"&gt;remove&lt;/span&gt; &lt;span class="nx"&gt;backup&lt;/span&gt;

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro-Tip:&lt;/strong&gt; If you ever get an error saying "Remote origin already exists," it means your project is already linked to a server. Use &lt;code&gt;set-url&lt;/code&gt; to update it instead of &lt;code&gt;add&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;Eventually....&lt;/h1&gt;

&lt;p&gt;So after taking a short detour, we finally pushed our initial code to gitlab! 🎉🎉&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%2Fqpfq34xvy9xi9l6j569k.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%2Fqpfq34xvy9xi9l6j569k.png" alt="Final Code Push" width="800" height="337"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Final Code Push&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Follow me: &lt;a href="https://www.linkedin.com/in/hrishikeshdalal/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/hrishikeshdalal/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My portfolio: &lt;a href="https://hrishikeshdalal.tech/" rel="noopener noreferrer"&gt;https://hrishikeshdalal.tech/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>drupal</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Creating a Module Project on Drupal (NO CODE) (With BONUS Section)</title>
      <dc:creator>Hrishikesh Dalal</dc:creator>
      <pubDate>Mon, 08 Jun 2026 07:51:00 +0000</pubDate>
      <link>https://dev.to/hrishikesh_dalal_ced8f95e/creating-a-module-project-on-drupal-no-code-with-bonus-section-19ld</link>
      <guid>https://dev.to/hrishikesh_dalal_ced8f95e/creating-a-module-project-on-drupal-no-code-with-bonus-section-19ld</guid>
      <description>&lt;p&gt;Hey there!&lt;/p&gt;

&lt;p&gt;Welcome to my GSoC journey where in I am going to take you through an adventure of events. This blog is for the Level 1. Or rather I should saying learning about how to "make the dish". We are going to create our very own Drupal Module Project!! &lt;/p&gt;

&lt;p&gt;I will also append a Youtube link for the same if it does suit you better. Lets get into it!&lt;/p&gt;

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

&lt;h1&gt;Step 1: Understanding what all types of Projects you can create&lt;/h1&gt;

&lt;p&gt;When you head over to this site for project creation - &lt;a href="https://www.drupal.org/docs/develop/managing-a-drupalorg-theme-module-or-distribution-project/creating-a-new-project/how-to-create-a-new-project" rel="noopener noreferrer"&gt;Drupal Project Create&lt;/a&gt;. You will have 4 options. &lt;/p&gt;

&lt;p&gt;Drupal offers a few different project types:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Module project:&lt;/strong&gt; Contains PHP code that extends Drupal or adds new features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Theme project:&lt;/strong&gt; Changes the look and feel of a Drupal site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. General project:&lt;/strong&gt; Contains code, but isn't a module, theme, or specific type.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Community project&lt;/strong&gt;: Non-code projects used to manage groups or camps.&lt;/p&gt;

&lt;p&gt;Since our aim is to build an AI Recipe Generator that adds brand-new functionality to the site, selecting the Module project was the clear choice.&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%2Fvftwa2c27lhy8jr3yap3.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%2Fvftwa2c27lhy8jr3yap3.png" alt="Types of Drupal Projects" width="800" height="715"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Types of Drupal Projects&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;Step 2: Have Git on your computer&lt;/h1&gt;

&lt;p&gt;The absolute bare minimum as all the code changes everything should be done by this. But if you reading this and are a techie, you must already be having git : )&lt;/p&gt;

&lt;h1&gt;Step 3: Creating a project&lt;/h1&gt;

&lt;p&gt;Now when you go over this link: &lt;a href="https://www.drupal.org/project/add" rel="noopener noreferrer"&gt;Project Creation&lt;/a&gt;, you will have a ton of options. Let us go through each one of them one by one. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Drupal core:&lt;/strong&gt; The foundational software that runs the entire Drupal platform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distribution project:&lt;/strong&gt; An all-in-one starter kit that bundles Drupal with pre-selected features to quickly launch a specific type of website.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community project:&lt;/strong&gt; An organizational space for managing Drupal groups, events, and people rather than website code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;General project:&lt;/strong&gt; A catch-all category for miscellaneous code, tools, and libraries that don't fit into the standard module or theme categories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Module project:&lt;/strong&gt; A functional plugin that adds new features or changes how your website works.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theme project:&lt;/strong&gt; The design package that controls the colors, layout, and overall visual appearance of your website.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theme Engine project:&lt;/strong&gt; The behind-the-scenes system that translates your theme's visual design into something the Drupal platform can understand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Translation project:&lt;/strong&gt; An outdated archive for language translations, which are now managed on a separate, dedicated website.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Step 4: The Nitty Gritties&lt;/h1&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%2Fos0m02myzor9cehi2710.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%2Fos0m02myzor9cehi2710.png" alt="All Changes" width="799" height="436"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;All the things you can do in a snap&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now when you go to the next page, there is this huge form that you need to fill. Let me take you across each filed one by one.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Basic Identity
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Name: AI Recipe Generator&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; The project's human-readable title.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why I chose it:&lt;/strong&gt; It clearly tells users exactly what the tool does right away.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Short name: &lt;code&gt;ai_recipe_generator&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; The machine-readable system name used for URLs and codebases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why I chose it:&lt;/strong&gt; It matches the readable name using standard Drupal convention (lowercase and underscores) for consistency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Project type: Full project&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; Defines if it's a temporary "Sandbox" or an official "Full project."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why I chose it:&lt;/strong&gt; To get end-to-end control and official release packaging for this GSoC module.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Status and Classification
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Maintenance status: Actively maintained&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; Shows the community how much attention the project gets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why I chose it:&lt;/strong&gt; I will be actively monitoring, updating, and managing this code for the next 12 weeks and beyond.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Development status: Under active development&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; Indicates the codebase's current maturity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why I chose it:&lt;/strong&gt; The module is currently being built from the ground up and evolving daily.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Module categories &amp;amp; Ecosystem: Artificial Intelligence (AI)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; Tags used to organize and filter Drupal projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why I chose it:&lt;/strong&gt; Since the module relies on generative LLMs, this ensures the right audience finds it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Dependencies: AI module&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; Other modules required for this to work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why I chose it:&lt;/strong&gt; We are leveraging the existing Drupal AI core module to securely handle API configurations and process prompts.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Issue Tracking and Releases
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Components: Code, Documentation, Miscellaneous, User interface&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; Categories for issue queue tickets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why I chose it:&lt;/strong&gt; Granular tags keep the project organized and make bug triage much easier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Enable issue tracker: Checked&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; Allows the community to report bugs and submit patches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why I chose it:&lt;/strong&gt; Open source thrives on collaboration, and this is essential for community contributions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Version options: Tagged releases, Development branch releases&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What it is:&lt;/strong&gt; How Drupal packages the code for download via Composer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why I chose it:&lt;/strong&gt; It gives users the choice between a stable "Tagged" release or the bleeding-edge "Development" version.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;The Description that I put is below.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;The AI Recipe Generator is a module designed to accelerate site building by utilizing Artificial Intelligence to generate Drupal Recipes dynamically.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;By integrating with the Drupal AI ecosystem, this tool allows developers and site builders to input natural language prompts and automatically generate the necessary configuration, module dependencies, and structure required for a functional Drupal Recipe.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h3&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"module-project--features"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Features&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Integrates directly with the Drupal AI module to process prompts.&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Dynamically generates &lt;span class="nt"&gt;&amp;lt;code&amp;gt;&lt;/span&gt;recipe.yml&lt;span class="nt"&gt;&amp;lt;/code&amp;gt;&lt;/span&gt; files and associated configurations.&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Streamlines the creation of standard site features (e.g., blog setups, event content types) without manual YAML writing.&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h3&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"module-project--post-installation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Post-Installation&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Once installed, you will configure the generator through the AI module's interface. You must have an active AI provider configured via the core AI module to process prompts and begin generating recipes.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h3&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"module-project--additional-requirements"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Additional Requirements&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;This module requires the following dependencies:&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;AI (Artificial Intelligence) module ecosystem&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h3&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"module-project--recommended-libraries"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Recommended modules/libraries&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;There are currently no additional recommended modules beyond the required AI ecosystem dependencies.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h3&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"module-project--similar-projects"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Similar projects&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;While standard Drupal site-building tools exist, this project uniquely leverages generative LLMs and the new Drupal Recipe API to architect configurations via natural language.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h3&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"module-project--support"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Supporting this Module&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;This project is currently being developed as part of &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;Google Summer of Code 2026&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h3&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"module-project--community-documentation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Community Documentation&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Weekly progress, architectural breakdowns, and documentation for this GSoC 2026 project are being documented under the &lt;span class="nt"&gt;&amp;lt;em&amp;gt;&lt;/span&gt;Engineering in the Wild&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&lt;/span&gt; series.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Further you can also add your logo here. It was also confusing for me to find out where the logo is. &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%2Fcatrij4rdrn66ybl8qds.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%2Fcatrij4rdrn66ybl8qds.png" alt="Where to put Drupal Logo" width="800" height="168"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Where to put Drupal Logo&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You are almost done!!! You can review and see the details what they are. And then finally you can save and your project is successfully created! You can view my module here:&lt;a href="https://www.drupal.org/project/ai_recipe_generator" rel="noopener noreferrer"&gt;AI Recipe Generator&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;Bonus: How to Add Maintainers&lt;/h1&gt;

&lt;p&gt;Most probably, you will be working with someone else. And it will be necessary to add someone there. Head over to the Maintainers tab and select whom you want to add in the search box. You can select the necessary changes to be made and then press enter!&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%2Ffhamgvxsp8wziudsf6ei.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%2Ffhamgvxsp8wziudsf6ei.png" alt="For adding Maintainers" width="800" height="382"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;For adding Maintainers&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Follow Along for my next journey&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.hrishikeshdalal.tech/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhrishikeshdalal.tech%2Fog-image.png" height="800" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.hrishikeshdalal.tech/" rel="noopener noreferrer" class="c-link"&gt;
            Hrishikesh Dalal | Portfolio | Engineer, Innovator, Hackathon Winner
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Official website of Hrishikesh Dalal – Computer Engineering student, Hackathon winner, and tech enthusiast.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.hrishikeshdalal.tech%2Ffavicon.ico" width="256" height="256"&gt;
          hrishikeshdalal.tech
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>ai</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>drupal</category>
    </item>
    <item>
      <title>The AI Ghostwriter Experiment</title>
      <dc:creator>Hrishikesh Dalal</dc:creator>
      <pubDate>Sun, 17 May 2026 11:48:08 +0000</pubDate>
      <link>https://dev.to/hrishikesh_dalal_ced8f95e/the-ai-ghostwriter-experiment-1o2a</link>
      <guid>https://dev.to/hrishikesh_dalal_ced8f95e/the-ai-ghostwriter-experiment-1o2a</guid>
      <description>&lt;p&gt;Over the past few months, I ran an experiment on this blog.&lt;/p&gt;

&lt;p&gt;Balancing engineering projects, open-source contributions, and university means deep-focus writing is a luxury I rarely have. I wanted to test a hypothesis: &lt;em&gt;Can a developer leverage LLMs to fully automate content creation without losing technical depth?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I launched my &lt;em&gt;"Engineering in the Wild"&lt;/em&gt; &amp;amp; "System Design" series to find out. Here is what I learned from letting AI ghostwrite my blog, and why I’m officially pivoting my strategy.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Workflow
&lt;/h3&gt;

&lt;p&gt;It wasn’t just mindless prompting. I built a specific pipeline to ground the AI in reality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Input:&lt;/strong&gt; Raw notes on architectural decisions (like sync APIs vs. Pub/Sub) or details from my ongoing projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generation:&lt;/strong&gt; Prompting the LLM to structure an engaging, DEV.to-optimized article.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output:&lt;/strong&gt; Flawless markdown, clean code snippets, and accessible analogies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On paper, it worked perfectly. I shipped consistently, and the articles read like polished, textbook overviews that explained complex concepts exceptionally well.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Flaw: Sanitized Engineering
&lt;/h3&gt;

&lt;p&gt;While the explanations were solid, the experiment revealed a fatal flaw in fully automated content: &lt;strong&gt;it completely sanitizes the reality of writing code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Reviewing the generated articles made a few things glaringly obvious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Loss of Signal:&lt;/strong&gt; AI outputs the statistical average of human knowledge. It produces clean, pristine ideals. But real engineering is chaotic and messy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Erasure of Friction:&lt;/strong&gt; The real value of a dev blog isn't just the final architecture—it’s the friction it took to get there. AI erased the edge-case geofencing bugs in my attendance platform, the legacy codebase constraints at my enterprise internship, and the brutal code reviews from merging open-source AI modules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Commodity Trap:&lt;/strong&gt; A flawless explanation of a protocol is useful, but if anyone can generate it in ten seconds, it loses its unique edge. It didn’t show how &lt;em&gt;I&lt;/em&gt; think; it showed how the model thinks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Pivot: Authentic Grit
&lt;/h3&gt;

&lt;p&gt;The foundational overviews the AI helped me build serve their purpose, and AI remains a phenomenal tool. But going forward, the workflow for &lt;em&gt;"Engineering in the Wild"&lt;/em&gt; &amp;amp; "System Design" is evolving.&lt;/p&gt;

&lt;p&gt;The best documentation isn’t just a flawless essay; it’s a collection of genuine experiences from the trenches of development. It’s time to bring the grit back to this blog.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Even this meta-analysis was generated by AI :) but the pivot is 100% human.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>ai</category>
    </item>
    <item>
      <title>EP 15: Pub/Sub - Stop Chaining Your Services</title>
      <dc:creator>Hrishikesh Dalal</dc:creator>
      <pubDate>Wed, 18 Feb 2026 11:20:06 +0000</pubDate>
      <link>https://dev.to/hrishikesh_dalal_ced8f95e/ep-15-pubsub-stop-chaining-your-services-53ng</link>
      <guid>https://dev.to/hrishikesh_dalal_ced8f95e/ep-15-pubsub-stop-chaining-your-services-53ng</guid>
      <description>&lt;p&gt;You just launched your dream startup, &lt;strong&gt;"DevEats"&lt;/strong&gt;—a food delivery app for developers who need serious fuel while debugging. Your signature item? The &lt;strong&gt;"Triple Stack Smash Burger with Truffle Fries."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the beginning, life was simple. You had one backend service (a monolith). A user ordered a burger, your code saved it to the database, and life was good.&lt;/p&gt;

&lt;p&gt;But you grew fast. Now, YOU are the owner of a scaling platform, and your code is turning into a tangled mess of spaghetti (pun intended).&lt;/p&gt;

&lt;p&gt;Here is why you need the &lt;strong&gt;Pub/Sub&lt;/strong&gt; pattern, explained through the lens of your own burger empire.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. What is the Need? (The "Smash Burger Panic")
&lt;/h2&gt;

&lt;p&gt;Let’s look at your current codebase. When a user clicks "Order Burger", your backend does this strictly in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Payment Service:&lt;/strong&gt; Charge the credit card $25.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Order Service:&lt;/strong&gt; Save the order to the database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notification Service:&lt;/strong&gt; Send a receipt email.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kitchen Service:&lt;/strong&gt; Print the ticket for the chef.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics Service:&lt;/strong&gt; Update your admin dashboard sales graph.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The Problem:&lt;/strong&gt;&lt;br&gt;
One Friday night, your &lt;strong&gt;Email Provider goes down&lt;/strong&gt;.&lt;br&gt;
Because your code is sequential (A -&amp;gt; B -&amp;gt; C -&amp;gt; D), the entire process crashes at Step 3.&lt;/p&gt;

&lt;p&gt;The payment went through (Step 1), but the kitchen printer never got the ticket (Step 4).&lt;/p&gt;

&lt;p&gt;Now you have a hangry developer who paid for a Triple Stack Burger that isn't being made. They are angry, and your support inbox is flooding.&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%2Fhgtok79omv8rofd7dxgw.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%2Fhgtok79omv8rofd7dxgw.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Need:&lt;/strong&gt;&lt;br&gt;
You need a way for your system to say, &lt;em&gt;"Hey, a burger was just ordered!"&lt;/em&gt; without caring who is listening or if the email service is currently online. You need to &lt;strong&gt;decouple&lt;/strong&gt; the sender from the receivers.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The Solution: Pub/Sub Architecture
&lt;/h2&gt;

&lt;p&gt;In a Publish/Subscribe (Pub/Sub) model, we split your architecture into three parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Publisher (You/The Order Service):&lt;/strong&gt; You simply shout a message ("Order #505: Triple Smash Burger!") into a channel. You don't know who is listening. You don't care.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Topic (The Channel):&lt;/strong&gt; A dedicated lane for specific types of messages (e.g., &lt;code&gt;events.burger_ordered&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Subscribers (The Listeners):&lt;/strong&gt; Independent services that have signed up to listen to that topic.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The New Flow:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;User orders the burger.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You (Order Service)&lt;/strong&gt; publish a message to the &lt;code&gt;events.burger_ordered&lt;/code&gt; topic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Done.&lt;/strong&gt; You return "Success" to the user immediately.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Meanwhile, in the background:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Kitchen Service&lt;/strong&gt; hears the message and instantly prints the ticket on the grill station.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Notification Service&lt;/strong&gt; hears the message and &lt;em&gt;tries&lt;/em&gt; to send an email. If it fails (because the provider is down), it retries later. &lt;strong&gt;Crucially, it does not stop the kitchen from cooking.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Rewards Service&lt;/strong&gt; hears the message and adds 50 points to the user's account.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. When to Use It?
&lt;/h2&gt;

&lt;p&gt;You shouldn't use Pub/Sub for everything. Use it when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1-to-Many Relationships:&lt;/strong&gt; One event (Burger Ordered) triggers multiple, unrelated actions (Email, Kitchen Display, Inventory Check).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decoupling is Vital:&lt;/strong&gt; You want to add a new "SMS Service" next week without rewriting your existing Order Service code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asynchronous Processing:&lt;/strong&gt; You don't want the user staring at a loading spinner while your server generates a PDF invoice.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. The Pros and Cons
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ The Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scalability:&lt;/strong&gt; You can add 50 new subscribers (e.g., a "Surge Pricing Bot") without touching the original Publisher code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability:&lt;/strong&gt; If one subscriber crashes (e.g., the Email service), the others (Kitchen, Analytics) keep working perfectly. The burger still gets made.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed:&lt;/strong&gt; The Publisher fires the event and moves on. The user gets a "Your Order is Placed!" screen instantly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ❌ The Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complexity:&lt;/strong&gt; You are introducing a new component (a Broker like Redis, Kafka, or Google Pub/Sub) to manage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging is a Nightmare:&lt;/strong&gt; You can't just follow a linear stack trace anymore. You have to trace messages flying across a network.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency Issues:&lt;/strong&gt; What if the message is delivered twice? (Does the customer get charged twice? Does the chef make two burgers?). You have to write code to handle these edge cases.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Pub/Sub vs. Message Queue (The Confusion)
&lt;/h2&gt;

&lt;p&gt;This is where most devs get tripped up. Both use "Brokers," but the intent is different.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Scenario A: Pub/Sub (The "Megaphone")&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Use Case:&lt;/strong&gt; You launch a &lt;strong&gt;New limited-edition Ghost Pepper Burger.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Logic:&lt;/strong&gt; &lt;em&gt;1 Message -&amp;gt; Many Receivers.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Publisher:&lt;/strong&gt; The Menu Manager Service.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Subscribers:&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App Notification Service:&lt;/strong&gt; Pushes "New Burger Alert!" to all users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inventory Service:&lt;/strong&gt; Reserves spicy peppers in the warehouse.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Marketing Service:&lt;/strong&gt; Posts automatically to Twitter/X.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; Everyone needs to know about this event to do their own specific job.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Scenario B: Message Queue (The "Grill Line")&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Use Case:&lt;/strong&gt; It's lunch rush. You have 500 burger orders coming in.&lt;br&gt;
&lt;strong&gt;Logic:&lt;/strong&gt; &lt;em&gt;1 Message -&amp;gt; 1 Receiver (Load Balancing).&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Producer:&lt;/strong&gt; The Order Service pushes 500 tickets to a &lt;strong&gt;Queue&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consumers (Chefs):&lt;/strong&gt; You have 5 Chefs (Chef A, B, C, D, E).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Flow:&lt;/strong&gt; Chef A grabs Ticket #1. Chef B grabs Ticket #2.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why?&lt;/strong&gt; If Chef A is grilling the burger for Ticket #1, you &lt;strong&gt;do not&lt;/strong&gt; want Chef B to grill the same burger. That’s a waste of meat. You want to &lt;em&gt;distribute&lt;/em&gt; the work, not broadcast it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Cheat Sheet&lt;/strong&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Pub/Sub&lt;/th&gt;
&lt;th&gt;Message Queue&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Philosophy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"Everyone needs to know this happened."&lt;/td&gt;
&lt;td&gt;"Someone please do this job."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Distribution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Broadcast (One-to-All)&lt;/td&gt;
&lt;td&gt;Point-to-Point (One-to-One)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Burger Example&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"New Menu Item Launched!" (Tell everyone)&lt;/td&gt;
&lt;td&gt;"Grill this patty" (One chef does it)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Final Words&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As the owner of &lt;strong&gt;DevEats&lt;/strong&gt;, switching to Pub/Sub saved your Friday night rush. When your Email Service crashed, nobody noticed. The orders kept flowing, the smash burgers kept sizzling, and the emails were just queued up and sent an hour later.&lt;/p&gt;

&lt;p&gt;That is the power of decoupling. 🍔 code responsibly!&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>pubsub</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The Jungle Protocol: Turning my Professional Journey into an Adaptive Quest</title>
      <dc:creator>Hrishikesh Dalal</dc:creator>
      <pubDate>Sun, 01 Feb 2026 13:58:07 +0000</pubDate>
      <link>https://dev.to/hrishikesh_dalal_ced8f95e/the-jungle-protocol-turning-my-professional-journey-into-an-adaptive-quest-3p4m</link>
      <guid>https://dev.to/hrishikesh_dalal_ced8f95e/the-jungle-protocol-turning-my-professional-journey-into-an-adaptive-quest-3p4m</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/new-year-new-you-google-ai-2025-12-31"&gt;New Year, New You Portfolio Challenge Presented by Google AI&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About Me
&lt;/h2&gt;

&lt;p&gt;I’m Hrishikesh Dalal, a Computer Engineering student at Sardar Patel Institute of Technology (SPIT), Mumbai. I don't just write code; I build experiences. Currently, I’m engineering a Jumanji-themed gamified portfolio that turns the standard resume into an adventure.&lt;/p&gt;

&lt;p&gt;My focus lies in Full Stack Development (Next.js, React) and creating developer tools—I recently published envalyze and env-fault to the NPM registry to help devs manage environments better. When I'm not pushing commits to Open Source projects like Drupal or contributing to MDN Web Docs, I'm exploring the intersection of AI and law with projects like VerdictAI.&lt;/p&gt;

&lt;p&gt;I write about system design, open source, and the reality of building software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Portfolio
&lt;/h2&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__cloud-run"&gt;
  &lt;iframe height="600px" src="https://hrishikesh-dalal-portfolio-571902073238.europe-west1.run.app"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;




&lt;p&gt;Link: &lt;a href="https://hrishikesh-dalal-portfolio-571902073238.europe-west1.run.app" rel="noopener noreferrer"&gt;https://hrishikesh-dalal-portfolio-571902073238.europe-west1.run.app&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  My Tech Stack
&lt;/h3&gt;

&lt;p&gt;To build an experience this immersive, I needed a stack that balanced performance with high-end visuals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend: Next.js &amp;amp; Tailwind CSS&lt;/li&gt;
&lt;li&gt;Animations: GSAP (for that cinematic feel)&lt;/li&gt;
&lt;li&gt;3D Elements: Three.js (for the interactive globe and hero patterns)&lt;/li&gt;
&lt;li&gt;AI:Gemini API (powering the NPC-style chatbots)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Process: From Chaos to Clarity
&lt;/h3&gt;

&lt;p&gt;Building a portfolio is a trap. You want to show off everything, but if you're not careful, you end up with a bloated mess.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. The Affinity Mapping Phase
&lt;/h4&gt;

&lt;p&gt;Initially, I was drowning in ideas from my UI/UX course. I had a laundry list: a full 3D world, a terminal, hidden easter eggs, business-centric project stats, and a Jumanji-themed game. I used &lt;strong&gt;Affinity Mapping&lt;/strong&gt; to dump every "cool" idea onto a board and then ruthlessly segregated them.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. The "Reality Check"
&lt;/h4&gt;

&lt;p&gt;I had to ask the most important question: &lt;strong&gt;Why is someone here?&lt;/strong&gt;&lt;br&gt;
Hiring managers are busy. They might be tech-savvy, or they might not be. They might want to play a game, or they might just want to see my resume and leave in 30 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Decision:&lt;/strong&gt; A "Clean &amp;amp; Clear" landing page with a defined Call to Action (CTA) is non-negotiable. The "wow" factor should enhance the info, not hide it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Breakdown: Section by Section
&lt;/h3&gt;

&lt;h4&gt;
  
  
  The Hero (The First 5 Seconds)
&lt;/h4&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%2Fhthw4dymw522shj11743.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%2Fhthw4dymw522shj11743.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I treated the Hero section like a movie opening. I implemented a preloader with a cinematic transition that drops you into an interactive dot pattern. It’s meant to grab attention immediately.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Impact (Big Numbers &amp;amp; Open Source)
&lt;/h4&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%2Fxuplswoqeglnkxh8ljth.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%2Fxuplswoqeglnkxh8ljth.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of just saying "I build tools," I used big, bold typography to showcase my &lt;strong&gt;NPM stats&lt;/strong&gt;. I wanted the real-world impact of &lt;code&gt;envalyze&lt;/code&gt; and &lt;code&gt;env-fault&lt;/code&gt; to be unavoidable. I also dedicated space to my Open Source journey—showing my Hacktoberfest badges and my role as a project admin.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Experience Timeline
&lt;/h4&gt;

&lt;p&gt;I used a scroll-triggered timeline with GSAP micro-interactions. When you hover over an entry, there’s a slight movement—just enough to feel alive, but not enough to be distracting.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Terminal (For the Geeks)
&lt;/h4&gt;

&lt;p&gt;I built a fully functional terminal for my projects. You can change themes, run an &lt;code&gt;echo&lt;/code&gt;, or see animations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt; Try typing &lt;code&gt;sudo&lt;/code&gt;. You’ve been warned.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The Accessibility Switch:&lt;/strong&gt; If you aren't a terminal person, there's a toggle to switch back to a standard grid. No one gets left behind.&lt;/p&gt;

&lt;h3&gt;
  
  
  The "Jungle" Experience
&lt;/h3&gt;

&lt;p&gt;This was the hardest part to get right. My first version was just a collection of games, and the feedback from friends was brutal: &lt;em&gt;"It’s disconnected. I don't see YOU in this."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I went back to the drawing board and turned it into a narrative. I added:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A Prologue &amp;amp; Epilogue:&lt;/strong&gt; To give the "quest" a purpose.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Level 2 (The Jumper):&lt;/strong&gt; While you play, the character narrates my tech stack and experience journey.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secret Cheat Codes:&lt;/strong&gt; Because what's a game without them?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Bringing it to life with AI
&lt;/h3&gt;

&lt;p&gt;My main chatbot you have different answers queries, sample questions that you can ask to make it better. &lt;/p&gt;

&lt;p&gt;While the game chatbot is like NPC character answering you.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Architecture
&lt;/h3&gt;

&lt;p&gt;The diagram below shows how the game chatbot is integrated to handle context-aware queries, ensuring it knows where you are in the game and who I am as a developer.&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%2F0z9vphjt0p8id5g9g8yk.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%2F0z9vphjt0p8id5g9g8yk.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The User Interaction Layer&lt;br&gt;
User Sends Message: The process begins with the user interacting with the interface. &lt;br&gt;
Frontend App (NEXT JS): The core UI is built using React. It features a React Markdown Renderer, which ensures that the AI's responses—often containing code snippets or formatted text—are displayed cleanly and professionally to the user.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Security and Traffic Management&lt;br&gt;
Backend API Gateway &amp;amp; Security Layer: Instead of calling the Gemini API directly from the frontend (which would expose your API keys), the app calls a secure backend gateway. This layer handles authentication and protects your credentials.&lt;br&gt;
Load Balancer: To prevent any single server from becoming overwhelmed, a load balancer sits in the middle. It analyzes incoming requests and routes them efficiently across multiple active instances.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Processing Core&lt;br&gt;
Chat Model Instances: The system uses multiple parallel instances (Instance 1, 2, and 3) to process requests.&lt;br&gt;
Least Used Routing: The load balancer is shown routing a request specifically to "Instance 1" because it is currently the "Least Used," ensuring optimal performance and low latency.&lt;br&gt;
Google's Gemini API: These instances act as the bridge to Google’s infrastructure. They send the processed user prompt to the Gemini API and receive the raw AI generation in return.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Response Loop&lt;br&gt;
Forwards Response: Once a chat instance receives the data from Google, it forwards that response back through the secure backend.&lt;br&gt;
Final Display: The message is sent back to the NEXT JS app, where it is rendered as Markdown, completing the loop and appearing on the user's screen.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Easter Eggs
&lt;/h3&gt;

&lt;p&gt;I have a game at the start where the user can press the "?" button and play that simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Stay Hungry, Stay Foolish."&lt;/strong&gt; My portfolio ends with this quote because it sums up my approach to engineering. Whether it's deep-diving into the Drupal source code or building a terminal from scratch, I’m always looking for the next thing that feels slightly impossible to build.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm Most Proud Of
&lt;/h2&gt;

&lt;p&gt;If you’re a developer, you know the feeling: you spend 10% of your time on the features people see and 90% of your time on the "over-engineered" systems that make you feel like a wizard. Here are the pillars of this portfolio that I obsessed over.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Terminal (Because real devs use a CLI)
&lt;/h3&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%2F9wclxo5divqo63axsd66.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%2F9wclxo5divqo63axsd66.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I didn't want a static "Projects" page; I wanted something that felt like home. I built a fully functional, web-based &lt;strong&gt;Terminal&lt;/strong&gt; where you can actually interact with my work.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Experience:&lt;/strong&gt; It’s a working CLI where you can navigate projects, change themes, or trigger animations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The "Sudo" Trap:&lt;/strong&gt; I’ve hidden easter eggs for people who like to poke around—try typing &lt;code&gt;sudo&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Hybrid UI:&lt;/strong&gt; I know recruiters aren't always looking to type commands, so I built a "safety net" toggle that instantly switches the terminal into a standard project grid.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Projects with a "Business First" Logic
&lt;/h3&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%2Fffuih8dmbek5usvz4jbu.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%2Fffuih8dmbek5usvz4jbu.png" alt=" "&gt;&lt;/a&gt;&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%2Fc90f5dki8e2z7qd7c0g4.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%2Fc90f5dki8e2z7qd7c0g4.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most portfolios just show a screenshot and a GitHub link. I decided to treat my projects like real products.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Beyond the Code:&lt;/strong&gt; When you click into a project, I don't just list the tech stack. I break down the &lt;strong&gt;Business Perspective&lt;/strong&gt;, the &lt;strong&gt;Impact&lt;/strong&gt;, and the &lt;strong&gt;Stats&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The "Why" Factor:&lt;/strong&gt; I included the reasoning behind my architectural choices so that a non-technical stakeholder can understand the value I created, not just the code I wrote.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deep Dives:&lt;/strong&gt; Each project page is designed to show the journey from a pain point to a scalable solution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. The Jumanji Game Engine
&lt;/h3&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%2Fj8c48sfbpfgpbcbr5954.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%2Fj8c48sfbpfgpbcbr5954.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I turned my professional experience into a narrative quest. This wasn't just about putting a game on a website; it was about making the resume &lt;em&gt;playable&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Narrative:&lt;/strong&gt; I added a full prologue and epilogue to make sure it felt like a real quest, not just a random mini-game.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Career Jumper:&lt;/strong&gt; In Level 2, the character literally narrates my tech stack and my journey through different roles while you play.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recruiter Mode:&lt;/strong&gt; I even made the game adaptive—a recruiter can upload a job description, and the game will fine-tune the information it highlights to match what they need.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. The Chatbot Architecture
&lt;/h3&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%2Fd5jdp2hcjplottmv6nsh.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%2Fd5jdp2hcjplottmv6nsh.png" alt=" "&gt;&lt;/a&gt;&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%2Fw6ywwj3qd4mhxof823go.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%2Fw6ywwj3qd4mhxof823go.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m most proud of what’s happening "under the hood" here. I built a production-ready pipeline for the Gemini-powered Chatbot.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Load Balancer:&lt;/strong&gt; My system uses three different chat model instances. I implemented a load balancer that routes traffic to the "least used" instance to keep things snappy, no matter the traffic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security &amp;amp; Scalability:&lt;/strong&gt; I kept the logic on the backend. The React frontend talks to a secure API Gateway, which handles the Gemini API calls to keep my keys safe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The NPC Persona:&lt;/strong&gt; I used the &lt;strong&gt;Gemini API&lt;/strong&gt; to give the bot a specific "In-game NPC" persona—it knows it’s in the Jungle, but it also knows my GitHub stats.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>googleaichallenge</category>
      <category>portfolio</category>
      <category>gemini</category>
    </item>
    <item>
      <title>System Design: EP 14 - The Coffee Shop Guide to Understanding Message Brokers</title>
      <dc:creator>Hrishikesh Dalal</dc:creator>
      <pubDate>Wed, 21 Jan 2026 11:17:47 +0000</pubDate>
      <link>https://dev.to/hrishikesh_dalal_ced8f95e/system-design-ep-14-the-coffee-shop-guide-to-understanding-message-brokers-393b</link>
      <guid>https://dev.to/hrishikesh_dalal_ced8f95e/system-design-ep-14-the-coffee-shop-guide-to-understanding-message-brokers-393b</guid>
      <description>&lt;p&gt;If you are a developer moving from a monolith to microservices, you’ve probably hit &lt;strong&gt;The Problem&lt;/strong&gt;. Service A calls Service B, but Service B is slow, or down, or just busy. Suddenly, Service A hangs, the user sees a spinning wheel of death, and you get paged at 3 AM.&lt;/p&gt;

&lt;p&gt;The solution? Stop making your services talk directly. Introduce a &lt;strong&gt;Message Broker&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If that sounds abstract, let's talk about coffee.&lt;/p&gt;




&lt;h3&gt;
  
  
  The "Bad" Coffee Shop (Synchronous)
&lt;/h3&gt;

&lt;p&gt;Imagine a coffee shop where the person taking your order is also the &lt;em&gt;only&lt;/em&gt; person allowed to make your coffee.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;You&lt;/strong&gt; (The User) walk in and order a latte.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Cashier&lt;/strong&gt; (Service A) takes your money.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Cashier&lt;/strong&gt; then walks over to the espresso machine, steams the milk, pulls the shot, pours the art, and hands it to you.&lt;/li&gt;
&lt;li&gt;Only &lt;em&gt;then&lt;/em&gt; do they return to the register to take the next person's order.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The Result:&lt;/strong&gt; A massive line out the door. If the espresso machine breaks, the cashier is stuck waiting, and nobody can even &lt;em&gt;place&lt;/em&gt; an order. This is &lt;strong&gt;Synchronous Communication&lt;/strong&gt; (like HTTP REST calls). It creates tight coupling and bottlenecks.&lt;/p&gt;




&lt;h3&gt;
  
  
  The "Good" Coffee Shop (Asynchronous with a Broker)
&lt;/h3&gt;

&lt;p&gt;Now, let's look at how a Starbucks or a high-volume cafe actually works.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;You&lt;/strong&gt; (The User) order a latte.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Cashier&lt;/strong&gt; (Service A / Producer) takes your money and writes your order on a cup (or a ticket).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Cashier&lt;/strong&gt; places the cup on the &lt;strong&gt;Counter/Ticket Rail&lt;/strong&gt; (The Message Broker).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Cashier&lt;/strong&gt; immediately turns back to you and says, "Next please!"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Barista&lt;/strong&gt; (Service B / Consumer) sees the cup on the rail, picks it up, and makes the coffee.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The Result:&lt;/strong&gt; The cashier never stops working. They can take 50 orders in the time it takes the barista to make 5 drinks. The "Ticket Rail" acts as a buffer.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Technical Translation
&lt;/h3&gt;

&lt;p&gt;That "Ticket Rail" is your Message Broker (like RabbitMQ, Kafka, or AWS SQS). Here is the mapping for your next system design interview:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. The Producer (The Cashier)
&lt;/h4&gt;

&lt;p&gt;This is the service that sends the data. In the coffee shop, the cashier "produces" the order. They don't care &lt;em&gt;who&lt;/em&gt; makes the coffee or &lt;em&gt;when&lt;/em&gt; it gets made; they just need to know the order has been safely placed on the rail.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dev Term:&lt;/strong&gt; &lt;code&gt;Publish&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. The Message Broker (The Ticket Rail)
&lt;/h4&gt;

&lt;p&gt;This is the middleware that sits between your services. It holds the messages (orders) until a consumer is ready to take them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Queue:&lt;/strong&gt; The line of cups waiting on the machine. If the baristas get overwhelmed, the queue grows, but the cups aren't lost. They are safely stored until the backlog clears.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. The Consumer (The Barista)
&lt;/h4&gt;

&lt;p&gt;This is the service that processes the data. The barista "consumes" the order from the rail.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dev Term:&lt;/strong&gt; &lt;code&gt;Subscribe&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scaling:&lt;/strong&gt; If the line of cups gets too long, what do you do? You don't clone the cashier; you add a second barista. Message brokers allow you to scale your processing power (Consumers) independently of your intake power (Producers).&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Why use a Message Broker?
&lt;/h3&gt;

&lt;p&gt;Using the coffee shop model, the benefits become obvious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decoupling:&lt;/strong&gt; The cashier doesn't need to know which barista is working today. If the barista quits (Service B crashes), the cashier can keep taking orders. The cups just pile up on the rail until a new barista is hired (Service B restarts). No data is lost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Throttling (Load Leveling):&lt;/strong&gt; If 100 people rush the store at once, the cashier takes all the orders quickly. The baristas continue working at their normal, safe speed. They don't explode from stress; they just work through the backlog.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asynchronous Processing:&lt;/strong&gt; Heavy tasks (like roasting beans or baking pastries) don't block the customer from paying and leaving.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Direct HTTP calls are like a cashier making every drink themselves. It works for a lemonade stand, but it fails at scale.&lt;/p&gt;

&lt;p&gt;A Message Broker is the ticket rail that lets your services work at their own speeds, independently and reliably.&lt;/p&gt;

&lt;p&gt;So, the next time you're architecting a system, ask yourself: &lt;strong&gt;Are we building a lemonade stand, or are we building a coffee empire?&lt;/strong&gt;&lt;/p&gt;

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