<?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: M Rayhan Khan</title>
    <description>The latest articles on DEV Community by M Rayhan Khan (@m_rayhankhan_71c3f2ed50c).</description>
    <link>https://dev.to/m_rayhankhan_71c3f2ed50c</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%2F2600954%2F7ddf4ee1-70f8-4357-9af8-4187ed38c05a.png</url>
      <title>DEV Community: M Rayhan Khan</title>
      <link>https://dev.to/m_rayhankhan_71c3f2ed50c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/m_rayhankhan_71c3f2ed50c"/>
    <language>en</language>
    <item>
      <title>I asked a company brain about a contract I'm not allowed to see. It said no, and told me who to ask.</title>
      <dc:creator>M Rayhan Khan</dc:creator>
      <pubDate>Sun, 18 Oct 2026 17:46:56 +0000</pubDate>
      <link>https://dev.to/m_rayhankhan_71c3f2ed50c/i-asked-a-company-brain-about-a-contract-im-not-allowed-to-see-it-said-no-and-told-me-who-to-ask-3494</link>
      <guid>https://dev.to/m_rayhankhan_71c3f2ed50c/i-asked-a-company-brain-about-a-contract-im-not-allowed-to-see-it-said-no-and-told-me-who-to-ask-3494</guid>
      <description>&lt;p&gt;Every company wants an AI assistant that knows everything. The very next sentence is always the same worry: &lt;em&gt;what happens when it shows the intern the salary sheet?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most "company brain" demos skip that question. They index every document and answer from whatever they find. For &lt;strong&gt;Graph Hacks 2026&lt;/strong&gt; (WeMakeDevs × FalkorDB) I built the opposite: a company brain whose first job is knowing &lt;strong&gt;who is allowed to know what&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's called &lt;strong&gt;Need-to-Know&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧠 Live demo: &lt;a href="https://mrayhankhan.github.io/need-to-know/" rel="noopener noreferrer"&gt;https://mrayhankhan.github.io/need-to-know/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 Code: &lt;a href="https://github.com/mrayhankhan/need-to-know" rel="noopener noreferrer"&gt;https://github.com/mrayhankhan/need-to-know&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  Access is a chain, and chains are a graph problem
&lt;/h2&gt;

&lt;p&gt;Inside a real company, access is rarely "this person can open this file". It looks more like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Priya is in &lt;strong&gt;Support&lt;/strong&gt;. Support is part of &lt;strong&gt;All Staff&lt;/strong&gt;. All Staff was added to &lt;strong&gt;Drive migration 2023 (temporary)&lt;/strong&gt;. Three years ago, that group was given the &lt;strong&gt;salary sheet&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nobody remembers that last step. Nobody can answer "who can actually see this?" with confidence. And a chatbot that answers from every document makes that hidden chain everyone's problem.&lt;/p&gt;

&lt;p&gt;A chain of memberships is exactly what a graph database is built for. In FalkorDB, one query returns everything a person &lt;em&gt;or an AI agent&lt;/em&gt; can read, through any depth of nested groups:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cypher"&gt;&lt;code&gt;&lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;p:&lt;/span&gt;&lt;span class="n"&gt;Principal&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;id:&lt;/span&gt; &lt;span class="n"&gt;$pid&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:MEMBER_OF&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;g:&lt;/span&gt;&lt;span class="n"&gt;Principal&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:CAN_READ&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="k"&gt;DISTINCT&lt;/span&gt; &lt;span class="n"&gt;t.id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The median time is &lt;strong&gt;0.45 ms&lt;/strong&gt;, which is fast enough to run on every question and every agent step. Permissions are never cached, so there's no stale access to worry about.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Need-to-Know does
&lt;/h2&gt;

&lt;p&gt;I generated a realistic company, &lt;strong&gt;Northwind Labs&lt;/strong&gt;: 211 people, 9 teams, 19 nested groups, 21 documents and chats, 3 customers and 3 AI agents. I also hid three real-world mistakes in it for the brain to find.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. A brain you can watch think
&lt;/h3&gt;

