<?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: Le Huy Hiep</title>
    <description>The latest articles on DEV Community by Le Huy Hiep (@coji831).</description>
    <link>https://dev.to/coji831</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%2F4059146%2F780a3a3e-9230-484f-ab5a-4fe48798e3fe.jpg</url>
      <title>DEV Community: Le Huy Hiep</title>
      <link>https://dev.to/coji831</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/coji831"/>
    <language>en</language>
    <item>
      <title>We automated our Terraform. Locally it worked fine. In CI it hung for three hours.</title>
      <dc:creator>Le Huy Hiep</dc:creator>
      <pubDate>Mon, 14 Sep 2026 14:36:09 +0000</pubDate>
      <link>https://dev.to/coji831/we-automated-our-terraform-locally-it-worked-fine-in-ci-it-hung-for-three-hours-9fo</link>
      <guid>https://dev.to/coji831/we-automated-our-terraform-locally-it-worked-fine-in-ci-it-hung-for-three-hours-9fo</guid>
      <description>&lt;p&gt;It worked locally 😂 because Terraform asks for the variable it is missing, and something was there to answer. An agent, in our case, typing into the prompt.&lt;/p&gt;

&lt;p&gt;In CI nothing types. Runner stdin never closes, so there is no timeout either. It just waits.&lt;/p&gt;

&lt;p&gt;No error. Three hours of nothing.&lt;/p&gt;

&lt;p&gt;Terraform wanted project_id. It was never set in CI.&lt;/p&gt;

&lt;p&gt;Two fixes: pass it as TF_VAR_project_id, and add -input=false so it fails in two seconds instead of hanging.&lt;/p&gt;

&lt;p&gt;The smaller cost was the three hours. The bigger one was deleting the plan gate on PRs. It hung at random and was not blocking anything, so it went.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>ci</category>
      <category>devops</category>
      <category>ai</category>
    </item>
    <item>
      <title>userId! vs !userId</title>
      <dc:creator>Le Huy Hiep</dc:creator>
      <pubDate>Mon, 07 Sep 2026 10:10:53 +0000</pubDate>
      <link>https://dev.to/coji831/userid-vs-userid-1cai</link>
      <guid>https://dev.to/coji831/userid-vs-userid-1cai</guid>
      <description>&lt;p&gt;I never write the first one. But an agent could.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;userId!&lt;/code&gt; tells TypeScript "trust me, this exists."&lt;br&gt;
&lt;code&gt;!userId&lt;/code&gt; checks whether it actually does.&lt;/p&gt;

&lt;p&gt;My habit is the check: &lt;code&gt;!userId&lt;/code&gt;, then act. The agent's output used&lt;br&gt;
the assertion: &lt;code&gt;userId!&lt;/code&gt;, assume it exists. On a route that allowed&lt;br&gt;
guests, a user who was not logged in meant no user ID.&lt;/p&gt;

&lt;p&gt;The code called the database with an empty ID. An empty ID means no&lt;br&gt;
filter. The query returned every user's records.&lt;/p&gt;

&lt;p&gt;No ID -&amp;gt; all the data.&lt;/p&gt;

&lt;p&gt;My tests missed it because they only ran with logged-in users.&lt;br&gt;
I caught it re-reading the code before a migration.&lt;/p&gt;

&lt;p&gt;The fix: check for a missing ID and stop before the query runs.&lt;/p&gt;

&lt;p&gt;When you review agent output, do not just check the logic. Check the&lt;br&gt;
assumptions it typed as facts. The confident version is the dangerous&lt;br&gt;
one.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>security</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Agent reading every files to answer one simple question?</title>
      <dc:creator>Le Huy Hiep</dc:creator>
      <pubDate>Tue, 18 Aug 2026 05:30:57 +0000</pubDate>
      <link>https://dev.to/coji831/agent-reading-every-files-to-answer-one-simple-question-18ce</link>
      <guid>https://dev.to/coji831/agent-reading-every-files-to-answer-one-simple-question-18ce</guid>
      <description>&lt;p&gt;My knowledge base grew across thousands of markdown files. Finding one fact meant reading whole files. Keyword search found words, not meaning. And reading whole files burns tokens: tens of thousands of tokens to surface one fact. The real metric is not storage. It is tokens per answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why not the usual tools?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;grep finds the file, but you still read it. Cost unchanged.&lt;/li&gt;
&lt;li&gt;A cloud vector DB sends private notes out and adds infra for a 2 MB corpus.&lt;/li&gt;
&lt;li&gt;Semantic-only search cannot do exact filters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What I built:&lt;/strong&gt; a local-first retrieval layer.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;SQLite FTS5 index: instant keyword search, exact filters, real file:line references.&lt;/li&gt;
&lt;li&gt;Local ONNX embeddings (384-dim): semantic ranking. Every hit points at a real file.&lt;/li&gt;
&lt;li&gt;One-command rebuild. The index is derived, so it never goes stale.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; 2,000 chunks, one CLI, zero servers. An answer now costs a few hundred tokens, not a sweep through thousands of files.&lt;/p&gt;

&lt;p&gt;Start deterministic. Add semantic where keywords fail. Rebuild often.&lt;/p&gt;

</description>
      <category>rag</category>
      <category>sqlite</category>
      <category>ai</category>
      <category>llm</category>
    </item>
    <item>
      <title>How to add UI for your RAG?!?</title>
      <dc:creator>Le Huy Hiep</dc:creator>
      <pubDate>Mon, 03 Aug 2026 14:53:12 +0000</pubDate>
      <link>https://dev.to/coji831/how-to-add-ui-for-your-rag-51bl</link>
      <guid>https://dev.to/coji831/how-to-add-ui-for-your-rag-51bl</guid>
      <description>&lt;p&gt;Just built some FastAPI SSE backend streaming LLM responses token-by-token,&lt;br&gt;
after i got some free time.&lt;/p&gt;

&lt;p&gt;Two things broke in production that worked fine locally 🙃:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;nginx buffers SSE by default. The stream was delivering locally, dead&lt;br&gt;
silent on Railway. &lt;code&gt;proxy_buffering&lt;/code&gt; off, two hours later, fixed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The LLM API returns an &lt;code&gt;empty_retrieval&lt;/code&gt; event when no docs match. I wasn't&lt;br&gt;
handling it, so the frontend sat on a loading spinner indefinitely. Added&lt;br&gt;
the handler, resolved.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://zooming-charm-production-547e.up.railway.app/" rel="noopener noreferrer"&gt;https://zooming-charm-production-547e.up.railway.app/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>fastapi</category>
      <category>react</category>
      <category>rag</category>
    </item>
  </channel>
</rss>