&lt;p&gt;The whole company graph is drawn inside a brain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Leadership sits in the frontal lobe and teams across the top.&lt;/li&gt;
&lt;li&gt;Customer-facing teams are at the back.&lt;/li&gt;
&lt;li&gt;Documents live in the memory lobe and AI agents in the cerebellum.&lt;/li&gt;
&lt;li&gt;FalkorDB is the brain stem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you ask a question, signals travel from &lt;strong&gt;you&lt;/strong&gt;, through &lt;strong&gt;your groups&lt;/strong&gt;, to each &lt;strong&gt;document&lt;/strong&gt; FalkorDB allowed. Blocked documents get a red signal that stops short. The animation follows the exact path the database used, so it's an honest picture of how the answer was found.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Same question, different people, different answers
&lt;/h3&gt;

&lt;p&gt;Ask &lt;em&gt;"Why did Acme Corp's invoice go up in October?"&lt;/em&gt; as &lt;strong&gt;Priya, a Support intern&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;She gets the answer from the pricing policy: loyalty discounts last 12 months and aren't renewed automatically. Every fact is cited with its source and owner.&lt;/li&gt;
&lt;li&gt;She &lt;strong&gt;does not&lt;/strong&gt; get the contract value or the invoice runs. Instead she sees a locked line: &lt;em&gt;"Contract value and discount. Needs Finance or Leadership access. Ask Arjun Mehta."&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now ask the same thing as &lt;strong&gt;Meera, Head of Finance&lt;/strong&gt;, and the hidden lines become real answers. A "See how someone else sees this" box puts the two answers side by side.&lt;/p&gt;

&lt;p&gt;The brain doesn't pretend restricted things don't exist, and it doesn't leak them either. It tells you what's missing and &lt;strong&gt;who to ask&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. "Why can I see this?"
&lt;/h3&gt;

&lt;p&gt;Every fact has a button that shows the shortest chain of groups behind it, for example &lt;em&gt;Priya → Support → All Staff → Company handbook&lt;/em&gt;. Access stops being a mystery.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Private memory for every person and every agent
&lt;/h3&gt;

&lt;p&gt;The brain remembers what you asked before. Each memory hangs off its owner's node in the graph, and every memory query starts at &lt;em&gt;your&lt;/em&gt; node. That means there is simply &lt;strong&gt;no path&lt;/strong&gt; from me to your memories. The demo proves it: &lt;em&gt;"Priya has 4 memories. Meera can reach 0."&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. AI agents follow the same rules as people
&lt;/h3&gt;

&lt;p&gt;Agents are members of groups, just like people, so they get exactly the access their groups have.&lt;/p&gt;

&lt;p&gt;In the demo, the &lt;strong&gt;Support Agent&lt;/strong&gt; and the &lt;strong&gt;Finance Agent&lt;/strong&gt; share customer ticket #4821. The Finance Agent adds a Finance-only note with the contract details. When the case goes back to the Support Agent, that note is redacted, so the reply to the customer can't leak it. If a draft reply does contain private Finance data, the approve step refuses to send it.&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%2Fqphnaflkinn49ed7zfih.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%2Fqphnaflkinn49ed7zfih.png" alt="Agents sharing a case without leaking" width="800" height="769"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  6. The brain checks itself
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Health check&lt;/strong&gt; compares who &lt;em&gt;should&lt;/em&gt; open each sensitive document with who &lt;em&gt;actually&lt;/em&gt; can, and found all three planted problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Salary bands 2026:&lt;/strong&gt; 211 people can open it instead of 3, all through that forgotten "Drive migration 2023 (temporary)" group.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Q3 board update:&lt;/strong&gt; 34 people instead of 5, through a project group.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ravi Kumar&lt;/strong&gt; moved from Finance to Engineering but is still in the Finance group. That one stale membership alone unlocks 5 things.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The part I'm proudest of: every suggested fix is &lt;strong&gt;tested on a full copy of the company first&lt;/strong&gt;, using FalkorDB's &lt;code&gt;GRAPH.COPY&lt;/code&gt;. The brain forks the graph, applies the fix, and checks that the right people lost access &lt;em&gt;and&lt;/em&gt; that everyone who should keep access still has it. Then it deletes the copy. Only after that does a human approve, and the change is saved as a decision record that the brain can explain later.&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%2Frop871l0l0celvu65li8.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%2Frop871l0l0celvu65li8.png" alt="Health check with a fix tested on a copy" width="800" height="737"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How FalkorDB is used
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Variable-length traversal&lt;/strong&gt; (&lt;code&gt;MEMBER_OF*0..8&lt;/code&gt;) for access, explanations and "who can read this?"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full-text index&lt;/strong&gt; (&lt;code&gt;db.idx.fulltext.queryNodes&lt;/code&gt;) to find candidate passages. Access is then checked on every single one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;GRAPH.COPY&lt;/code&gt;&lt;/strong&gt; to test access fixes on a fork before touching the real company.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One graph per company.&lt;/strong&gt; Northwind and a second company, Bluefin, live side by side and never mix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read-only queries&lt;/strong&gt; for everything an asker can trigger.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;MCP server&lt;/strong&gt;, so any MCP-compatible AI agent can ask the brain questions under its own identity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The number that convinced me the graph matters
&lt;/h2&gt;

&lt;p&gt;I wrote the access rules a second time in plain Python as an independent ground truth. Then I ran 54 askers × 8 questions through three kinds of access check:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Access check&lt;/th&gt;
&lt;th&gt;Leaks&lt;/th&gt;
&lt;th&gt;Wrong denials&lt;/th&gt;
&lt;th&gt;Helpfulness&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Graph traversal (Need-to-Know)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flat permission list (direct groups only)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;521&lt;/td&gt;
&lt;td&gt;37.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No check (a plain document chatbot)&lt;/td&gt;
&lt;td&gt;840&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The graph traversal agreed with the Python ground truth on &lt;strong&gt;100% of 6,634&lt;/strong&gt; (person, passage) pairs.&lt;/p&gt;

&lt;p&gt;A flat permission list is safe but nearly useless: people got only 37.5% of what they were entitled to see. No check is helpful but leaks 840 times. &lt;strong&gt;Only the graph is both safe and helpful&lt;/strong&gt;, because only the graph understands groups inside groups.&lt;/p&gt;

&lt;h2&gt;
  
  
  What broke along the way
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No Docker on my laptop.&lt;/strong&gt; FalkorDB doesn't run natively on Windows, so I ran everything against a real FalkorDB in GitHub Actions instead. It turned out to be the best decision of the weekend. Every push runs 13 tests, the benchmark, a container build and screenshots of every screen, then redeploys the live demo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Answers that drifted.&lt;/strong&gt; My first search ranked anything mentioning "Acme" highly, so asking why Acme's invoice went up returned Acme's liability cap. Now I drop passages that match only on a customer's name, and favour policies and decisions for "why" questions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One line of CSS.&lt;/strong&gt; &lt;code&gt;display: flex&lt;/code&gt; on my tab panels silently beat the browser's &lt;code&gt;hidden&lt;/code&gt; attribute, so every tab rendered at once. &lt;code&gt;[hidden] { display: none !important; }&lt;/code&gt; fixed it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container paths.&lt;/strong&gt; My first Dockerfile used &lt;code&gt;find&lt;/code&gt; to locate the FalkorDB module, but &lt;code&gt;find&lt;/code&gt; isn't in the image. Reading the image config showed it lives at &lt;code&gt;/var/lib/falkordb/bin/falkordb.so&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I'd build next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Connectors that import real groups and documents from Google Workspace, Slack and Notion.&lt;/li&gt;
&lt;li&gt;A live alert when a new share suddenly widens access to something sensitive.&lt;/li&gt;
&lt;li&gt;Time travel: "who could see this document last March?"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://mrayhankhan.github.io/need-to-know/" rel="noopener noreferrer"&gt;https://mrayhankhan.github.io/need-to-know/&lt;/a&gt; (switch "Viewing as" in the top right to see the same brain through different eyes)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/mrayhankhan/need-to-know" rel="noopener noreferrer"&gt;https://github.com/mrayhankhan/need-to-know&lt;/a&gt; (run it locally with two Docker commands)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to WeMakeDevs and FalkorDB for Graph Hacks. Building this made one thing very clear to me: a company brain is only as trustworthy as its sense of who is allowed to know what.&lt;/p&gt;

&lt;h1&gt;
  
  
  GraphHacks #FalkorDB #WeMakeDevs
&lt;/h1&gt;

</description>
      <category>ai</category>
      <category>devchallenge</category>
      <category>llm</category>
      <category>security</category>
    </item>
    <item>
      <title>How I built a flash-sale engine that can't oversell</title>
      <dc:creator>M Rayhan Khan</dc:creator>
      <pubDate>Sat, 13 Jun 2026 05:25:43 +0000</pubDate>
      <link>https://dev.to/m_rayhankhan_71c3f2ed50c/how-i-built-a-flash-sale-engine-that-cant-oversell-even-at-1000-concurrent-buyers-34p5</link>
      <guid>https://dev.to/m_rayhankhan_71c3f2ed50c/how-i-built-a-flash-sale-engine-that-cant-oversell-even-at-1000-concurrent-buyers-34p5</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;I created this piece of content for the purpose of entering the &lt;strong&gt;H0: Hack the Zero Stack&lt;/strong&gt; hackathon. #H0Hackathon&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The problem (that's harder than it sounds)
&lt;/h2&gt;

&lt;p&gt;"Don't sell more tickets than you have" sounds trivial until 10,000 people click &lt;strong&gt;Buy&lt;/strong&gt; in the same second.&lt;/p&gt;

&lt;p&gt;The naive fix — a single &lt;code&gt;remaining&lt;/code&gt; counter you decrement on every purchase — falls apart under load. And when you try to go multi-region, it gets worse: with eventual consistency across regions you can oversell during the replication window.&lt;/p&gt;

&lt;p&gt;I wanted a flash-sale engine that is &lt;strong&gt;globally fast AND strongly consistent AND operationally simple&lt;/strong&gt; — all three. That combination is precisely what &lt;strong&gt;Amazon Aurora DSQL&lt;/strong&gt; is built for, so I built &lt;strong&gt;DropZero&lt;/strong&gt; on it for the hackathon.&lt;/p&gt;




&lt;h2&gt;
  
  
  The trap I almost walked into
&lt;/h2&gt;

&lt;p&gt;Aurora DSQL is a serverless, PostgreSQL-compatible, multi-region active-active SQL database. Crucially, it uses &lt;strong&gt;optimistic concurrency control (OCC)&lt;/strong&gt;: transactions run without locks, and conflicts are detected at commit time — the loser gets a &lt;code&gt;SQLSTATE 40001&lt;/code&gt; serialization error and retries.&lt;/p&gt;

&lt;p&gt;That detail flips the "obvious" design on its head. A single hot counter row that every buyer updates is the &lt;strong&gt;worst&lt;/strong&gt; workload for OCC. Thousands of writes to one key collide at commit time, and you get a retry storm that eats your throughput. AWS's own documentation is explicit: spread writes across the key range.&lt;/p&gt;




&lt;h2&gt;
  
  
  The design that actually works
&lt;/h2&gt;

&lt;p&gt;Instead of a counter, &lt;strong&gt;model each sellable unit as its own database row&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;drop_units&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt;         &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;gen_random_uuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="n"&gt;drop_id&lt;/span&gt;    &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;unit_no&lt;/span&gt;    &lt;span class="nb"&gt;integer&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;status&lt;/span&gt;     &lt;span class="nb"&gt;text&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="s1"&gt;'available'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;-- available | claimed&lt;/span&gt;
  &lt;span class="n"&gt;order_id&lt;/span&gt;   &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;claimed_at&lt;/span&gt; &lt;span class="n"&gt;timestamptz&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each buyer &lt;strong&gt;claims a random distinct unit&lt;/strong&gt; in one strongly-consistent transaction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/store-dsql.ts (simplified)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;reserveUnit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dropId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;withRetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Find a random available unit, claim it atomically&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;candidates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;`SELECT id FROM drop_units
          WHERE drop_id = $1 AND status = 'available'
          ORDER BY random() LIMIT 5`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dropId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SOLD_OUT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// Race for one — OCC means only one wins per row&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="s2"&gt;`UPDATE drop_units
              SET status = 'claimed', order_id = $1, claimed_at = now()
            WHERE id = $2 AND status = 'available'
            RETURNING unit_no`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rowCount&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RETRY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;unit_no&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;withRetry&lt;/code&gt; only re-runs on &lt;code&gt;SQLSTATE 40001&lt;/code&gt; (OCC conflict), with jittered exponential backoff. Everything else surfaces immediately.&lt;/p&gt;

&lt;p&gt;Two properties fall out of this design for free:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Overselling is impossible by construction.&lt;/strong&gt; Each row transitions &lt;code&gt;available → claimed&lt;/code&gt; at most once, enforced by the &lt;code&gt;WHERE status = 'available'&lt;/code&gt; predicate in a strongly-consistent transaction. So &lt;code&gt;claimed ≤ total&lt;/code&gt; always holds — regardless of region count or traffic spike.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Conflicts stay near zero.&lt;/strong&gt; Because buyers target &lt;em&gt;random&lt;/em&gt; rows, 5,000 simultaneous buyers touch ~5,000 &lt;em&gt;different&lt;/em&gt; rows. DSQL is optimized for exactly this write pattern. The few genuine collisions (two buyers picking the same random row) are retried transparently.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  An extra layer: idempotency
&lt;/h2&gt;

&lt;p&gt;Double-clicks and network retries can cause a buyer to send the same request twice. I added a unique index on &lt;code&gt;idempotency_key&lt;/code&gt; in the &lt;code&gt;orders&lt;/code&gt; table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;orders_idempotency_key&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idempotency_key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The claim function checks this first — if the key already produced an order, return it. A double-click never double-buys.&lt;/p&gt;




&lt;h2&gt;
  
  
  Proving it: the stampede simulator
&lt;/h2&gt;

&lt;p&gt;DropZero ships with a built-in concurrency simulator. Click &lt;strong&gt;Run stampede&lt;/strong&gt;, choose a buyer count and a drop with limited inventory, and the app fires that many concurrent purchase requests.&lt;/p&gt;

&lt;p&gt;Result for &lt;strong&gt;1,000 buyers racing for 200 units&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;confirmed:   200   (exactly the inventory)
rejected:    800   (clean SOLD_OUT, not errors)
oversold:      0
conflicts:     2   (OCC retries, resolved transparently)
p99 latency: 42ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every time. The "integrity proof" button runs a live &lt;code&gt;SELECT COUNT(*)&lt;/code&gt; grouped by status to confirm &lt;code&gt;claimed = 200&lt;/code&gt; and &lt;code&gt;available = 0&lt;/code&gt; with no ghost rows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Aurora DSQL specifically
&lt;/h2&gt;

&lt;p&gt;Other databases could prevent overselling — but usually with trade-offs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Single-region RDS with row locks&lt;/td&gt;
&lt;td&gt;Locks under high concurrency → queue → latency spike&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redis DECR with Lua&lt;/td&gt;
&lt;td&gt;Fast but not durable by default; adding durability adds complexity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DynamoDB conditional writes&lt;/td&gt;
&lt;td&gt;No SQL; harder to model the relational parts (orders, seller analytics)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CockroachDB / Spanner&lt;/td&gt;
&lt;td&gt;Great, but operational overhead; not serverless&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Aurora DSQL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Serverless, PostgreSQL SQL, multi-region active-active, strongly consistent, zero ops&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;DSQL specifically solves the "global buyers, one inventory" problem without a waiting room, without a single write bottleneck, and without giving up strong consistency. It's the right tool for this workload.&lt;/p&gt;




&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Choice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Next.js 14 (App Router) + Tailwind CSS + SWR for live polling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API&lt;/td&gt;
&lt;td&gt;Next.js Route Handlers (Node runtime)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Amazon Aurora DSQL&lt;/strong&gt; — serverless, multi-region, PostgreSQL-compatible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DB auth&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pg&lt;/code&gt; driver + &lt;code&gt;@aws-sdk/dsql-signer&lt;/code&gt; — IAM auth tokens, no stored passwords&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosting&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Vercel&lt;/strong&gt; + Vercel Marketplace OIDC integration (keyless AWS access)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The OIDC integration is worth calling out: Vercel assumes an AWS IAM role per deployment. No &lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; or &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt; anywhere in the project. Zero stored credentials.&lt;/p&gt;




&lt;h2&gt;
  
  
  One schema note: DSQL doesn't support foreign keys or synchronous indexes
&lt;/h2&gt;

&lt;p&gt;DSQL is not vanilla PostgreSQL. I hit two constraints that shaped the schema:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No foreign keys.&lt;/strong&gt; &lt;code&gt;orders.drop_id&lt;/code&gt; and &lt;code&gt;drop_units.drop_id&lt;/code&gt; are logical references enforced in application code, not DB constraints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Indexes must be &lt;code&gt;CREATE INDEX ASYNC&lt;/code&gt;.&lt;/strong&gt; The &lt;code&gt;db:init&lt;/code&gt; script auto-rewrites &lt;code&gt;CREATE INDEX&lt;/code&gt; → &lt;code&gt;CREATE INDEX ASYNC&lt;/code&gt; when it detects a DSQL endpoint. Otherwise the migration hangs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batched inserts under 10k rows/txn.&lt;/strong&gt; When minting units for a large drop, inserts are batched in chunks of 500.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are reasonable constraints for what DSQL gives you in return.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://dropzero.vercel.app" rel="noopener noreferrer"&gt;https://dropzero.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/mrayhankhan/dropzero" rel="noopener noreferrer"&gt;https://github.com/mrayhankhan/dropzero&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The app runs in zero-credential preview mode (in-memory) by default, so you can poke around without an AWS account. The badge in the header tells you which mode you're in.&lt;/p&gt;




&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;Distributed databases don't remove the hard parts of concurrency — they move them into your data model. Aurora DSQL's OCC model is powerful, but it punishes designs with hot rows and rewards designs with spread-out writes.&lt;/p&gt;

&lt;p&gt;Turn one hot counter into many cool unit rows, and a gnarly distributed-systems problem becomes a dozen lines of SQL — with a mathematically provable guarantee baked in.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built for the &lt;a href="https://h01.devpost.com" rel="noopener noreferrer"&gt;H0: Hack the Zero Stack&lt;/a&gt; hackathon — Track 3 (Million-scale Global App). #H0Hackathon&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>postgres</category>
      <category>nextjs</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How I built a dependency risk scanner with Coral</title>
      <dc:creator>M Rayhan Khan</dc:creator>
      <pubDate>Sat, 30 May 2026 18:33:39 +0000</pubDate>
      <link>https://dev.to/m_rayhankhan_71c3f2ed50c/how-i-built-a-dependency-risk-scanner-with-coral-in-7-days-4p9</link>
      <guid>https://dev.to/m_rayhankhan_71c3f2ed50c/how-i-built-a-dependency-risk-scanner-with-coral-in-7-days-4p9</guid>
      <description>&lt;h2&gt;
  
  
  Why this project
&lt;/h2&gt;

&lt;p&gt;Every developer has 5-10 side projects with rotting dependencies and doesn't know it. The 2024 xz-utils backdoor was caught &lt;strong&gt;by accident&lt;/strong&gt; — one engineer noticed SSH was 500 ms slower than usual. That's how close it came.&lt;/p&gt;

&lt;p&gt;Tools like Snyk and Dependabot catch known CVEs after they're published. Nothing checks the three signals that &lt;em&gt;together&lt;/em&gt; predict a future supply-chain attack: &lt;strong&gt;active CVEs · abandoned maintainer · collapsing downloads&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That three-way signal only exists if you can JOIN across &lt;strong&gt;OSV&lt;/strong&gt; (Google's vulnerability database), the &lt;strong&gt;npm registry&lt;/strong&gt;, and the &lt;strong&gt;npm download API&lt;/strong&gt;. Which is exactly what Coral does.&lt;/p&gt;

&lt;h2&gt;
  
  
  The query the whole project is built around
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;pkg&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;latest_version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repository__url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time__modified&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;last_publish_at&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;npm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;packages&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;package_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;pkg&lt;/span&gt;
&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;cves&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;affected__package__name&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;package_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;cve_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="n"&gt;database_specific__severity&lt;/span&gt;
               &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="s1"&gt;'CRITICAL'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="s1"&gt;'HIGH'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
               &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="s1"&gt;'MODERATE'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="s1"&gt;'LOW'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;worst_sev_rank&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;osv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vulnerabilities&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;package_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;pkg&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;ecosystem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'npm'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;withdrawn&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
  &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;affected__package__name&lt;/span&gt;
&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;dl_month&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;downloads&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;npm_downloads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;downloads_last_month&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;package_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;pkg&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;COALESCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cves&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cve_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;cve_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;COALESCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cves&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;worst_sev_rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;worst_severity_rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;dl_month&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;downloads&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pkg&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;cves&lt;/span&gt;     &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;cves&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;package_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;dl_month&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One query. Three live systems — three different hosts (&lt;code&gt;registry.npmjs.org&lt;/code&gt;, &lt;code&gt;api.osv.dev&lt;/code&gt;, &lt;code&gt;api.npmjs.org&lt;/code&gt;). Zero glue code. &lt;strong&gt;No ChatGPT instance on earth can run this.&lt;/strong&gt; Verified against &lt;code&gt;minimist&lt;/code&gt;: 2 CVEs, worst severity CRITICAL, 531M downloads/month.&lt;/p&gt;

&lt;h2&gt;
  
  
  The OSV source spec
&lt;/h2&gt;

&lt;p&gt;OSV is a public REST API. The Coral source spec is a single YAML file, and the skeleton came together quickly. The hard part started right after.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;vulnerabilities&lt;/code&gt; table uses &lt;code&gt;POST /v1/query&lt;/code&gt;. Two things bit me, and both were about &lt;em&gt;reading the response shape correctly&lt;/em&gt; rather than writing YAML:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;__&lt;/code&gt; flatten convention isn't automatic.&lt;/strong&gt; I assumed a column named &lt;code&gt;database_specific__severity&lt;/code&gt; would auto-resolve the nested &lt;code&gt;database_specific.severity&lt;/code&gt;. It didn't — it came back &lt;code&gt;null&lt;/code&gt;. Nested fields need an explicit &lt;code&gt;expr&lt;/code&gt;:
&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="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;database_specific__severity&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;Utf8&lt;/span&gt;
     &lt;span class="na"&gt;expr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;path&lt;/span&gt;
       &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;database_specific&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Array indexing uses string keys.&lt;/strong&gt; To lift the package name out of the &lt;code&gt;affected[]&lt;/code&gt; array as a JOIN key, the path is &lt;code&gt;[affected, "0", package, name]&lt;/code&gt; — &lt;code&gt;"0"&lt;/code&gt; as a &lt;em&gt;string&lt;/em&gt;, not an integer (the integer form fails schema validation).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;coral source lint&lt;/code&gt; caught my structural mistakes offline; the nested-path mistakes only showed up when I ran a real query against &lt;code&gt;lodash&lt;/code&gt; and &lt;code&gt;minimist&lt;/code&gt; and saw &lt;code&gt;null&lt;/code&gt; columns. No tool tells you that — you have to diff the response against your spec by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  The npm specs (note the plural)
&lt;/h2&gt;

&lt;p&gt;This is where I learned the most. npm is really two APIs: &lt;code&gt;registry.npmjs.org&lt;/code&gt; for package metadata and &lt;code&gt;api.npmjs.org&lt;/code&gt; for download counts. My first instinct was one source spec with a per-table &lt;code&gt;base_url&lt;/code&gt; override.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That field doesn't exist.&lt;/strong&gt; A Coral source has exactly one &lt;code&gt;base_url&lt;/code&gt;. The clean fix turned out to be better than the hack: &lt;strong&gt;two source specs&lt;/strong&gt;. &lt;code&gt;npm.yaml&lt;/code&gt; (the &lt;code&gt;packages&lt;/code&gt; table) and &lt;code&gt;npm_downloads.yaml&lt;/code&gt; (&lt;code&gt;downloads_last_month&lt;/code&gt; + &lt;code&gt;downloads_last_week&lt;/code&gt;). That's not a workaround — it's a second genuinely reusable spec, and it doubled my bounty surface area.&lt;/p&gt;

&lt;p&gt;The other lesson: a declared &lt;code&gt;filter&lt;/code&gt; must &lt;em&gt;also&lt;/em&gt; be declared as a column for &lt;code&gt;WHERE package_name = ...&lt;/code&gt; to resolve, and the filter value isn't echoed back automatically — so JOINs key off real returned columns (&lt;code&gt;npm.packages.name&lt;/code&gt;, &lt;code&gt;downloads.package&lt;/code&gt;, &lt;code&gt;osv.affected__package__name&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  The fan-out
&lt;/h2&gt;

&lt;p&gt;The auditor reads &lt;code&gt;package.json&lt;/code&gt; from a GitHub raw URL, collects every dependency (including devDependencies — supply-chain attacks via dev tools are real, see event-stream), and runs the query once per dep with 6-way concurrency. &lt;code&gt;chalk/chalk&lt;/code&gt; finished in ~17 seconds. &lt;code&gt;lib/concurrency.ts&lt;/code&gt; is 30 lines.&lt;/p&gt;

&lt;h2&gt;
  
  
  The dashboard
&lt;/h2&gt;

&lt;p&gt;Three columns: 🟢 healthy / 🟡 watch / 🔴 danger. Click a card → drill-down with every signal and a direct link to the OSV record. The whole UI is in &lt;a href="//./app/components/"&gt;&lt;code&gt;app/components/&lt;/code&gt;&lt;/a&gt; — three files, all client components, Tailwind for styling. GitHub maintainer-activity (last push, archived) is layered on top via the bundled &lt;code&gt;github&lt;/code&gt; source when a token is present — deliberately kept &lt;em&gt;out&lt;/em&gt; of the headline query so the demo runs with zero auth.&lt;/p&gt;

&lt;h2&gt;
  
  
  The scoring rules
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;lib/risk.ts&lt;/code&gt; is a pure function, and the scoring rules are the part I most wanted to get right by hand — this is product judgment, not codegen. Easy to unit-test. Rules I landed on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CVE HIGH/CRITICAL → instant danger.&lt;/strong&gt; No nuance needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stale + collapsing → danger.&lt;/strong&gt; Maintainer silent &amp;gt; 1 year AND downloads down &amp;gt; 30%. This is the xz-utils pattern.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stale OR declining → watch.&lt;/strong&gt; Either alone is a yellow flag, not red.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Otherwise → healthy.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The compound rule was the one that took the most reading. A package can have no CVE filed yet and still be the most dangerous thing in your repo if the maintainer has gone dark.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fallback path
&lt;/h2&gt;

&lt;p&gt;I built a transparent HTTP fallback (&lt;code&gt;lib/coral.ts&lt;/code&gt; path B) so the demo doesn't break on a laptop without Coral installed. &lt;strong&gt;Same data, same row shape&lt;/strong&gt;, just bypassing the CLI. The header shows &lt;code&gt;coral CLI&lt;/code&gt; vs &lt;code&gt;direct HTTP fallback&lt;/code&gt; so judges can see which path is active. The fallback is a safety net; Coral is the production engine.&lt;/p&gt;

&lt;p&gt;One subtlety that cost me an hour: Coral's SQL engine is DataFusion, not SQLite. So &lt;code&gt;julianday()&lt;/code&gt; and &lt;code&gt;json_group_array()&lt;/code&gt; don't exist — the date math is &lt;code&gt;date_part('day', now() - to_timestamp(col))&lt;/code&gt; and the CVE list is &lt;code&gt;array_agg(named_struct(...))&lt;/code&gt;. Worth knowing before you write the query.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Three insights I didn't expect:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The hard part of source specs isn't writing them — it's reading the API docs accurately.&lt;/strong&gt; Scaffolding the YAML is fast (with or without an assistant). I spent far more time confirming OSV's nested field paths against real responses than authoring the spec. Every &lt;code&gt;null&lt;/code&gt; column was a docs-reading miss, not a syntax error — and no tool catches those for you.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The cross-source JOIN really does feel like magic in the terminal.&lt;/strong&gt; Three completely separate systems, one result set, one query. The demo moment isn't the dashboard — it's the &lt;code&gt;coral sql&lt;/code&gt; invocation. Everyone leans forward.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pure scoring functions are worth their weight in unit tests.&lt;/strong&gt; Once &lt;code&gt;lib/risk.ts&lt;/code&gt; was unit-tested I could change the rules without fear. The 12 tests in &lt;code&gt;risk.test.ts&lt;/code&gt; caught two regressions during the hackathon.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;The repo is on GitHub. Three custom source specs, one Next.js app, MIT licensed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/mrayhankhan/CoralBean.git
bash scripts/install-coral.sh
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste &lt;code&gt;facebook/react&lt;/code&gt; (mostly green) or &lt;code&gt;chalk/chalk&lt;/code&gt; (watch &lt;code&gt;color-convert&lt;/code&gt; go red) and watch.&lt;/p&gt;

&lt;p&gt;🏴‍☠️&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
