<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://logicbee.ai/blog</id>
    <title>Logic Bee Blog</title>
    <updated>2026-04-01T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://logicbee.ai/blog"/>
    <subtitle>Logic Bee Blog</subtitle>
    <icon>https://logicbee.ai/logo/logo-blue-2.jpg</icon>
    <entry>
        <title type="html"><![CDATA[Anatomy of a CSV Import Pipeline — Where 90% of the Work Happens Before the First Write]]></title>
        <id>https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline</id>
        <link href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline"/>
        <updated>2026-04-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Your CSV is not your data. It's a promise that needs verification, transformation, and three layers of validation before it earns the right to touch your database. Here's how a production import hook turns a tab-delimited file into trusted journal entries.]]></summary>
        <content type="html"><![CDATA[<p>Your CSV is not your data. It's a promise that needs verification, transformation, and three layers of validation before it earns the right to touch your database. Here's how a production import hook turns a tab-delimited file into trusted journal entries.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-premise">The Premise<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#the-premise" class="hash-link" aria-label="Direct link to The Premise" title="Direct link to The Premise" translate="no">​</a></h2>
<p>Every data import starts with the same fantasy: upload a file, click import, done. The reality is a defensive pipeline where the database write — the part most people think of as "the import" — is the very last step, and often the simplest one. The hard work is everything that comes before it.</p>
<p>This article dissects a production hook that imports general ledger journal entries from an external accounting system's CSV export. The hook is 300+ lines. Fewer than 20 of those lines actually write to the database.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-source-data-problem">The Source Data Problem<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#the-source-data-problem" class="hash-link" aria-label="Direct link to The Source Data Problem" title="Direct link to The Source Data Problem" translate="no">​</a></h2>
<p>Before writing a single line of import code, you need to confront an uncomfortable truth: <strong>the source data is your responsibility</strong>. The external system exported it. Your users downloaded it. Nobody in that chain guarantees it's clean.</p>
<p>In this pipeline, the source is a tab-delimited CSV with columns like <code>Trans #</code>, <code>Date</code>, <code>GL Code</code>, <code>Debit</code>, <code>Credit</code>, <code>Memo</code>, and <code>Class</code>. Each row is a single journal item line. Multiple rows share the same <code>Trans #</code> to form a compound journal entry.</p>
<p>The file could have:</p>
<ul>
<li class="">Rows with no transaction number (separator lines, subtotals)</li>
<li class="">GL codes that don't exist in your chart of accounts</li>
<li class="">Amounts formatted with US thousands commas (<code>1,250.00</code>)</li>
<li class="">Stray quote characters from copy-paste artifacts</li>
<li class="">Zero-amount lines (e.g., <code>Sales Tax Payable 0.00</code>)</li>
</ul>
<p>The hook's job isn't to "import a CSV." It's to <strong>distill a messy file into trusted financial documents</strong> — or reject the entire batch with a clear explanation of why.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-pipeline">The Pipeline<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#the-pipeline" class="hash-link" aria-label="Direct link to The Pipeline" title="Direct link to The Pipeline" translate="no">​</a></h2>
<p>Here's the shape of the import, with the write at the end where it belongs:</p>
<div class="language-mermaid codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-mermaid codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token plain">flowchart LR</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  A["Source File"] --&gt; B["Download"] --&gt; C["Parse"] --&gt; D["Clean"] --&gt; E["Group"] --&gt; F["Preflight Validate"] --&gt; G["Deduplicate"] --&gt; H["Build Payloads"] --&gt; I["Write"] --&gt; J["Report"]</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  style I fill:#16a34a,color:#fff,stroke:#15803d</span><br></span></code></pre></div></div>
<p>Nine steps. Only one writes to the database. Let's walk through them.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="step-1-validate-the-request">Step 1: Validate the Request<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#step-1-validate-the-request" class="hash-link" aria-label="Direct link to Step 1: Validate the Request" title="Direct link to Step 1: Validate the Request" translate="no">​</a></h2>
<p>Before downloading or parsing anything, validate that the request itself is well-formed:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">validator</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">joi</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">validateData</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> fileUrl</span><span class="token operator">:</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">dataPayload</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">fileUrl </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  SuperJoi</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">object</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    fileUrl</span><span class="token operator">:</span><span class="token plain"> SuperJoi</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">string</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">required</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getUserInfo</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>If there's no file URL, fail immediately. Don't download, don't parse, don't allocate memory. Guard clauses first.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="step-2-load-reference-data">Step 2: Load Reference Data<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#step-2-load-reference-data" class="hash-link" aria-label="Direct link to Step 2: Load Reference Data" title="Direct link to Step 2: Load Reference Data" translate="no">​</a></h2>
<p>Before you can validate the CSV, you need to know what "valid" means. That means loading the reference datasets the import will validate against:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// --&gt;Get: all active general ledger accounts</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> generalLedgerAccounts </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> generalLedgerFlowCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">addPolicy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'canRead'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">cache</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">generalLedgerAccountNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">limit</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token number">10000</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getMany</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'FinanceInterface.GeneralLedgerAccount'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// --&gt;Get: warehouses</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> warehouses </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> warehouseFlowCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">addPolicy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'canRead'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getDocumentStatuses</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">'active'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'data'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">cache</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">warehouseNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">limit</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token number">100</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getMany</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'InventoryManagementInterface.Warehouse'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>Notice the <code>.cache()</code> — these datasets are stable reference data. And notice the hard limit. You never query reference data without a ceiling.</p>
<p>Both queries fail fast with descriptive errors if they return empty:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">generalLedgerAccounts</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">length </span><span class="token operator">===</span><span class="token plain"> </span><span class="token number">0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">throw</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">naoFormatErrorById</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'bad_request'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    reason</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'Failed to find general ledger accounts'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>No GL accounts means no chart of accounts means no point continuing. The error is specific enough that the user knows exactly what to fix.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="step-3-ensure-preconditions">Step 3: Ensure Preconditions<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#step-3-ensure-preconditions" class="hash-link" aria-label="Direct link to Step 3: Ensure Preconditions" title="Direct link to Step 3: Ensure Preconditions" translate="no">​</a></h2>
<p>Some imports depend on system state that might not exist yet. This hook ensures fiscal periods and years are created before any journal entries are written:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">executeRequestOrThrow</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">ensureFiscalPeriodsActionCfpQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>This is easy to overlook. If you write a journal entry dated March 2024 and no fiscal period exists for Q1 2024, the entry either fails silently or lands in an undefined period. The hook handles this <em>before</em> it even looks at the CSV.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="step-4-build-the-deduplication-index">Step 4: Build the Deduplication Index<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#step-4-build-the-deduplication-index" class="hash-link" aria-label="Direct link to Step 4: Build the Deduplication Index" title="Direct link to Step 4: Build the Deduplication Index" translate="no">​</a></h2>
<p>For idempotent imports — where re-running the same file shouldn't create duplicates — you need to know what already exists:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> existingJournalEntries </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> journalEntryFlowCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">addPolicy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'canRead'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">journalEntryNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.name'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> $regex</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'^PIPE-'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">projection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.name'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">1</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">limit</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token number">2_000_000</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getMany</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'FinanceInterface.JournalEntry'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> existingJournalNameSet</span><span class="token operator">:</span><span class="token plain"> Set</span><span class="token operator">&lt;</span><span class="token builtin" style="color:rgb(189, 147, 249)">string</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">new</span><span class="token plain"> </span><span class="token class-name">Set</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  existingJournalEntries</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">map</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">je</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> je</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">name</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>Two things to highlight here. First, the <code>.projection({ 'data.name': 1 })</code> — we only need the name field, so we only fetch the name field. With 2 million potential records, this is the difference between a 30-second query and a timeout. Second, the <code>Set</code> — O(1) lookup for every deduplication check instead of scanning an array.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="step-5-parse-and-clean">Step 5: Parse and Clean<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#step-5-parse-and-clean" class="hash-link" aria-label="Direct link to Step 5: Parse and Clean" title="Direct link to Step 5: Parse and Clean" translate="no">​</a></h2>
<p>Now — and only now — do we touch the CSV:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> glCsv </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">new</span><span class="token plain"> </span><span class="token class-name">NaoCsvRunner2</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">loadFile</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  inputFilePath</span><span class="token operator">:</span><span class="token plain"> downloadToLocalTemp</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">filePath</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  delimiter</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'\t'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> allRowsRaw </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> glCsv</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">readFile</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> numberOfLines</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">Infinity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> allRows </span><span class="token operator">=</span><span class="token plain"> allRowsRaw</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">filter</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">row</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">any</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">cleanValue</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">row</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">'Trans #'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>The <code>cleanValue</code> helper does the unglamorous work that prevents downstream failures:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> cleanValue </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">v</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">string</span><span class="token plain"> </span><span class="token operator">|</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">string</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">v </span><span class="token operator">||</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">''</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">trim</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">replace</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token regex regex-delimiter">/</span><span class="token regex regex-source language-regex">"</span><span class="token regex regex-source language-regex quantifier number">+</span><span class="token regex regex-delimiter">/</span><span class="token regex regex-flags">g</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">''</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>Trim whitespace. Strip stray quotes. Return an empty string instead of <code>undefined</code>. Every field in the CSV passes through this function before it's used anywhere. It's three lines of code that prevent dozens of edge-case bugs.</p>
<p>The filter step drops rows with no <code>Trans #</code> — subtotal rows, blank lines, section headers. These aren't data. They're presentation artifacts from the source system's export.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="step-6-preflight-validation--the-gate">Step 6: Preflight Validation — The Gate<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#step-6-preflight-validation--the-gate" class="hash-link" aria-label="Direct link to Step 6: Preflight Validation — The Gate" title="Direct link to Step 6: Preflight Validation — The Gate" translate="no">​</a></h2>
<p>This is the most important step in the entire pipeline, and it happens before a single document is created.</p>
<p>The hook scans <em>every row</em> in the file and checks that every GL code exists in the system's chart of accounts:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> existingGlCodes</span><span class="token operator">:</span><span class="token plain"> Set</span><span class="token operator">&lt;</span><span class="token builtin" style="color:rgb(189, 147, 249)">string</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">new</span><span class="token plain"> </span><span class="token class-name">Set</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  generalLedgerAccounts</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">map</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">gl</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> gl</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">code</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> missingGlCodeLines</span><span class="token operator">:</span><span class="token plain"> Map</span><span class="token operator">&lt;</span><span class="token builtin" style="color:rgb(189, 147, 249)">string</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">number</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">new</span><span class="token plain"> </span><span class="token class-name">Map</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">let</span><span class="token plain"> i </span><span class="token operator">=</span><span class="token plain"> </span><span class="token number">0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"> i </span><span class="token operator">&lt;</span><span class="token plain"> allRows</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">length</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"> i</span><span class="token operator">++</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> glCode </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">cleanValue</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">allRows</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain">i</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">'GL Code'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token operator">!</span><span class="token plain">existingGlCodes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">has</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">glCode</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> lineNumber </span><span class="token operator">=</span><span class="token plain"> i </span><span class="token operator">+</span><span class="token plain"> </span><span class="token number">2</span><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)">// +1 for 1-indexed, +1 for header row</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token operator">!</span><span class="token plain">missingGlCodeLines</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">has</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">glCode</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      missingGlCodeLines</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">set</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">glCode</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    missingGlCodeLines</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">get</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">glCode</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">push</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">lineNumber</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>If any GL codes are missing, the entire import aborts — with a detailed error listing every invalid code and the exact line numbers where they appear:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">missingGlCodeLines</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">size </span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token number">0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain">code</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> lines</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">of</span><span class="token plain"> missingGlCodeLines</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">entries</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    naoLogger</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">error</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string string" style="color:rgb(255, 121, 198)">Missing GL code: "</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">code</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string string" style="color:rgb(255, 121, 198)">" — found on </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">lines</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation">length</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string string" style="color:rgb(255, 121, 198)"> rows: lines </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">lines</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation function" style="color:rgb(80, 250, 123)">join</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string interpolation string" style="color:rgb(255, 121, 198)">', '</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">throw</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">naoFormatErrorById</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'bad_request'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    reason</span><span class="token operator">:</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string string" style="color:rgb(255, 121, 198)">Import aborted — </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">missingGlCodeLines</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation">size</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string string" style="color:rgb(255, 121, 198)"> GL codes not found: </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token template-string interpolation operator">...</span><span class="token template-string interpolation">missingGlCodeLines</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation function" style="color:rgb(80, 250, 123)">keys</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation function" style="color:rgb(80, 250, 123)">join</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string interpolation string" style="color:rgb(255, 121, 198)">', '</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>This is an all-or-nothing gate. The pipeline doesn't import 9,950 valid rows and skip 50 bad ones — that would leave your ledger in a partial state. It validates everything first, then processes everything. <strong>Fail before you begin, not while you're halfway through.</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="step-7-group-and-transform">Step 7: Group and Transform<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#step-7-group-and-transform" class="hash-link" aria-label="Direct link to Step 7: Group and Transform" title="Direct link to Step 7: Group and Transform" translate="no">​</a></h2>
<p>CSV rows are flat. Journal entries are compound documents with a header and multiple line items. The grouping step bridges that gap:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> groupedTransactions </span><span class="token operator">=</span><span class="token plain"> naoUtils</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">_</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">groupBy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  allRows</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">row</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">any</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">cleanValue</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">row</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">'Trans #'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>Each group becomes one journal entry. Within the group, every row is transformed into a typed journal item line. This is where raw strings become domain objects:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// --&gt;Parse: amounts — strip US thousands commas then convert to number</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> debitAmount </span><span class="token operator">=</span><span class="token plain"> naoUtils</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">_</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">toNumber</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">debitRaw </span><span class="token operator">||</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'0'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">replace</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token regex regex-delimiter">/</span><span class="token regex regex-source language-regex">,</span><span class="token regex regex-delimiter">/</span><span class="token regex regex-flags">g</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">''</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">||</span><span class="token plain"> </span><span class="token number">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> creditAmount </span><span class="token operator">=</span><span class="token plain"> naoUtils</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">_</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">toNumber</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">creditRaw </span><span class="token operator">||</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'0'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">replace</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token regex regex-delimiter">/</span><span class="token regex regex-source language-regex">,</span><span class="token regex regex-delimiter">/</span><span class="token regex regex-flags">g</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">''</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">||</span><span class="token plain"> </span><span class="token number">0</span><br></span></code></pre></div></div>
<p>Dates get the same treatment — string to <code>DateTime</code> object via <code>naoDateTime()</code>, never <code>new Date()</code>:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token plain">journalEntryDate</span><span class="token operator">:</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">naoDateTime</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">date</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">toJSDate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">accountingDate</span><span class="token operator">:</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">naoDateTime</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">date</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">toJSDate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><br></span></code></pre></div></div>
<p>Every field is explicitly converted to its target type. Strings become numbers. Date strings become Date objects. GL codes become document references via lookup. The CSV column <code>Class</code> becomes a <code>warehouseId</code> through a resolution function. Nothing arrives at the database in its original CSV form.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="step-8-write--the-easy-part">Step 8: Write — The Easy Part<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#step-8-write--the-easy-part" class="hash-link" aria-label="Direct link to Step 8: Write — The Easy Part" title="Direct link to Step 8: Write — The Easy Part" translate="no">​</a></h2>
<p>After all that preparation, the actual write is anticlimactic:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">executeRequestOrThrow</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">createJournalEntryWithItemsActionCfpQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  payload</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> skipSession</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> skipEvent</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">countCreated</span><span class="token operator">++</span><br></span></code></pre></div></div>
<p>One call per journal entry. The <code>skipSession: true</code> flag is deliberate — each entry auto-commits independently, avoiding MongoDB's 60-second transaction timeout on long-running imports. The <code>skipEvent: true</code> prevents downstream event cascades during bulk import.</p>
<p>Notice what's <em>not</em> here: no validation, no deduplication, no type conversion. All of that was handled in steps 1 through 7. The write trusts the pipeline above it.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="the-preferred-alternative-flowbulk">The Preferred Alternative: flowBulk<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#the-preferred-alternative-flowbulk" class="hash-link" aria-label="Direct link to The Preferred Alternative: flowBulk" title="Direct link to The Preferred Alternative: flowBulk" translate="no">​</a></h3>
<p>The <code>executeRequestOrThrow</code> approach works here because each journal entry is a compound document — a header with nested line items — and the downstream hook (<code>create-data-entry-for-journal-entry</code>) handles that compound creation logic. We're delegating to a hook that knows how to build both the parent and child documents atomically.</p>
<p>But for simpler, flat document imports — GL accounts, contacts, products, warehouses — <strong>flowBulk is the preferred write strategy.</strong> It batches all operations into a single database round-trip, which is dramatically faster than sequential per-document calls.</p>
<p>Here's what the write step looks like with flowBulk:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// --&gt;Get: the flow collection</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> flowCollection </span><span class="token operator">=</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowGlobal</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getFlowCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">glNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// --&gt;Init: bulk orders</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> flowBulk </span><span class="token operator">=</span><span class="token plain"> flowCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">glNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">bulkOrders</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// --&gt;Build: bulk insert operations from prepared payloads</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> flowQuery </span><span class="token operator">=</span><span class="token plain"> flowCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">glNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> account </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">of</span><span class="token plain"> preparedAccounts</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> flowData </span><span class="token operator">=</span><span class="token plain"> flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowData</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">setData</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">account</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  flowBulk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">insertOne</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">flowData</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// --&gt;Execute: all operations in a single batch</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">flowBulk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">length </span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token number">0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  data </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> flowCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">runBulk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> flowBulk </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">dbSession</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>The performance difference is significant. Importing 10,000 GL accounts with <code>executeRequestOrThrow</code> in a loop takes ~500 seconds (50ms × 10,000). The same import with flowBulk takes ~2 seconds — one database round-trip for the entire batch.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="when-to-use-which">When to Use Which<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#when-to-use-which" class="hash-link" aria-label="Direct link to When to Use Which" title="Direct link to When to Use Which" translate="no">​</a></h3>
<table><thead><tr><th>Strategy</th><th>Use When</th><th>Trade-off</th></tr></thead><tbody><tr><td><code>executeRequestOrThrow</code></td><td>Compound documents (header + lines), or when the write triggers business logic in a downstream hook</td><td>Slower — one network round-trip per document, but each entry is independently committed and validated by the target hook</td></tr><tr><td><code>flowBulk</code></td><td>Flat document imports (accounts, contacts, products) where you're writing directly to a collection</td><td>Faster — single batch operation, but you own all validation and no downstream hooks fire</td></tr></tbody></table>
<p>The journal entry import in this article uses <code>executeRequestOrThrow</code> because the <code>create-data-entry-for-journal-entry</code> hook does more than just insert — it creates the journal header, generates line items, calculates balances, and links to fiscal periods. That logic already exists and is tested. Duplicating it inside the import hook would be a mistake.</p>
<p><strong>Use flowBulk when you can. Fall back to per-entry calls when the write involves business logic you shouldn't be reimplementing.</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="step-9-monitor-and-report">Step 9: Monitor and Report<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#step-9-monitor-and-report" class="hash-link" aria-label="Direct link to Step 9: Monitor and Report" title="Direct link to Step 9: Monitor and Report" translate="no">​</a></h2>
<p>The hook tracks every outcome:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">let</span><span class="token plain"> countCreated </span><span class="token operator">=</span><span class="token plain"> </span><span class="token number">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">let</span><span class="token plain"> countSkipped </span><span class="token operator">=</span><span class="token plain"> </span><span class="token number">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">let</span><span class="token plain"> countDuplicate </span><span class="token operator">=</span><span class="token plain"> </span><span class="token number">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> skippedRows</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> transNum</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">string</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"> reason</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">string</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><br></span></code></pre></div></div>
<p>Memory usage is monitored every 30 seconds during long imports:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> memoryInterval </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">setInterval</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> mem </span><span class="token operator">=</span><span class="token plain"> process</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">memoryUsage</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  naoLogger</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">log</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string string" style="color:rgb(255, 121, 198)">Memory — heap: </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string interpolation">mem</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation">heapUsed </span><span class="token template-string interpolation operator">/</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation number">1024</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation operator">/</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation number">1024</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation function" style="color:rgb(80, 250, 123)">toFixed</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string interpolation number">1</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string string" style="color:rgb(255, 121, 198)">MB</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">30_000</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>Progress is logged every 500 transactions. And the final result gives you the full picture:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token plain">data </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> countCreated</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> countSkipped</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> countDuplicate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> skippedRows </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>No silent failures. No "import complete" with no details. Every row is accounted for.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-pipeline-at-a-glance">The Pipeline at a Glance<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#the-pipeline-at-a-glance" class="hash-link" aria-label="Direct link to The Pipeline at a Glance" title="Direct link to The Pipeline at a Glance" translate="no">​</a></h2>
<table><thead><tr><th>Step</th><th>Purpose</th><th>Writes to DB?</th></tr></thead><tbody><tr><td>1. Validate request</td><td>Reject malformed calls</td><td>No</td></tr><tr><td>2. Load reference data</td><td>GL accounts, warehouses</td><td>No (reads)</td></tr><tr><td>3. Ensure preconditions</td><td>Fiscal periods exist</td><td>Conditional</td></tr><tr><td>4. Build dedup index</td><td>Fetch existing entries</td><td>No (reads)</td></tr><tr><td>5. Parse and clean</td><td>CSV → clean rows</td><td>No</td></tr><tr><td>6. Preflight validate</td><td>All-or-nothing GL check</td><td>No</td></tr><tr><td>7. Group and transform</td><td>Rows → journal payloads</td><td>No</td></tr><tr><td>8. Write</td><td>Create journal entries</td><td><strong>Yes</strong></td></tr><tr><td>9. Report</td><td>Counters, skipped rows</td><td>No</td></tr></tbody></table>
<p>Eight steps of preparation. One step of writing. That ratio is not an accident — it's the architecture.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="hard-won-lessons-from-production-imports">Hard-Won Lessons From Production Imports<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#hard-won-lessons-from-production-imports" class="hash-link" aria-label="Direct link to Hard-Won Lessons From Production Imports" title="Direct link to Hard-Won Lessons From Production Imports" translate="no">​</a></h2>
<p>The pipeline above works. But getting it to that state involved months of production imports, failed runs, angry rollbacks, and late-night debugging sessions. These are the lessons that don't show up in the code — they show up in the decisions behind it.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="1-ai-doesnt-know-your-domain--and-it-will-guess-confidently">1. AI Doesn't Know Your Domain — And It Will Guess Confidently<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#1-ai-doesnt-know-your-domain--and-it-will-guess-confidently" class="hash-link" aria-label="Direct link to 1. AI Doesn't Know Your Domain — And It Will Guess Confidently" title="Direct link to 1. AI Doesn't Know Your Domain — And It Will Guess Confidently" translate="no">​</a></h3>
<p>Data imports are soaked in domain knowledge. What does "Class" mean in this CSV? It's a warehouse. What's a <code>Trans #</code>? It's a grouping key for compound journal entries. What does a zero-amount line mean — is it an error, or is it a tax-exempt placeholder?</p>
<p>AI will generate a perfectly structured import hook. It will parse, loop, and write. But it will consistently get the <em>meaning</em> wrong because it doesn't know your chart of accounts, your fiscal calendar, your warehouse naming conventions, or what "posted" means in your system versus the source system.</p>
<p>Every column in the CSV carries implicit business context that the AI has never seen. The <code>GL Code</code> column isn't just a string — it's a foreign key into your chart of accounts, and the mapping between the source system's codes and yours might not be 1:1. The <code>Date</code> column isn't just a date — it determines which fiscal period the entry lands in, which affects financial reporting.</p>
<p><strong>Expect to rewrite 50-70% of the AI's field mapping and business logic.</strong> Use the AI for the pipeline structure — the download, parse, loop, write skeleton. Do the domain mapping yourself.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="2-data-preparation-should-be-70-of-the-work">2. Data Preparation Should Be 70% of the Work<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#2-data-preparation-should-be-70-of-the-work" class="hash-link" aria-label="Direct link to 2. Data Preparation Should Be 70% of the Work" title="Direct link to 2. Data Preparation Should Be 70% of the Work" translate="no">​</a></h3>
<p>If you're spending most of your time on the database write, you're building the pipeline backward. The write is trivial once the data is clean. The hard part — the part that takes 70% of your development time — is everything before it:</p>
<ul>
<li class="">Understanding the source file format (delimiters, encoding, quoting)</li>
<li class="">Identifying and filtering junk rows (subtotals, headers, blank lines)</li>
<li class="">Mapping source columns to target fields</li>
<li class="">Converting types (string amounts with commas → numbers, date strings → Date objects)</li>
<li class="">Resolving foreign keys (GL code → <code>generalLedgerAccountId</code>, Class → <code>warehouseId</code>)</li>
<li class="">Grouping flat rows into compound documents</li>
</ul>
<p>If your commit history shows three days on data prep and an afternoon on the write, you're doing it right. If it's the inverse, your pipeline will break on the first real file.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="3-the-error-rate-must-be-zero">3. The Error Rate Must Be Zero<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#3-the-error-rate-must-be-zero" class="hash-link" aria-label="Direct link to 3. The Error Rate Must Be Zero" title="Direct link to 3. The Error Rate Must Be Zero" translate="no">​</a></h3>
<p>Not "low." Not "acceptable." <strong>Zero.</strong></p>
<p>Financial data imports don't have a margin for error. If you import 10,000 journal entries and 3 are wrong, you don't have 99.97% accuracy — you have a corrupted ledger. The accountant won't find those 3 bad entries. They'll find them in six months during an audit, and by then the cascade of dependent transactions makes the fix exponentially harder.</p>
<p>This is why the pipeline uses an all-or-nothing preflight gate. If a single GL code is invalid, the entire import aborts. It's aggressive, and users sometimes push back — "just skip the bad ones" — but partial imports create partial ledgers, and partial ledgers create real financial risk.</p>
<p>Design your pipeline so it either completes perfectly or doesn't start at all.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="4-prepare-the-workspace-for-fast-import-wipe-cycles">4. Prepare the Workspace for Fast Import-Wipe Cycles<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#4-prepare-the-workspace-for-fast-import-wipe-cycles" class="hash-link" aria-label="Direct link to 4. Prepare the Workspace for Fast Import-Wipe Cycles" title="Direct link to 4. Prepare the Workspace for Fast Import-Wipe Cycles" translate="no">​</a></h3>
<p>You will run the import multiple times before it's right. The first run will reveal data issues you didn't anticipate. The second run will expose edge cases in your transformation logic. The third run might actually work.</p>
<p>This means you need the ability to <strong>wipe and reimport quickly</strong>:</p>
<ul>
<li class="">Tag all imported documents with a recognizable prefix (<code>PIPE-</code> in this hook) so you can query and delete them in bulk</li>
<li class="">Use <code>skipSession: true</code> so each document auto-commits — if you need to kill a run midway, you know exactly what was written</li>
<li class="">Keep the source file immutable — download it once, process it from local storage, never modify the original</li>
<li class="">Have a cleanup script ready that deletes all <code>PIPE-*</code> journal entries so you can re-run from scratch</li>
</ul>
<p>The import-wipe-reimport cycle is your development loop. Make it fast. If a wipe takes 20 minutes, you'll only test three iterations in an hour. If it takes 30 seconds, you'll test twenty.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="5-the-audit-trail-checklist">5. The Audit Trail Checklist<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#5-the-audit-trail-checklist" class="hash-link" aria-label="Direct link to 5. The Audit Trail Checklist" title="Direct link to 5. The Audit Trail Checklist" translate="no">​</a></h3>
<p>Before writing the first line of code, answer these questions:</p>
<ul class="contains-task-list containsTaskList_QswE">
<li class="task-list-item"><input type="checkbox" disabled=""> <strong>Naming convention</strong>: How will imported documents be identified? (<code>PIPE-{transNum}</code>, <code>IMPORT-{batchId}</code>, etc.)</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <strong>Deduplication strategy</strong>: What makes two entries "the same"? Name? Source ID? Content hash?</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <strong>Audit fields</strong>: Does each imported document carry its source file reference, import timestamp, and batch ID?</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <strong>Transaction grouping</strong>: Are compound documents (header + lines) created atomically or individually?</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <strong>Batching strategy</strong>: One DB call per document, or batched inserts? Does the downstream hook support batch payloads?</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <strong>Session management</strong>: Shared transaction across all writes, or independent auto-commits? (For long imports, independent commits avoid MongoDB's 60-second transaction timeout)</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <strong>Event suppression</strong>: Should downstream events (notifications, recalculations) fire during import, or be suppressed with <code>skipEvent: true</code>?</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <strong>Rollback plan</strong>: If the import is wrong, how do you delete everything it created?</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <strong>Completion guarantee</strong>: If the process crashes at row 5,000 of 10,000, can you resume or must you wipe and restart?</li>
</ul>
<p>Answer every one of these <em>before</em> you start coding. They shape the pipeline's architecture in ways that are expensive to change later.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="6-measure-every-prep-query--youll-be-surprised">6. Measure Every Prep Query — You'll Be Surprised<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#6-measure-every-prep-query--youll-be-surprised" class="hash-link" aria-label="Direct link to 6. Measure Every Prep Query — You'll Be Surprised" title="Direct link to 6. Measure Every Prep Query — You'll Be Surprised" translate="no">​</a></h3>
<p>Every reference data query in the prep stage loads data into memory. You need to know how much. The instinct is to worry about "200,000 documents" — that sounds like a lot. But if you're only projecting the <code>name</code> field, 200,000 short strings might be 2MB. That's nothing.</p>
<p>On the other hand, fetching 10,000 full documents with nested arrays of line items could be 500MB.</p>
<p><strong>Measure, don't guess:</strong></p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> result </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> fc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">projection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.name'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">1</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">limit</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token number">2_000_000</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getMany</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// Log the actual size</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> sizeInBytes </span><span class="token operator">=</span><span class="token plain"> Buffer</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">byteLength</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token constant" style="color:rgb(189, 147, 249)">JSON</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">stringify</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">result</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">naoLogger</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">log</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string string" style="color:rgb(255, 121, 198)">Dedup index: </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">result</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation">data</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation">length</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string string" style="color:rgb(255, 121, 198)"> docs, </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string interpolation">sizeInBytes </span><span class="token template-string interpolation operator">/</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation number">1024</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation operator">/</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation number">1024</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation function" style="color:rgb(80, 250, 123)">toFixed</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string interpolation number">1</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string string" style="color:rgb(255, 121, 198)">MB</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>This changes your architecture decisions. If the dedup index is 2MB, load it all into a <code>Set</code> — fast and safe. If it's 200MB, you need a different strategy: streaming comparison, database-side dedup, or chunked lookups.</p>
<p>The projection operator is your best friend here. The difference between <code>{ 'data.name': 1 }</code> and fetching full documents can be 100x in memory footprint. Always project to the minimum fields you need, and always log the actual size.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="7-there-is-no-room-for-error--the-import-must-complete">7. There Is No Room for Error — The Import Must Complete<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#7-there-is-no-room-for-error--the-import-must-complete" class="hash-link" aria-label="Direct link to 7. There Is No Room for Error — The Import Must Complete" title="Direct link to 7. There Is No Room for Error — The Import Must Complete" translate="no">​</a></h3>
<p>A 50% imported ledger is worse than a 0% imported ledger. With zero imports, the customer knows nothing happened. With half the data imported, they don't know which half — and they can't trust any of it.</p>
<p>This has design implications:</p>
<ul>
<li class=""><strong>Preflight everything</strong>: Validate the entire file before writing the first document. If row 9,999 has an invalid GL code, you want to know before row 1 is committed.</li>
<li class=""><strong>Idempotent design</strong>: If the process crashes and restarts, it should skip already-imported entries (the dedup <code>Set</code>) and continue — not create duplicates.</li>
<li class=""><strong>Progress logging</strong>: Log every 500 transactions so you can see exactly where a failure occurred. The memory monitor isn't vanity — it's your early warning system for OOM kills.</li>
<li class=""><strong>Independent commits</strong>: <code>skipSession: true</code> means each journal entry is its own commit. If the process dies at entry 5,001, entries 1–5,000 are safe and the restart picks up at 5,001.</li>
</ul>
<p>Design for the crash. It will happen. The question is whether you recover in minutes or spend a weekend rebuilding the ledger.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="8-the-validation-report-is-your-customer-deliverable">8. The Validation Report Is Your Customer Deliverable<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#8-the-validation-report-is-your-customer-deliverable" class="hash-link" aria-label="Direct link to 8. The Validation Report Is Your Customer Deliverable" title="Direct link to 8. The Validation Report Is Your Customer Deliverable" translate="no">​</a></h3>
<p>Here's a pattern that saves weeks of back-and-forth: <strong>run the pipeline in validation-only mode first.</strong></p>
<p>The preflight validation step — the one that checks GL codes, resolves warehouses, and verifies fiscal periods — produces a report that is <em>exactly</em> what the customer needs to clean their data. Don't just throw an error. Format the validation results as a deliverable:</p>
<div class="language-text codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-text codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Import Validation Report</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">========================</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">File: general-ledger-export-2024.csv</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Total rows: 12,847</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Valid rows: 12,691</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Skipped (no Trans #): 142</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Invalid GL codes: 3</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  - "4510" → found on 8 rows (lines 234, 567, 891, ...)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  - "6200-A" → found on 2 rows (lines 1002, 1003)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  - "MISC" → found on 4 rows (lines 5501, 5502, 5503, 5504)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Action required: Add missing GL codes to chart of accounts, or update the CSV to use valid codes.</span><br></span></code></pre></div></div>
<p>Send this to the customer <em>before</em> running the actual import. Nine times out of ten, this report is all they need. They fix the three GL codes in their spreadsheet, re-export, and the next run succeeds cleanly.</p>
<p>The validation stage isn't just a safety gate — it's a communication tool. It speaks the customer's language (GL codes, line numbers) instead of yours (stack traces, error IDs).</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="9-always-benchmark-at-scale--what-if-this-file-has-10-million-entries">9. Always Benchmark at Scale — What If This File Has 10 Million Entries?<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#9-always-benchmark-at-scale--what-if-this-file-has-10-million-entries" class="hash-link" aria-label="Direct link to 9. Always Benchmark at Scale — What If This File Has 10 Million Entries?" title="Direct link to 9. Always Benchmark at Scale — What If This File Has 10 Million Entries?" translate="no">​</a></h3>
<p>Your test file has 500 rows and runs in 3 seconds. Your production file has 200,000 rows. Your largest customer's file has 10 million. Does your pipeline survive?</p>
<p>Things that break at scale:</p>
<ul>
<li class=""><strong>Memory</strong>: Loading 10 million rows into a JavaScript array. At ~1KB per parsed row object, that's 10GB. Your 8GB server is dead.</li>
<li class=""><strong>Dedup index</strong>: A <code>Set</code> of 2 million strings is fine (~150MB). A <code>Set</code> of 50 million strings is not.</li>
<li class=""><strong>Sequential writes</strong>: 10 million <code>executeRequestOrThrow</code> calls at 50ms each = 139 hours. You need batching or parallelism.</li>
<li class=""><strong>Logging</strong>: Logging every skipped row with its reason — if 2 million rows are skipped, your <code>skippedRows</code> array consumes more memory than the actual data.</li>
<li class=""><strong>Progress intervals</strong>: Logging every 500 transactions makes sense at 10,000. At 10 million, that's 20,000 log lines — still manageable, but worth verifying.</li>
</ul>
<p>Run the numbers before you run the import:</p>
<table><thead><tr><th>Metric</th><th>500 rows</th><th>200K rows</th><th>10M rows</th></tr></thead><tbody><tr><td>Raw file size</td><td>~50KB</td><td>~20MB</td><td>~1GB</td></tr><tr><td>Parse time</td><td>&lt; 1s</td><td>~5s</td><td>~60s</td></tr><tr><td>Memory (parsed)</td><td>~500KB</td><td>~200MB</td><td>~10GB ❌</td></tr><tr><td>Dedup query</td><td>instant</td><td>~2s</td><td>~30s</td></tr><tr><td>Sequential writes (50ms/ea)</td><td>25s</td><td>2.7hrs</td><td>139hrs ❌</td></tr></tbody></table>
<p>If the 10M column has red marks, your architecture needs to change — streaming parsers, chunked processing, parallel writes, or database-side dedup. Don't discover this in production.</p>
<p><strong>The file you're testing with is never the file you'll receive.</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-takeaway">The Takeaway<a href="https://logicbee.ai/blog/anatomy-of-a-csv-import-pipeline#the-takeaway" class="hash-link" aria-label="Direct link to The Takeaway" title="Direct link to The Takeaway" translate="no">​</a></h2>
<p>The instinct is to start with the database write and work backward. Production import pipelines work the other way: <strong>start with the source data and build forward through layers of validation, cleaning, and transformation until the write becomes a formality.</strong></p>
<p>Data preparation is 70% of the work. The error rate must be zero. The AI will get the structure right and the domain wrong. Your validation report is your customer's favorite deliverable. And the file you tested with is never the file you'll receive in production.</p>
<p>Your CSV is not your data. It's raw material. The pipeline is the refinery.</p>
<p>Trust the data only after you've earned that trust — one step at a time.</p>]]></content>
        <author>
            <name>Gabriel Paunescu</name>
            <uri>https://www.linkedin.com/in/gabrielpaunescu/</uri>
        </author>
        <category label="Hooks" term="Hooks"/>
        <category label="Best Practices" term="Best Practices"/>
        <category label="Case Study" term="Case Study"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Building an AI-Ready Codebase: Architecture Decisions That Pay Off]]></title>
        <id>https://logicbee.ai/blog/building-an-ai-ready-codebase</id>
        <link href="https://logicbee.ai/blog/building-an-ai-ready-codebase"/>
        <updated>2026-03-23T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Your architecture is your AI strategy. Every decorator, every naming convention, every file-per-function decision determines whether AI can contribute meaningfully to your codebase — or just generate noise.]]></summary>
        <content type="html"><![CDATA[<p>Your architecture is your AI strategy. Every decorator, every naming convention, every file-per-function decision determines whether AI can contribute meaningfully to your codebase — or just generate noise.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-premise">The Premise<a href="https://logicbee.ai/blog/building-an-ai-ready-codebase#the-premise" class="hash-link" aria-label="Direct link to The Premise" title="Direct link to The Premise" translate="no">​</a></h2>
<p>Most teams try to adopt AI coding assistants by writing better prompts. Logic Bee took a different approach: redesign the architecture so AI can't get it wrong. One hook per file. Mandatory decorators with machine-readable metadata. Self-registering modules. The result? AI agents that understand the codebase as well as a new team member — on day one.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-story">The Story<a href="https://logicbee.ai/blog/building-an-ai-ready-codebase#the-story" class="hash-link" aria-label="Direct link to The Story" title="Direct link to The Story" translate="no">​</a></h2>
<p>When Logic Bee was a monolithic Express app, AI code generation was unreliable. Functions were tangled across large files. Business logic mixed with routing. Naming was inconsistent. An AI asked to "add a billing function" would generate code that worked in isolation but broke in context.</p>
<p>The refactoring to a decorator-based, one-hook-per-file architecture wasn't about AI. It was about maintainability, testability, and developer experience. But the side effect was transformative: the same codebase that became easier for humans to navigate also became trivially parseable by AI.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-five-decisions">The Five Decisions<a href="https://logicbee.ai/blog/building-an-ai-ready-codebase#the-five-decisions" class="hash-link" aria-label="Direct link to The Five Decisions" title="Direct link to The Five Decisions" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="1-one-function-one-file">1. One Function, One File<a href="https://logicbee.ai/blog/building-an-ai-ready-codebase#1-one-function-one-file" class="hash-link" aria-label="Direct link to 1. One Function, One File" title="Direct link to 1. One Function, One File" translate="no">​</a></h3>
<p>Every hook lives in its own file at a predictable path:</p>
<div class="language-text codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-text codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token plain">hooks/{library-slug}/{method-slug}/{method-slug}.{library-slug}.hook.ts</span><br></span></code></pre></div></div>
<p><strong>Why it matters for AI</strong>: When the AI generates a new hook, it never needs to decide <em>where</em> to put the code. The path is deterministic from the library and method names. There's no risk of the AI inserting code into the wrong file or appending to an existing module.</p>
<p><strong>Why it matters for humans</strong>: Code reviews are self-contained. <code>git diff</code> shows one function per file. Merge conflicts between developers working on different hooks are eliminated.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="2-self-describing-decorators">2. Self-Describing Decorators<a href="https://logicbee.ai/blog/building-an-ai-ready-codebase#2-self-describing-decorators" class="hash-link" aria-label="Direct link to 2. Self-Describing Decorators" title="Direct link to 2. Self-Describing Decorators" translate="no">​</a></h3>
<p>Every hook wears its identity on its sleeve:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token decorator at operator">@</span><span class="token decorator function" style="color:rgb(80, 250, 123)">LogicHook</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  name</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'FinanceBillsCalculateLateFees'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  path</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'finance-bills/calculate-late-fees'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  library</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'finance-bills'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  method</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'calculate-late-fees'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p><strong>Why it matters for AI</strong>: The decorator is structured metadata — not a comment, not documentation, but code that the system reads at boot time. AI can scan decorators to understand what a hook does without reading the business logic.</p>
<p><strong>Why it matters for humans</strong>: New developers can <code>grep</code> for any hook by name, library, or method. Discovery is instant.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="3-auto-generated-barrels">3. Auto-Generated Barrels<a href="https://logicbee.ai/blog/building-an-ai-ready-codebase#3-auto-generated-barrels" class="hash-link" aria-label="Direct link to 3. Auto-Generated Barrels" title="Direct link to 3. Auto-Generated Barrels" translate="no">​</a></h3>
<p>When a new hook is created, barrel files (<code>index.ts</code>) are regenerated automatically. Developers never manually import hooks.</p>
<p><strong>Why it matters for AI</strong>: The AI can scaffold a hook, run the barrel generator, and know that the hook is registered — without understanding the module system. No manual import means no forgotten imports.</p>
<p><strong>Why it matters for humans</strong>: One less thing to remember. One less source of "it compiles but doesn't run" bugs.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="4-standardized-wrapper-pattern">4. Standardized Wrapper Pattern<a href="https://logicbee.ai/blog/building-an-ai-ready-codebase#4-standardized-wrapper-pattern" class="hash-link" aria-label="Direct link to 4. Standardized Wrapper Pattern" title="Direct link to 4. Standardized Wrapper Pattern" translate="no">​</a></h3>
<p>Every hook uses the Bob Wrapper: <code>execute()</code> → <code>async (bob) =&gt;</code> → <code>try/catch</code> → <code>returnEventResult</code>.</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">public</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">static</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">execute</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token operator">:</span><span class="token plain"> BobRequest</span><span class="token operator">&lt;</span><span class="token constant" style="color:rgb(189, 147, 249)">T</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">let</span><span class="token plain"> ok </span><span class="token operator">=</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> error</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">any</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">null</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">try</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token comment" style="color:rgb(98, 114, 164)">// business logic</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">err</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> error </span><span class="token operator">=</span><span class="token plain"> err</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"> ok </span><span class="token operator">=</span><span class="token plain"> </span><span class="token boolean">false</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">returnEventResult</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> ok</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> error</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p><strong>Why it matters for AI</strong>: The wrapper is a rigid template. AI fills in the business logic between <code>START_CODE_LOGIC</code> and <code>END_CODE_LOGIC</code>. The structural code around it is identical across hundreds of hooks — which means the AI never gets it wrong.</p>
<p><strong>Why it matters for humans</strong>: Every hook reads the same way. Error handling is guaranteed. The cognitive load of reading unfamiliar code drops to near zero.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="5-machine-readable-skills">5. Machine-Readable Skills<a href="https://logicbee.ai/blog/building-an-ai-ready-codebase#5-machine-readable-skills" class="hash-link" aria-label="Direct link to 5. Machine-Readable Skills" title="Direct link to 5. Machine-Readable Skills" translate="no">​</a></h3>
<p>Business rules, conventions, and patterns are encoded in <code>.agents/skills/</code> — not in wiki pages, Slack threads, or tribal knowledge.</p>
<p><strong>Why it matters for AI</strong>: Skills are loaded at prompt time. The AI doesn't need to infer conventions from code samples — it reads the rules directly.</p>
<p><strong>Why it matters for humans</strong>: Skills are versioned with the codebase. When conventions change, the skill files update, and the AI immediately adapts.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="measuring-the-impact">Measuring the Impact<a href="https://logicbee.ai/blog/building-an-ai-ready-codebase#measuring-the-impact" class="hash-link" aria-label="Direct link to Measuring the Impact" title="Direct link to Measuring the Impact" translate="no">​</a></h2>
<p>Before the architecture refactoring:</p>
<table><thead><tr><th>Metric</th><th>Monolith Era</th><th>Hook Architecture</th></tr></thead><tbody><tr><td>AI-generated code acceptance rate</td><td>~30%</td><td>~85%</td></tr><tr><td>Time to onboard new developer</td><td>2–3 weeks</td><td>2–3 days</td></tr><tr><td>Average code review time per function</td><td>25 min</td><td>8 min</td></tr><tr><td>Merge conflicts per sprint</td><td>8–12</td><td>0–2</td></tr><tr><td>Lines of code per business function</td><td>200–500</td><td>40–120</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="what-other-teams-can-learn">What Other Teams Can Learn<a href="https://logicbee.ai/blog/building-an-ai-ready-codebase#what-other-teams-can-learn" class="hash-link" aria-label="Direct link to What Other Teams Can Learn" title="Direct link to What Other Teams Can Learn" translate="no">​</a></h2>
<p>You don't need to use Logic Bee's exact architecture to make your codebase AI-ready. But these principles apply universally:</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="principle-1-predictable-file-locations">Principle 1: Predictable File Locations<a href="https://logicbee.ai/blog/building-an-ai-ready-codebase#principle-1-predictable-file-locations" class="hash-link" aria-label="Direct link to Principle 1: Predictable File Locations" title="Direct link to Principle 1: Predictable File Locations" translate="no">​</a></h3>
<p>If your AI has to guess where a file goes, it will guess wrong 30% of the time. A convention that maps names to paths eliminates this entirely.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="principle-2-structured-metadata-over-comments">Principle 2: Structured Metadata Over Comments<a href="https://logicbee.ai/blog/building-an-ai-ready-codebase#principle-2-structured-metadata-over-comments" class="hash-link" aria-label="Direct link to Principle 2: Structured Metadata Over Comments" title="Direct link to Principle 2: Structured Metadata Over Comments" translate="no">​</a></h3>
<p>Comments are for humans. Decorators (or annotations, or frontmatter) are for machines AND humans. Use structured metadata for anything the AI needs to discover.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="principle-3-one-unit-of-logic-per-file">Principle 3: One Unit of Logic Per File<a href="https://logicbee.ai/blog/building-an-ai-ready-codebase#principle-3-one-unit-of-logic-per-file" class="hash-link" aria-label="Direct link to Principle 3: One Unit of Logic Per File" title="Direct link to Principle 3: One Unit of Logic Per File" translate="no">​</a></h3>
<p>The smaller the blast radius of a change, the safer AI-generated code becomes. A wrong line in a 40-line file is easy to catch. A wrong line in a 400-line file is not.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="principle-4-rigid-structural-templates">Principle 4: Rigid Structural Templates<a href="https://logicbee.ai/blog/building-an-ai-ready-codebase#principle-4-rigid-structural-templates" class="hash-link" aria-label="Direct link to Principle 4: Rigid Structural Templates" title="Direct link to Principle 4: Rigid Structural Templates" translate="no">​</a></h3>
<p>The more of your code that's identical across instances, the less the AI can get wrong. Boilerplate isn't the enemy — inconsistent boilerplate is.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="principle-5-encode-conventions-dont-assume-them">Principle 5: Encode Conventions, Don't Assume Them<a href="https://logicbee.ai/blog/building-an-ai-ready-codebase#principle-5-encode-conventions-dont-assume-them" class="hash-link" aria-label="Direct link to Principle 5: Encode Conventions, Don't Assume Them" title="Direct link to Principle 5: Encode Conventions, Don't Assume Them" translate="no">​</a></h3>
<p>If a convention lives only in your head, the AI doesn't know it. If it lives in a skill file, the AI follows it automatically.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-takeaway">The Takeaway<a href="https://logicbee.ai/blog/building-an-ai-ready-codebase#the-takeaway" class="hash-link" aria-label="Direct link to The Takeaway" title="Direct link to The Takeaway" translate="no">​</a></h2>
<p>AI-ready architecture isn't a separate initiative. It's good architecture: modular, predictable, self-describing, and convention-driven. The same decisions that make your codebase maintainable for a team of ten developers make it navigable for AI agents.</p>
<p><strong>Design for the junior developer who just joined your team. The AI is that developer — permanently.</strong></p>]]></content>
        <author>
            <name>Gabriel Paunescu</name>
            <uri>https://www.linkedin.com/in/gabrielpaunescu/</uri>
        </author>
        <category label="AI" term="AI"/>
        <category label="Architecture" term="Architecture"/>
        <category label="Developer Experience" term="Developer Experience"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[When to Override the AI: Patterns the Machine Gets Wrong]]></title>
        <id>https://logicbee.ai/blog/when-to-override-the-ai</id>
        <link href="https://logicbee.ai/blog/when-to-override-the-ai"/>
        <updated>2026-03-16T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[AI coding assistants are remarkably good at following patterns. They're remarkably bad at knowing when a pattern doesn't apply. Here are three categories where you should always take the wheel.]]></summary>
        <content type="html"><![CDATA[<p>AI coding assistants are remarkably good at following patterns. They're remarkably bad at knowing when a pattern doesn't apply. Here are three categories where you should always take the wheel.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-premise">The Premise<a href="https://logicbee.ai/blog/when-to-override-the-ai#the-premise" class="hash-link" aria-label="Direct link to The Premise" title="Direct link to The Premise" translate="no">​</a></h2>
<p>AI generates code by pattern matching against its training data and your project's skill files. For 80% of Logic Bee hooks, this produces correct, convention-following code. But certain categories of logic require reasoning that current AI models consistently get wrong — not because they're broken, but because the problems require domain knowledge that never appears in code patterns alone.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-story">The Story<a href="https://logicbee.ai/blog/when-to-override-the-ai#the-story" class="hash-link" aria-label="Direct link to The Story" title="Direct link to The Story" translate="no">​</a></h2>
<p>A senior developer tracked every AI-generated hook over three months and categorized the corrections. Three patterns emerged: financial calculations, multi-tenant edge cases, and transaction session management. Each required the same type of intervention — the developer understanding <em>why</em>, not just <em>how</em>.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="pattern-1-financial-calculations">Pattern 1: Financial Calculations<a href="https://logicbee.ai/blog/when-to-override-the-ai#pattern-1-financial-calculations" class="hash-link" aria-label="Direct link to Pattern 1: Financial Calculations" title="Direct link to Pattern 1: Financial Calculations" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="what-the-ai-does">What the AI Does<a href="https://logicbee.ai/blog/when-to-override-the-ai#what-the-ai-does" class="hash-link" aria-label="Direct link to What the AI Does" title="Direct link to What the AI Does" translate="no">​</a></h3>
<p>AI uses JavaScript arithmetic because it looks correct:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ AI-generated: floating point disaster</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> taxAmount </span><span class="token operator">=</span><span class="token plain"> subtotal </span><span class="token operator">*</span><span class="token plain"> taxRate</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> total </span><span class="token operator">=</span><span class="token plain"> subtotal </span><span class="token operator">+</span><span class="token plain"> taxAmount </span><span class="token operator">+</span><span class="token plain"> shippingCost</span><br></span></code></pre></div></div>
<p>The problem isn't obvious until you see: <code>199.99 * 0.08 = 15.999200000000001</code>.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="what-the-developer-does">What the Developer Does<a href="https://logicbee.ai/blog/when-to-override-the-ai#what-the-developer-does" class="hash-link" aria-label="Direct link to What the Developer Does" title="Direct link to What the Developer Does" translate="no">​</a></h3>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ mathChain for precision</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> taxAmount </span><span class="token operator">=</span><span class="token plain"> naoUtils</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">mathChain</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">subtotal</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">multiply</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">taxRate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">done</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> total </span><span class="token operator">=</span><span class="token plain"> naoUtils</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">mathChain</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">subtotal</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">add</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">taxAmount</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">add</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">shippingCost</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">done</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="why-ai-gets-this-wrong">Why AI Gets This Wrong<a href="https://logicbee.ai/blog/when-to-override-the-ai#why-ai-gets-this-wrong" class="hash-link" aria-label="Direct link to Why AI Gets This Wrong" title="Direct link to Why AI Gets This Wrong" translate="no">​</a></h3>
<p>AI sees <code>*</code> and <code>+</code> operators in countless training examples. <code>mathChain()</code> is Logic Bee-specific. Even with skill files telling the AI to use <code>mathChain</code>, it sometimes falls back to raw operators for "simple" calculations — but there's no such thing as a simple financial calculation.</p>
<p><strong>Rule</strong>: Any arithmetic involving currency → <code>naoUtils.mathChain()</code>. No exceptions.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="pattern-2-multi-tenant-edge-cases">Pattern 2: Multi-Tenant Edge Cases<a href="https://logicbee.ai/blog/when-to-override-the-ai#pattern-2-multi-tenant-edge-cases" class="hash-link" aria-label="Direct link to Pattern 2: Multi-Tenant Edge Cases" title="Direct link to Pattern 2: Multi-Tenant Edge Cases" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="what-the-ai-does-1">What the AI Does<a href="https://logicbee.ai/blog/when-to-override-the-ai#what-the-ai-does-1" class="hash-link" aria-label="Direct link to What the AI Does" title="Direct link to What the AI Does" translate="no">​</a></h3>
<p>AI handles the happy path correctly — querying documents with <code>.user(bob.flowUser)</code>. But it fails on edge cases where tenant boundaries interact in unexpected ways:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ AI-generated: cross-tenant data leak in batch processing</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> allVendors </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> vendorCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">vendorNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.type'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'preferred'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getMany</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'PurchasingInterface.Vendor'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// AI then uses vendor IDs to query another collection</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// But what if a vendor was shared across tenants?</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> vendorBills </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> billCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">billNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.vendorId'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> $</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token operator">:</span><span class="token plain"> allVendors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">map</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">v </span><span class="token operator">=&gt;</span><span class="token plain"> v</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getMany</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'FinanceInterface.Bill'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="what-the-developer-does-1">What the Developer Does<a href="https://logicbee.ai/blog/when-to-override-the-ai#what-the-developer-does-1" class="hash-link" aria-label="Direct link to What the Developer Does" title="Direct link to What the Developer Does" translate="no">​</a></h3>
<p>The developer adds business-unit scoping:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Add explicit business unit filtering</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> vendorBills </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> billCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">billNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token string-property property">'data.vendorId'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> $</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token operator">:</span><span class="token plain"> allVendors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">map</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">v </span><span class="token operator">=&gt;</span><span class="token plain"> v</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token string-property property">'data.businessUnitId'</span><span class="token operator">:</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getBusinessUnitId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)">// explicit scope</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getMany</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'FinanceInterface.Bill'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="why-ai-gets-this-wrong-1">Why AI Gets This Wrong<a href="https://logicbee.ai/blog/when-to-override-the-ai#why-ai-gets-this-wrong-1" class="hash-link" aria-label="Direct link to Why AI Gets This Wrong" title="Direct link to Why AI Gets This Wrong" translate="no">​</a></h3>
<p>Multi-tenancy is an architectural concern, not a code pattern. The AI knows to add <code>.user(bob.flowUser)</code> because the skill file says so. But it doesn't understand <em>why</em> — that in a shared-vendor scenario, FlowQuery's default scoping may not be sufficient and additional business-unit filtering is needed.</p>
<p><strong>Rule</strong>: Any cross-collection join → verify tenant and business-unit boundaries manually.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="pattern-3-complex-transaction-sessions">Pattern 3: Complex Transaction Sessions<a href="https://logicbee.ai/blog/when-to-override-the-ai#pattern-3-complex-transaction-sessions" class="hash-link" aria-label="Direct link to Pattern 3: Complex Transaction Sessions" title="Direct link to Pattern 3: Complex Transaction Sessions" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="what-the-ai-does-2">What the AI Does<a href="https://logicbee.ai/blog/when-to-override-the-ai#what-the-ai-does-2" class="hash-link" aria-label="Direct link to What the AI Does" title="Direct link to What the AI Does" translate="no">​</a></h3>
<p>AI includes <code>bob.dbSession()</code> on write operations because the skill file says so. But it doesn't understand transaction <em>design</em>:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ AI-generated: partial transaction safety</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">try</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)">// Operation 1: create credit memo</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> creditMemoCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">creditMemoNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">insertOne</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">creditMemoDoc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">dbSession</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)">// Operation 2: update invoice status</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> invoiceCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">invoiceNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">docId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">invoiceId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">updateOne</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.status'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'credited'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">dbSession</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)">// Operation 3: adjust vendor balance (NO SESSION!)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> vendorCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">vendorNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">docId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">vendorId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">updateOne</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.balance'</span><span class="token operator">:</span><span class="token plain"> newBalance </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)">// ← missing bob.dbSession()</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="what-the-developer-does-2">What the Developer Does<a href="https://logicbee.ai/blog/when-to-override-the-ai#what-the-developer-does-2" class="hash-link" aria-label="Direct link to What the Developer Does" title="Direct link to What the Developer Does" translate="no">​</a></h3>
<p>The developer ensures <em>all</em> writes within a logical transaction share the session — and adds rollback awareness:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ All writes in the same session, with failure awareness</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> session </span><span class="token operator">=</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">dbSession</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> creditMemoCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token operator">...</span><span class="token function" style="color:rgb(80, 250, 123)">insertOne</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">creditMemoDoc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> session</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> invoiceCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token operator">...</span><span class="token function" style="color:rgb(80, 250, 123)">updateOne</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.status'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'credited'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> session</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> vendorCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token operator">...</span><span class="token function" style="color:rgb(80, 250, 123)">updateOne</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.balance'</span><span class="token operator">:</span><span class="token plain"> newBalance </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> session</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="why-ai-gets-this-wrong-2">Why AI Gets This Wrong<a href="https://logicbee.ai/blog/when-to-override-the-ai#why-ai-gets-this-wrong-2" class="hash-link" aria-label="Direct link to Why AI Gets This Wrong" title="Direct link to Why AI Gets This Wrong" translate="no">​</a></h3>
<p>The AI treats <code>bob.dbSession()</code> as a "should include" parameter, not a "must include for atomicity" requirement. It doesn't reason about what happens when operation 3 fails — operation 1 and 2 commit, but the vendor balance is stale.</p>
<p><strong>Rule</strong>: If you're touching more than one collection → every write operation must use <code>bob.dbSession()</code>. Audit this manually every time.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-decision-framework">The Decision Framework<a href="https://logicbee.ai/blog/when-to-override-the-ai#the-decision-framework" class="hash-link" aria-label="Direct link to The Decision Framework" title="Direct link to The Decision Framework" translate="no">​</a></h2>
<table><thead><tr><th>Situation</th><th>AI or Developer?</th></tr></thead><tbody><tr><td>Hook scaffolding and boilerplate</td><td>✅ AI</td></tr><tr><td>Single-collection CRUD operations</td><td>✅ AI</td></tr><tr><td>Standard FlowQuery chains</td><td>✅ AI (with review)</td></tr><tr><td>Financial arithmetic</td><td>❌ Developer</td></tr><tr><td>Cross-collection joins with tenant concerns</td><td>❌ Developer</td></tr><tr><td>Multi-document transaction design</td><td>❌ Developer</td></tr><tr><td>Error message wording</td><td>❌ Developer</td></tr><tr><td>Schema-specific validation rules</td><td>❌ Developer</td></tr><tr><td>Performance optimization (batching, indexing)</td><td>❌ Developer</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-takeaway">The Takeaway<a href="https://logicbee.ai/blog/when-to-override-the-ai#the-takeaway" class="hash-link" aria-label="Direct link to The Takeaway" title="Direct link to The Takeaway" translate="no">​</a></h2>
<p>The AI is your fastest pair programmer — for patterns it has seen before. For patterns that require <em>understanding</em>, not just matching, the developer must intervene.</p>
<p>Three questions to ask about every AI-generated hook:</p>
<ol>
<li class=""><strong>Is there money involved?</strong> → Verify all math uses <code>mathChain()</code></li>
<li class=""><strong>Are there cross-collection queries?</strong> → Verify tenant and business-unit scoping</li>
<li class=""><strong>Are there multiple writes?</strong> → Verify every one uses <code>bob.dbSession()</code></li>
</ol>
<p><strong>Know when to let the AI drive. Know when to take the wheel.</strong></p>]]></content>
        <author>
            <name>Gabriel Paunescu</name>
            <uri>https://www.linkedin.com/in/gabrielpaunescu/</uri>
        </author>
        <category label="AI" term="AI"/>
        <category label="Best Practices" term="Best Practices"/>
        <category label="Hooks" term="Hooks"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[AI-Assisted Data Import Pipelines: A Real-World Case Study]]></title>
        <id>https://logicbee.ai/blog/ai-assisted-data-import-pipelines</id>
        <link href="https://logicbee.ai/blog/ai-assisted-data-import-pipelines"/>
        <updated>2026-03-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Importing 10,000 general ledger accounts shouldn't require 10,000 lines of code. Here's how we built a complete data import pipeline with AI — and the six places where the developer had to step in.]]></summary>
        <content type="html"><![CDATA[<p>Importing 10,000 general ledger accounts shouldn't require 10,000 lines of code. Here's how we built a complete data import pipeline with AI — and the six places where the developer had to step in.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-premise">The Premise<a href="https://logicbee.ai/blog/ai-assisted-data-import-pipelines#the-premise" class="hash-link" aria-label="Direct link to The Premise" title="Direct link to The Premise" translate="no">​</a></h2>
<p>Data import is one of ERP's most common, tedious, and error-prone workflows. Parse a file, validate rows, map fields, handle duplicates, write to the database, and report errors — all with transaction safety and tenant isolation. It's the perfect candidate for AI generation because the structure is repetitive, but the business logic is unique per import type.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-story">The Story<a href="https://logicbee.ai/blog/ai-assisted-data-import-pipelines#the-story" class="hash-link" aria-label="Direct link to The Story" title="Direct link to The Story" translate="no">​</a></h2>
<p>The team needed to import general ledger (GL) accounts from a client's CSV export. The import pipeline needed to:</p>
<ol>
<li class="">Parse a CSV file with 10,000+ rows</li>
<li class="">Validate each row against a GL account schema</li>
<li class="">Skip duplicate account numbers</li>
<li class="">Create new accounts in the <code>finance/general-ledger</code> collection</li>
<li class="">Report successes, skips, and failures in a structured response</li>
</ol>
<p>A developer prompted the AI to build the entire pipeline. The AI generated 90% of the working code. But six critical interventions turned it from "mostly working" into "production-ready."</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-pipeline-architecture">The Pipeline Architecture<a href="https://logicbee.ai/blog/ai-assisted-data-import-pipelines#the-pipeline-architecture" class="hash-link" aria-label="Direct link to The Pipeline Architecture" title="Direct link to The Pipeline Architecture" translate="no">​</a></h2>
<div class="language-text codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-text codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token plain">CSV Upload → Parse → Validate → Deduplicate → Insert → Report</span><br></span></code></pre></div></div>
<p>Each step maps to a section of the hook:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token decorator at operator">@</span><span class="token decorator function" style="color:rgb(80, 250, 123)">LogicHook</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  name</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'ImportPipeGeneralLedgerAccounts'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  path</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'import-pipe/general-ledger-accounts'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  library</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'import-pipe'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  method</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'general-ledger-accounts'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  legacy</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'app/app.importPipeHooks.generalLedgerAccounts'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="where-the-developer-stepped-in">Where the Developer Stepped In<a href="https://logicbee.ai/blog/ai-assisted-data-import-pipelines#where-the-developer-stepped-in" class="hash-link" aria-label="Direct link to Where the Developer Stepped In" title="Direct link to Where the Developer Stepped In" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="intervention-1-csv-parsing-edge-cases">Intervention 1: CSV Parsing Edge Cases<a href="https://logicbee.ai/blog/ai-assisted-data-import-pipelines#intervention-1-csv-parsing-edge-cases" class="hash-link" aria-label="Direct link to Intervention 1: CSV Parsing Edge Cases" title="Direct link to Intervention 1: CSV Parsing Edge Cases" translate="no">​</a></h3>
<p>The AI used a basic split-by-comma approach. Real CSV files have quoted fields, embedded commas, and encoding issues.</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ AI-generated: naive parsing</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> rows </span><span class="token operator">=</span><span class="token plain"> csvContent</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">split</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'\n'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">map</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">line </span><span class="token operator">=&gt;</span><span class="token plain"> line</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">split</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">','</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Developer fix: use the project's CSV utility</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> rows </span><span class="token operator">=</span><span class="token plain"> naoUtils</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">csv</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">parse</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">csvContent</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  header</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  skipEmptyLines</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  dynamicTyping</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">false</span><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)">// keep everything as strings for validation</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="intervention-2-batch-size-for-database-operations">Intervention 2: Batch Size for Database Operations<a href="https://logicbee.ai/blog/ai-assisted-data-import-pipelines#intervention-2-batch-size-for-database-operations" class="hash-link" aria-label="Direct link to Intervention 2: Batch Size for Database Operations" title="Direct link to Intervention 2: Batch Size for Database Operations" translate="no">​</a></h3>
<p>The AI generated a loop that inserted one document at a time — 10,000 individual insert operations.</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ AI approach: one-by-one inserts</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> account </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">of</span><span class="token plain"> validAccounts</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> fc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">glNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">insertOne</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">account</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">dbSession</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Developer fix: batch inserts</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> </span><span class="token constant" style="color:rgb(189, 147, 249)">BATCH_SIZE</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token number">500</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">let</span><span class="token plain"> i </span><span class="token operator">=</span><span class="token plain"> </span><span class="token number">0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"> i </span><span class="token operator">&lt;</span><span class="token plain"> validAccounts</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">length</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"> i </span><span class="token operator">+=</span><span class="token plain"> </span><span class="token constant" style="color:rgb(189, 147, 249)">BATCH_SIZE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> batch </span><span class="token operator">=</span><span class="token plain"> validAccounts</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">slice</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">i</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> i </span><span class="token operator">+</span><span class="token plain"> </span><span class="token constant" style="color:rgb(189, 147, 249)">BATCH_SIZE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> fc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">glNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">insertMany</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">dbSession</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="intervention-3-duplicate-detection-strategy">Intervention 3: Duplicate Detection Strategy<a href="https://logicbee.ai/blog/ai-assisted-data-import-pipelines#intervention-3-duplicate-detection-strategy" class="hash-link" aria-label="Direct link to Intervention 3: Duplicate Detection Strategy" title="Direct link to Intervention 3: Duplicate Detection Strategy" translate="no">​</a></h3>
<p>The AI checked for duplicates by querying each account number individually. The developer replaced it with a single bulk query:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Fetch all existing account numbers in one query</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> existing </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> fc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">glNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.accountNumber'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> $</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token operator">:</span><span class="token plain"> incomingAccountNumbers </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">project</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.accountNumber'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">1</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getMany</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'FinanceInterface.GeneralLedgerAccount'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> existingSet </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">new</span><span class="token plain"> </span><span class="token class-name">Set</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">existing</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">map</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">e </span><span class="token operator">=&gt;</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">accountNumber</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> newAccounts </span><span class="token operator">=</span><span class="token plain"> validAccounts</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">filter</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">a </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token operator">!</span><span class="token plain">existingSet</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">has</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">a</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">accountNumber</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="intervention-4-validation-schema">Intervention 4: Validation Schema<a href="https://logicbee.ai/blog/ai-assisted-data-import-pipelines#intervention-4-validation-schema" class="hash-link" aria-label="Direct link to Intervention 4: Validation Schema" title="Direct link to Intervention 4: Validation Schema" translate="no">​</a></h3>
<p>The AI generated a validation schema that was too permissive — accepting any string for account type. The developer added enum constraints:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Strict validation</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> accountSchema </span><span class="token operator">=</span><span class="token plain"> SuperJoi</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">object</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  accountNumber</span><span class="token operator">:</span><span class="token plain"> SuperJoi</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">string</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">pattern</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token regex regex-delimiter">/</span><span class="token regex regex-source language-regex anchor function" style="color:rgb(80, 250, 123)">^</span><span class="token regex regex-source language-regex char-set class-name">\d</span><span class="token regex regex-source language-regex quantifier number">{4,6}</span><span class="token regex regex-source language-regex anchor function" style="color:rgb(80, 250, 123)">$</span><span class="token regex regex-delimiter">/</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">required</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  accountName</span><span class="token operator">:</span><span class="token plain"> SuperJoi</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">string</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">max</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token number">200</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">required</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  accountType</span><span class="token operator">:</span><span class="token plain"> SuperJoi</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">string</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">valid</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token string" style="color:rgb(255, 121, 198)">'asset'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'liability'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'equity'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'revenue'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'expense'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">required</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  parentAccount</span><span class="token operator">:</span><span class="token plain"> SuperJoi</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">string</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">allow</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">null</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">''</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  isActive</span><span class="token operator">:</span><span class="token plain"> SuperJoi</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">boolean</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">default</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="intervention-5-error-reporting-granularity">Intervention 5: Error Reporting Granularity<a href="https://logicbee.ai/blog/ai-assisted-data-import-pipelines#intervention-5-error-reporting-granularity" class="hash-link" aria-label="Direct link to Intervention 5: Error Reporting Granularity" title="Direct link to Intervention 5: Error Reporting Granularity" translate="no">​</a></h3>
<p>The AI returned a generic "X succeeded, Y failed" message. The developer added row-level error reporting:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Row-level reporting</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> report </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  total</span><span class="token operator">:</span><span class="token plain"> rows</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">length</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  created</span><span class="token operator">:</span><span class="token plain"> newAccounts</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">length</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  skipped</span><span class="token operator">:</span><span class="token plain"> existingSet</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">size</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  errors</span><span class="token operator">:</span><span class="token plain"> validationErrors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">map</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">e </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    row</span><span class="token operator">:</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">rowNumber</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    accountNumber</span><span class="token operator">:</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token operator">?.</span><span class="token plain">accountNumber </span><span class="token operator">||</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'unknown'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    reason</span><span class="token operator">:</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">error</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">message</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="intervention-6-memory-management">Intervention 6: Memory Management<a href="https://logicbee.ai/blog/ai-assisted-data-import-pipelines#intervention-6-memory-management" class="hash-link" aria-label="Direct link to Intervention 6: Memory Management" title="Direct link to Intervention 6: Memory Management" translate="no">​</a></h3>
<p>With 10,000+ rows, the AI was holding all raw data, parsed data, and results in memory simultaneously. The developer added streaming-style processing:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Process in chunks, release references</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">let</span><span class="token plain"> processedCount </span><span class="token operator">=</span><span class="token plain"> </span><span class="token number">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">let</span><span class="token plain"> i </span><span class="token operator">=</span><span class="token plain"> </span><span class="token number">0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"> i </span><span class="token operator">&lt;</span><span class="token plain"> rows</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">length</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"> i </span><span class="token operator">+=</span><span class="token plain"> </span><span class="token constant" style="color:rgb(189, 147, 249)">BATCH_SIZE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> chunk </span><span class="token operator">=</span><span class="token plain"> rows</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">slice</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">i</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> i </span><span class="token operator">+</span><span class="token plain"> </span><span class="token constant" style="color:rgb(189, 147, 249)">BATCH_SIZE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> valid</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> errors </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">validateChunk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">chunk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> i</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  validationErrors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">push</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token operator">...</span><span class="token plain">errors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> newInChunk </span><span class="token operator">=</span><span class="token plain"> valid</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">filter</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">a </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token operator">!</span><span class="token plain">existingSet</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">has</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">a</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">accountNumber</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">newInChunk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">length </span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token number">0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">insertBatch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">fc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> newInChunk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    processedCount </span><span class="token operator">+=</span><span class="token plain"> newInChunk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">length</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)">// chunk goes out of scope, eligible for GC</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-final-result">The Final Result<a href="https://logicbee.ai/blog/ai-assisted-data-import-pipelines#the-final-result" class="hash-link" aria-label="Direct link to The Final Result" title="Direct link to The Final Result" translate="no">​</a></h2>
<table><thead><tr><th>Metric</th><th>AI-Generated</th><th>After Intervention</th></tr></thead><tbody><tr><td>Parse strategy</td><td>Split by comma</td><td><code>naoUtils.csv.parse()</code></td></tr><tr><td>Insert strategy</td><td>One-by-one (10,000 ops)</td><td>Batch of 500 (20 ops)</td></tr><tr><td>Duplicate check</td><td>Individual queries</td><td>Single bulk query</td></tr><tr><td>Validation</td><td>Permissive schema</td><td>Strict enums + patterns</td></tr><tr><td>Error reporting</td><td>Summary only</td><td>Row-level details</td></tr><tr><td>Memory usage</td><td>All-in-memory</td><td>Chunked processing</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-takeaway">The Takeaway<a href="https://logicbee.ai/blog/ai-assisted-data-import-pipelines#the-takeaway" class="hash-link" aria-label="Direct link to The Takeaway" title="Direct link to The Takeaway" translate="no">​</a></h2>
<p>AI generates excellent pipeline structure. The developer adds:</p>
<ol>
<li class=""><strong>Domain-specific parsing</strong> — real-world files aren't clean</li>
<li class=""><strong>Performance optimization</strong> — batch operations, bulk queries</li>
<li class=""><strong>Strict validation</strong> — business rules the AI doesn't know</li>
<li class=""><strong>Detailed reporting</strong> — users need row-level feedback</li>
<li class=""><strong>Resource management</strong> — memory and connection awareness</li>
</ol>
<p><strong>The AI builds the highway. You paint the lane markings.</strong></p>]]></content>
        <author>
            <name>Gabriel Paunescu</name>
            <uri>https://www.linkedin.com/in/gabrielpaunescu/</uri>
        </author>
        <category label="AI" term="AI"/>
        <category label="Case Study" term="Case Study"/>
        <category label="Hooks" term="Hooks"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Skills as a Contract Between AI and Developer]]></title>
        <id>https://logicbee.ai/blog/skills-as-a-contract</id>
        <link href="https://logicbee.ai/blog/skills-as-a-contract"/>
        <updated>2026-03-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Skills aren't documentation. They're executable contracts — structured knowledge files that tell the AI exactly how your codebase works. Invest two hours writing a skill file, save twenty hours of correcting AI output.]]></summary>
        <content type="html"><![CDATA[<p>Skills aren't documentation. They're executable contracts — structured knowledge files that tell the AI exactly how your codebase works. Invest two hours writing a skill file, save twenty hours of correcting AI output.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-premise">The Premise<a href="https://logicbee.ai/blog/skills-as-a-contract#the-premise" class="hash-link" aria-label="Direct link to The Premise" title="Direct link to The Premise" translate="no">​</a></h2>
<p>Most teams treat AI assistants like search engines: ask a question, get an answer, fix what's wrong. But Logic Bee takes a different approach. Instead of hoping the AI figures out how the code works, we <em>tell it</em> — through <code>.agents/skills/</code> files that serve as machine-readable contracts between the developer and the AI.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-story">The Story<a href="https://logicbee.ai/blog/skills-as-a-contract#the-story" class="hash-link" aria-label="Direct link to The Story" title="Direct link to The Story" translate="no">​</a></h2>
<p>Before skill files, every AI prompt required extensive context: "By the way, we use <code>naoUtils.mathChain()</code> for math, and <code>naoDateTime()</code> for dates, and errors should use <code>naoFormatErrorById()</code>, and the first thing in the try block should be <code>eventOptions</code>..."</p>
<p>One developer spent 15 minutes adding context to every prompt. Then they extracted it into a skill file — once. Now every AI interaction in the codebase automatically follows those conventions without any prompt engineering.</p>
<p>The return on investment was immediate: fewer review cycles, fewer rejected PRs, and dramatically fewer convention violations in AI-generated code.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="what-a-skill-file-looks-like">What a Skill File Looks Like<a href="https://logicbee.ai/blog/skills-as-a-contract#what-a-skill-file-looks-like" class="hash-link" aria-label="Direct link to What a Skill File Looks Like" title="Direct link to What a Skill File Looks Like" translate="no">​</a></h2>
<div class="language-markdown codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-markdown codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token title important punctuation" style="color:rgb(248, 248, 242)">#</span><span class="token title important"> SKILL.md — hook-code-style</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token hr punctuation" style="color:rgb(248, 248, 242)">---</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">name: hook-code-style</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token title important">description: Coding rules, naming patterns, and structural conventions for Logic Bee hooks</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token title important"></span><span class="token title important punctuation" style="color:rgb(248, 248, 242)">---</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token title important punctuation" style="color:rgb(248, 248, 242)">##</span><span class="token title important"> Hard Rules (violations = merge blockers)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token list punctuation" style="color:rgb(248, 248, 242)">1.</span><span class="token plain"> </span><span class="token code-snippet code keyword" style="color:rgb(189, 147, 249);font-style:italic">`ok`</span><span class="token plain"> and </span><span class="token code-snippet code keyword" style="color:rgb(189, 147, 249);font-style:italic">`data`</span><span class="token plain"> must be assigned before </span><span class="token code-snippet code keyword" style="color:rgb(189, 147, 249);font-style:italic">`returnEventResult`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token list punctuation" style="color:rgb(248, 248, 242)">2.</span><span class="token plain"> Every </span><span class="token code-snippet code keyword" style="color:rgb(189, 147, 249);font-style:italic">`.flowQuery()`</span><span class="token plain"> must include </span><span class="token code-snippet code keyword" style="color:rgb(189, 147, 249);font-style:italic">`.user(bob.flowUser)`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token list punctuation" style="color:rgb(248, 248, 242)">3.</span><span class="token plain"> Every write operation must pass </span><span class="token code-snippet code keyword" style="color:rgb(189, 147, 249);font-style:italic">`bob.dbSession()`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">...</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token title important punctuation" style="color:rgb(248, 248, 242)">##</span><span class="token title important"> Soft Conventions (violations = code review comments)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token list punctuation" style="color:rgb(248, 248, 242)">1.</span><span class="token plain"> </span><span class="token code-snippet code keyword" style="color:rgb(189, 147, 249);font-style:italic">`eventOptions`</span><span class="token plain"> is the first declaration in the try block</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token list punctuation" style="color:rgb(248, 248, 242)">2.</span><span class="token plain"> Use arrow comments: </span><span class="token code-snippet code keyword" style="color:rgb(189, 147, 249);font-style:italic">`// --&gt;Get:`</span><span class="token plain">, </span><span class="token code-snippet code keyword" style="color:rgb(189, 147, 249);font-style:italic">`// --&gt;Set:`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token list punctuation" style="color:rgb(248, 248, 242)">3.</span><span class="token plain"> Use </span><span class="token code-snippet code keyword" style="color:rgb(189, 147, 249);font-style:italic">`naoUtils.mathChain()`</span><span class="token plain"> for all arithmetic</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">...</span><br></span></code></pre></div></div>
<p>The skill is just a markdown file. But it transforms AI behavior from "best guess" to "informed generation."</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="what-makes-a-good-skill">What Makes a Good Skill<a href="https://logicbee.ai/blog/skills-as-a-contract#what-makes-a-good-skill" class="hash-link" aria-label="Direct link to What Makes a Good Skill" title="Direct link to What Makes a Good Skill" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="1-be-prescriptive-not-descriptive">1. Be Prescriptive, Not Descriptive<a href="https://logicbee.ai/blog/skills-as-a-contract#1-be-prescriptive-not-descriptive" class="hash-link" aria-label="Direct link to 1. Be Prescriptive, Not Descriptive" title="Direct link to 1. Be Prescriptive, Not Descriptive" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-text codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token plain">❌ "We usually try to use mathChain for calculations"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✅ "ALWAYS use naoUtils.mathChain() for arithmetic. Raw +, -, *, / operators </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    on financial values are a hard rule violation."</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="2-include-examples">2. Include Examples<a href="https://logicbee.ai/blog/skills-as-a-contract#2-include-examples" class="hash-link" aria-label="Direct link to 2. Include Examples" title="Direct link to 2. Include Examples" translate="no">​</a></h3>
<p>Every rule should have a ✅ correct and ❌ incorrect code example. AI learns better from contrast.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="3-separate-hard-and-soft-rules">3. Separate Hard and Soft Rules<a href="https://logicbee.ai/blog/skills-as-a-contract#3-separate-hard-and-soft-rules" class="hash-link" aria-label="Direct link to 3. Separate Hard and Soft Rules" title="Direct link to 3. Separate Hard and Soft Rules" translate="no">​</a></h3>
<p>The distinction matters. Hard rules should block generation. Soft rules should trigger warnings.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="4-keep-it-focused">4. Keep It Focused<a href="https://logicbee.ai/blog/skills-as-a-contract#4-keep-it-focused" class="hash-link" aria-label="Direct link to 4. Keep It Focused" title="Direct link to 4. Keep It Focused" translate="no">​</a></h3>
<p>One skill per concern. <code>hook-code-style</code> covers coding patterns. <code>flow-query</code> covers database access. Don't mix them.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="5-document-the-edge-cases">5. Document the Edge Cases<a href="https://logicbee.ai/blog/skills-as-a-contract#5-document-the-edge-cases" class="hash-link" aria-label="Direct link to 5. Document the Edge Cases" title="Direct link to 5. Document the Edge Cases" translate="no">​</a></h3>
<p>The 80% cases are obvious. Skills earn their ROI on the 20% that trips up AI:</p>
<div class="language-text codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-text codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token plain">"When a hook calls bob.runAction(), ALWAYS check the .ok property of the </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">result before continuing. AI tends to assume sub-requests always succeed."</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-skill-ecosystem">The Skill Ecosystem<a href="https://logicbee.ai/blog/skills-as-a-contract#the-skill-ecosystem" class="hash-link" aria-label="Direct link to The Skill Ecosystem" title="Direct link to The Skill Ecosystem" translate="no">​</a></h2>
<p>Logic Bee maintains a curated set of skills:</p>
<table><thead><tr><th>Skill</th><th>Contract</th></tr></thead><tbody><tr><td><code>creating-hooks</code></td><td>File structure, decorator metadata, scaffolding CLI</td></tr><tr><td><code>bob-request-api</code></td><td>BobRequest accessors and lifecycle</td></tr><tr><td><code>flow-query</code></td><td>Database operations and tenant scoping</td></tr><tr><td><code>hook-code-style</code></td><td>Naming, formatting, structural rules</td></tr><tr><td><code>hook-validation-rules</code></td><td>Hard rules and soft conventions</td></tr><tr><td><code>event-routing</code></td><td>How events dispatch to hooks</td></tr><tr><td><code>connectors</code></td><td>External API integration patterns</td></tr><tr><td><code>interfaces</code></td><td>Type definitions and data factories</td></tr></tbody></table>
<p>Each skill is a contract: "If you follow these rules, the generated code will be correct."</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="measuring-roi">Measuring ROI<a href="https://logicbee.ai/blog/skills-as-a-contract#measuring-roi" class="hash-link" aria-label="Direct link to Measuring ROI" title="Direct link to Measuring ROI" translate="no">​</a></h2>
<p>Before and after skill files:</p>
<table><thead><tr><th>Metric</th><th>Before Skills</th><th>After Skills</th></tr></thead><tbody><tr><td>AI-generated hooks needing revision</td><td>70%</td><td>15%</td></tr><tr><td>Convention violations per hook</td><td>3.2 avg</td><td>0.4 avg</td></tr><tr><td>Time from prompt to merge-ready</td><td>25 min</td><td>8 min</td></tr><tr><td>Developer context in prompts</td><td>5–10 lines</td><td>1 line (skill reference)</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="writing-your-first-skill">Writing Your First Skill<a href="https://logicbee.ai/blog/skills-as-a-contract#writing-your-first-skill" class="hash-link" aria-label="Direct link to Writing Your First Skill" title="Direct link to Writing Your First Skill" translate="no">​</a></h2>
<p>Start here:</p>
<ol>
<li class=""><strong>Pick your biggest pain point</strong> — what does the AI consistently get wrong?</li>
<li class=""><strong>Write the rule</strong> — prescriptive, with examples</li>
<li class=""><strong>Save it</strong> to <code>.agents/skills/your-skill-name/SKILL.md</code></li>
<li class=""><strong>Test it</strong> — prompt the AI to use the skill and check the output</li>
<li class=""><strong>Iterate</strong> — add rules as you find new patterns the AI misses</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-takeaway">The Takeaway<a href="https://logicbee.ai/blog/skills-as-a-contract#the-takeaway" class="hash-link" aria-label="Direct link to The Takeaway" title="Direct link to The Takeaway" translate="no">​</a></h2>
<p>Skills are the highest-leverage investment you can make in AI-assisted development. They turn tribal knowledge into machine-readable contracts. The developer's job isn't to correct AI output — it's to define the rules that make correction unnecessary.</p>
<p><strong>Write the contract once. Get correct code forever.</strong></p>]]></content>
        <author>
            <name>Gabriel Paunescu</name>
            <uri>https://www.linkedin.com/in/gabrielpaunescu/</uri>
        </author>
        <category label="AI" term="AI"/>
        <category label="Architecture" term="Architecture"/>
        <category label="Developer Experience" term="Developer Experience"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Debugging AI-Generated Code in an Event-Driven System]]></title>
        <id>https://logicbee.ai/blog/debugging-ai-generated-code</id>
        <link href="https://logicbee.ai/blog/debugging-ai-generated-code"/>
        <updated>2026-02-16T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The hook runs. It returns ok: true. The data looks right. But three hooks later in the pipeline, something breaks — and the stack trace points nowhere useful. Welcome to debugging in an event-driven system.]]></summary>
        <content type="html"><![CDATA[<p>The hook runs. It returns <code>ok: true</code>. The data looks right. But three hooks later in the pipeline, something breaks — and the stack trace points nowhere useful. Welcome to debugging in an event-driven system.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-premise">The Premise<a href="https://logicbee.ai/blog/debugging-ai-generated-code#the-premise" class="hash-link" aria-label="Direct link to The Premise" title="Direct link to The Premise" translate="no">​</a></h2>
<p>Debugging AI-generated hooks is different from debugging hand-written code. The code <em>looks</em> correct — it follows every convention, passes validation, and compiles cleanly. But AI optimizes for pattern matching, not for understanding the execution context. When a bug hides in the space between hooks, traditional debugging falls apart.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-story">The Story<a href="https://logicbee.ai/blog/debugging-ai-generated-code#the-story" class="hash-link" aria-label="Direct link to The Story" title="Direct link to The Story" translate="no">​</a></h2>
<p>A developer asks the AI to generate a hook for processing refunds. The hook queries the original invoice, calculates the refund amount, creates a credit memo, and updates the invoice status. The AI generates clean code. Tests pass. But in production, customers report that their invoice status shows "refunded" even when the credit memo creation fails.</p>
<p>The root cause? The AI wrote the status update <em>before</em> the credit memo creation — and without a shared database session, the two operations weren't atomic.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-debugging-playbook">The Debugging Playbook<a href="https://logicbee.ai/blog/debugging-ai-generated-code#the-debugging-playbook" class="hash-link" aria-label="Direct link to The Debugging Playbook" title="Direct link to The Debugging Playbook" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="step-1-trace-the-event-route">Step 1: Trace the Event Route<a href="https://logicbee.ai/blog/debugging-ai-generated-code#step-1-trace-the-event-route" class="hash-link" aria-label="Direct link to Step 1: Trace the Event Route" title="Direct link to Step 1: Trace the Event Route" translate="no">​</a></h3>
<p>Every request in Logic Bee flows through: <code>HTTP → Auth → FlowUser → Event Engine → Hook(s) → Response</code>. When something goes wrong, first verify that the right hook is even being called:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// Add temporary logging at the top of the try block</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token builtin" style="color:rgb(189, 147, 249)">console</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">log</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string string" style="color:rgb(255, 121, 198)">[DEBUG] </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation keyword" style="color:rgb(189, 147, 249);font-style:italic">new</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation class-name">Date</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation function" style="color:rgb(80, 250, 123)">toISOString</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string string" style="color:rgb(255, 121, 198)"> - Hook entered</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  hookPath</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'finance-bills/process-refund'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  docId</span><span class="token operator">:</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">dataPayload</span><span class="token operator">?.</span><span class="token plain">docId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  userId</span><span class="token operator">:</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token operator">?.</span><span class="token function" style="color:rgb(80, 250, 123)">getUserInfo</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token operator">?.</span><span class="token plain">id</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>If you don't see this log, the event routing is wrong — check the <code>@LogicHook</code> decorator's <code>path</code> property.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="step-2-verify-the-bobrequest-lifecycle">Step 2: Verify the BobRequest Lifecycle<a href="https://logicbee.ai/blog/debugging-ai-generated-code#step-2-verify-the-bobrequest-lifecycle" class="hash-link" aria-label="Direct link to Step 2: Verify the BobRequest Lifecycle" title="Direct link to Step 2: Verify the BobRequest Lifecycle" translate="no">​</a></h3>
<p>The <code>bob</code> object carries context through the entire execution. AI-generated code sometimes breaks the lifecycle by:</p>
<ul>
<li class=""><strong>Modifying <code>bob.dataPayload</code> directly</strong> instead of using <code>bob.replaceDataPayload()</code></li>
<li class=""><strong>Not passing <code>bob.dbSession()</code></strong> to write operations, breaking transaction boundaries</li>
<li class=""><strong>Calling <code>bob.executeRequestOrThrow()</code></strong> without error checking</li>
</ul>
<p>Check the <code>bob</code> state at each step:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// --&gt;Debug: log bob state before critical operations</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token builtin" style="color:rgb(189, 147, 249)">console</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">log</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'[DEBUG] dataPayload:'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token constant" style="color:rgb(189, 147, 249)">JSON</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">stringify</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">dataPayload</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">null</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">2</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token builtin" style="color:rgb(189, 147, 249)">console</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">log</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'[DEBUG] dbSession exists:'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token operator">!</span><span class="token operator">!</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">dbSession</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="step-3-check-operation-order">Step 3: Check Operation Order<a href="https://logicbee.ai/blog/debugging-ai-generated-code#step-3-check-operation-order" class="hash-link" aria-label="Direct link to Step 3: Check Operation Order" title="Direct link to Step 3: Check Operation Order" translate="no">​</a></h3>
<p>AI generates operations in the order they appear in the prompt, which may not be the correct execution order. In the refund story, the fix was:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ AI-generated order (status before credit memo)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">updateInvoiceStatus</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'refunded'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">createCreditMemo</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> refundData</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Correct order (credit memo first, then status)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> creditMemo </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">createCreditMemo</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> refundData</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">creditMemo</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">updateInvoiceStatus</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'refunded'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="step-4-verify-transaction-boundaries">Step 4: Verify Transaction Boundaries<a href="https://logicbee.ai/blog/debugging-ai-generated-code#step-4-verify-transaction-boundaries" class="hash-link" aria-label="Direct link to Step 4: Verify Transaction Boundaries" title="Direct link to Step 4: Verify Transaction Boundaries" translate="no">​</a></h3>
<p>When a hook performs multiple writes, all should share the same database session:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ AI sometimes creates independent write operations</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> collection1</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token operator">...</span><span class="token function" style="color:rgb(80, 250, 123)">updateOne</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> status</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'refunded'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> collection2</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token operator">...</span><span class="token function" style="color:rgb(80, 250, 123)">insertOne</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">creditMemoDoc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Both must use bob.dbSession()</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> collection1</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token operator">...</span><span class="token function" style="color:rgb(80, 250, 123)">updateOne</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> status</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'refunded'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">dbSession</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> collection2</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token operator">...</span><span class="token function" style="color:rgb(80, 250, 123)">insertOne</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">creditMemoDoc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">dbSession</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="step-5-check-sub-request-error-propagation">Step 5: Check Sub-Request Error Propagation<a href="https://logicbee.ai/blog/debugging-ai-generated-code#step-5-check-sub-request-error-propagation" class="hash-link" aria-label="Direct link to Step 5: Check Sub-Request Error Propagation" title="Direct link to Step 5: Check Sub-Request Error Propagation" translate="no">​</a></h3>
<p>When hooks call other hooks via <code>bob.executeRequestOrThrow()</code> or <code>bob.runAction()</code>, AI sometimes ignores the returned error:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ AI ignores sub-request failure</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> result </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">runAction</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'inventory.adjust-stock'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> data</span><span class="token operator">:</span><span class="token plain"> adjustmentData </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// continues execution even if result.ok === false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Check the result</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> result </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">runAction</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'inventory.adjust-stock'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> data</span><span class="token operator">:</span><span class="token plain"> adjustmentData </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token operator">!</span><span class="token plain">result</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">ok</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">throw</span><span class="token plain"> result</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">error </span><span class="token operator">||</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">naoFormatErrorById</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'bad_request'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    reason</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'Stock adjustment failed during refund processing'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="common-ai-generated-bug-patterns">Common AI-Generated Bug Patterns<a href="https://logicbee.ai/blog/debugging-ai-generated-code#common-ai-generated-bug-patterns" class="hash-link" aria-label="Direct link to Common AI-Generated Bug Patterns" title="Direct link to Common AI-Generated Bug Patterns" translate="no">​</a></h2>
<table><thead><tr><th>Pattern</th><th>Symptom</th><th>Root Cause</th></tr></thead><tbody><tr><td>Silent data corruption</td><td>Downstream hooks get wrong data</td><td>Direct <code>bob.dataPayload</code> mutation</td></tr><tr><td>Partial writes</td><td>Some documents updated, others not</td><td>Missing <code>bob.dbSession()</code> on some writes</td></tr><tr><td>Wrong hook called</td><td>Action does nothing or wrong thing</td><td>Decorator <code>path</code> doesn't match expected route</td></tr><tr><td>Ignored sub-request errors</td><td>Happy path always succeeds</td><td>Missing <code>.ok</code> check on <code>runAction</code> results</td></tr><tr><td>Race conditions</td><td>Intermittent failures under load</td><td><code>await</code> missing on async calls</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-takeaway">The Takeaway<a href="https://logicbee.ai/blog/debugging-ai-generated-code#the-takeaway" class="hash-link" aria-label="Direct link to The Takeaway" title="Direct link to The Takeaway" translate="no">​</a></h2>
<p>When debugging AI-generated hooks in a pipeline:</p>
<ol>
<li class=""><strong>Start at the route</strong> — is the right hook being called?</li>
<li class=""><strong>Check the bob lifecycle</strong> — is the request context intact?</li>
<li class=""><strong>Verify operation order</strong> — does the sequence match the business requirement?</li>
<li class=""><strong>Audit every write</strong> — does each one use <code>bob.dbSession()</code>?</li>
<li class=""><strong>Test sub-requests</strong> — are errors from child hooks handled?</li>
</ol>
<p><strong>The AI writes code that looks right. Your job is to verify it <em>runs</em> right — in context, in sequence, and under failure.</strong></p>]]></content>
        <author>
            <name>Gabriel Paunescu</name>
            <uri>https://www.linkedin.com/in/gabrielpaunescu/</uri>
        </author>
        <category label="AI" term="AI"/>
        <category label="Hooks" term="Hooks"/>
        <category label="Developer Experience" term="Developer Experience"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[The Developer's Review Checklist for AI-Generated Hooks]]></title>
        <id>https://logicbee.ai/blog/developer-review-checklist-ai-hooks</id>
        <link href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks"/>
        <updated>2026-02-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[AI follows the rules it knows. Your job is knowing the rules it missed. Here's the definitive review checklist for AI-generated Logic Bee hooks — 10 hard rules and 12 soft conventions, explained with real examples.]]></summary>
        <content type="html"><![CDATA[<p>AI follows the rules it knows. Your job is knowing the rules it missed. Here's the definitive review checklist for AI-generated Logic Bee hooks — 10 hard rules and 12 soft conventions, explained with real examples.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-premise">The Premise<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#the-premise" class="hash-link" aria-label="Direct link to The Premise" title="Direct link to The Premise" translate="no">​</a></h2>
<p>Logic Bee's AI validation system checks generated hooks against two categories of rules: <strong>hard rules</strong> that must never be violated, and <strong>soft conventions</strong> that should be followed unless there's a documented reason not to. The AI self-validates, but no validation is perfect — and understanding <em>why</em> each rule exists makes you a better reviewer.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-story">The Story<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#the-story" class="hash-link" aria-label="Direct link to The Story" title="Direct link to The Story" translate="no">​</a></h2>
<p>A junior developer merges an AI-generated hook without review. It passes all automated checks. Two weeks later, a production incident reveals that the hook was silently mutating <code>bob.dataPayload</code> directly — causing downstream hooks in the pipeline to receive corrupted data. The mutation wasn't caught because it's a soft convention violation, not a hard rule.</p>
<p>That incident inspired this checklist.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-10-hard-rules">The 10 Hard Rules<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#the-10-hard-rules" class="hash-link" aria-label="Direct link to The 10 Hard Rules" title="Direct link to The 10 Hard Rules" translate="no">​</a></h2>
<p>These are non-negotiable. If any of these fail, the hook must not be merged.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="1-ok-must-be-assigned-before-return">1. <code>ok</code> Must Be Assigned Before Return<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#1-ok-must-be-assigned-before-return" class="hash-link" aria-label="Direct link to 1-ok-must-be-assigned-before-return" title="Direct link to 1-ok-must-be-assigned-before-return" translate="no">​</a></h3>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ Missing ok assignment in success path</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">try</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  data </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">someOperation</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)">// forgot: ok = true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">err</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> error </span><span class="token operator">=</span><span class="token plain"> err</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"> ok </span><span class="token operator">=</span><span class="token plain"> </span><span class="token boolean">false</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="2-data-must-be-assigned-before-return">2. <code>data</code> Must Be Assigned Before Return<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#2-data-must-be-assigned-before-return" class="hash-link" aria-label="Direct link to 2-data-must-be-assigned-before-return" title="Direct link to 2-data-must-be-assigned-before-return" translate="no">​</a></h3>
<p>Every successful execution must set <code>data</code> — even if it's just <code>{ success: true }</code>.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="3-bobflowuser-must-be-passed-to-every-flowquery">3. <code>bob.flowUser</code> Must Be Passed to Every FlowQuery<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#3-bobflowuser-must-be-passed-to-every-flowquery" class="hash-link" aria-label="Direct link to 3-bobflowuser-must-be-passed-to-every-flowquery" title="Direct link to 3-bobflowuser-must-be-passed-to-every-flowquery" translate="no">​</a></h3>
<p>No exceptions. No helper functions that skip it. Every <code>.flowQuery()</code> chain needs <code>.user(bob.flowUser)</code>.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="4-returneventresult-must-be-the-last-statement">4. <code>returnEventResult</code> Must Be the Last Statement<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#4-returneventresult-must-be-the-last-statement" class="hash-link" aria-label="Direct link to 4-returneventresult-must-be-the-last-statement" title="Direct link to 4-returneventresult-must-be-the-last-statement" translate="no">​</a></h3>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ Code after returnEventResult</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">returnEventResult</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> ok</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> error</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token builtin" style="color:rgb(189, 147, 249)">console</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">log</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'done'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)">// unreachable but indicates confusion</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="5-error-variable-must-be-set-in-catch-block">5. Error Variable Must Be Set in Catch Block<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#5-error-variable-must-be-set-in-catch-block" class="hash-link" aria-label="Direct link to 5. Error Variable Must Be Set in Catch Block" title="Direct link to 5. Error Variable Must Be Set in Catch Block" translate="no">​</a></h3>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ Missing error assignment</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">err</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  ok </span><span class="token operator">=</span><span class="token plain"> </span><span class="token boolean">false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)">// forgot: error = err</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="6-trycatch-must-wrap-all-logic">6. <code>try/catch</code> Must Wrap All Logic<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#6-trycatch-must-wrap-all-logic" class="hash-link" aria-label="Direct link to 6-trycatch-must-wrap-all-logic" title="Direct link to 6-trycatch-must-wrap-all-logic" translate="no">​</a></h3>
<p>No business logic outside the try block except variable initialization.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="7-flowquery-must-include-flowoptions">7. FlowQuery Must Include <code>.flowOptions()</code><a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#7-flowquery-must-include-flowoptions" class="hash-link" aria-label="Direct link to 7-flowquery-must-include-flowoptions" title="Direct link to 7-flowquery-must-include-flowoptions" translate="no">​</a></h3>
<p>Every query needs the collection metadata to resolve correctly.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="8-decorator-metadata-must-match-file-path">8. Decorator Metadata Must Match File Path<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#8-decorator-metadata-must-match-file-path" class="hash-link" aria-label="Direct link to 8. Decorator Metadata Must Match File Path" title="Direct link to 8. Decorator Metadata Must Match File Path" translate="no">​</a></h3>
<p><code>path: 'finance-bills/calculate-late-fees'</code> must correspond to the actual file location.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="9-write-operations-must-pass-bobdbsession">9. Write Operations Must Pass <code>bob.dbSession()</code><a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#9-write-operations-must-pass-bobdbsession" class="hash-link" aria-label="Direct link to 9-write-operations-must-pass-bobdbsession" title="Direct link to 9-write-operations-must-pass-bobdbsession" translate="no">​</a></h3>
<p>For transactional integrity across multi-document updates.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="10-thrown-errors-must-use-naoformaterrorbyid">10. Thrown Errors Must Use <code>naoFormatErrorById</code><a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#10-thrown-errors-must-use-naoformaterrorbyid" class="hash-link" aria-label="Direct link to 10-thrown-errors-must-use-naoformaterrorbyid" title="Direct link to 10-thrown-errors-must-use-naoformaterrorbyid" translate="no">​</a></h3>
<p>Raw <code>throw new Error()</code> produces unstructured error responses.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-12-soft-conventions">The 12 Soft Conventions<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#the-12-soft-conventions" class="hash-link" aria-label="Direct link to The 12 Soft Conventions" title="Direct link to The 12 Soft Conventions" translate="no">​</a></h2>
<p>These improve code quality and consistency. Violations should be fixed unless there's a strong reason to deviate.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="1-eventoptions-first">1. <code>eventOptions</code> First<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#1-eventoptions-first" class="hash-link" aria-label="Direct link to 1-eventoptions-first" title="Direct link to 1-eventoptions-first" translate="no">​</a></h3>
<p>Declare the <code>eventOptions</code> object as the first statement inside the try block.</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">try</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> eventOptions </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    billNaoQueryOptions</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> docName</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'bill'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> cfpPath</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'finance/bills'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)">// ... rest of logic</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="2-arrow-comments-for-structure">2. Arrow Comments for Structure<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#2-arrow-comments-for-structure" class="hash-link" aria-label="Direct link to 2. Arrow Comments for Structure" title="Direct link to 2. Arrow Comments for Structure" translate="no">​</a></h3>
<p>Use <code>// --&gt;Get:</code>, <code>// --&gt;Set:</code>, <code>// --&gt;Validate:</code>, <code>// --&gt;Iterate:</code>, <code>// --&gt;Update:</code> prefix comments.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="3-naoutilsmathchain-for-math">3. <code>naoUtils.mathChain()</code> for Math<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#3-naoutilsmathchain-for-math" class="hash-link" aria-label="Direct link to 3-naoutilsmathchain-for-math" title="Direct link to 3-naoutilsmathchain-for-math" translate="no">​</a></h3>
<p>Never use raw arithmetic for financial calculations. Floating point errors are real.</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ Raw arithmetic</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> total </span><span class="token operator">=</span><span class="token plain"> quantity </span><span class="token operator">*</span><span class="token plain"> unitPrice</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Math chain</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> total </span><span class="token operator">=</span><span class="token plain"> naoUtils</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">mathChain</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">quantity</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">multiply</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">unitPrice</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">done</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="4-naodatetime-for-dates">4. <code>naoDateTime()</code> for Dates<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#4-naodatetime-for-dates" class="hash-link" aria-label="Direct link to 4-naodatetime-for-dates" title="Direct link to 4-naodatetime-for-dates" translate="no">​</a></h3>
<p>Never use <code>new Date()</code> or <code>Date.now()</code>. The Luxon-based wrapper handles timezones correctly.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="5-dont-mutate-bobdatapayload">5. Don't Mutate <code>bob.dataPayload</code><a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#5-dont-mutate-bobdatapayload" class="hash-link" aria-label="Direct link to 5-dont-mutate-bobdatapayload" title="Direct link to 5-dont-mutate-bobdatapayload" translate="no">​</a></h3>
<p>Read from it. Don't write to it. Use <code>bob.replaceDataPayload()</code> if you need to pass modified data downstream.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="6-one-responsibility-per-hook">6. One Responsibility Per Hook<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#6-one-responsibility-per-hook" class="hash-link" aria-label="Direct link to 6. One Responsibility Per Hook" title="Direct link to 6. One Responsibility Per Hook" translate="no">​</a></h3>
<p>If the AI generates a hook that both validates and processes, consider splitting it into two hooks.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="7-guard-clauses-before-logic">7. Guard Clauses Before Logic<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#7-guard-clauses-before-logic" class="hash-link" aria-label="Direct link to 7. Guard Clauses Before Logic" title="Direct link to 7. Guard Clauses Before Logic" translate="no">​</a></h3>
<p>Check for nulls, empty arrays, and invalid states at the top of the try block.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="8-descriptive-error-reasons">8. Descriptive Error Reasons<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#8-descriptive-error-reasons" class="hash-link" aria-label="Direct link to 8. Descriptive Error Reasons" title="Direct link to 8. Descriptive Error Reasons" translate="no">​</a></h3>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ Vague</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">throw</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">naoFormatErrorById</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'bad_request'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> reason</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'Invalid'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Descriptive</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">throw</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">naoFormatErrorById</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'bad_request'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  reason</span><span class="token operator">:</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string string" style="color:rgb(255, 121, 198)">Bill </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">bill</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation">docId</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string string" style="color:rgb(255, 121, 198)"> has zero balance and cannot accrue late fees</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="9-typescript-interface-references">9. TypeScript Interface References<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#9-typescript-interface-references" class="hash-link" aria-label="Direct link to 9. TypeScript Interface References" title="Direct link to 9. TypeScript Interface References" translate="no">​</a></h3>
<p>Pass the interface name to <code>.getMany()</code> and <code>.getOne()</code> for type safety.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="10-consistent-variable-naming">10. Consistent Variable Naming<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#10-consistent-variable-naming" class="hash-link" aria-label="Direct link to 10. Consistent Variable Naming" title="Direct link to 10. Consistent Variable Naming" translate="no">​</a></h3>
<p>Use <code>fc</code> for flow collections, <code>doc</code> for single documents, <code>docs</code> for arrays.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="11-no-consolelog-in-production-code">11. No <code>console.log</code> in Production Code<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#11-no-consolelog-in-production-code" class="hash-link" aria-label="Direct link to 11-no-consolelog-in-production-code" title="Direct link to 11-no-consolelog-in-production-code" translate="no">​</a></h3>
<p>Use the structured logging utilities from <code>@logic-bee/utils</code>.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="12-end-with-ok--true-data--result">12. End With <code>ok = true; data = result</code><a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#12-end-with-ok--true-data--result" class="hash-link" aria-label="Direct link to 12-end-with-ok--true-data--result" title="Direct link to 12-end-with-ok--true-data--result" translate="no">​</a></h3>
<p>The last two lines of the try block should always be the success assignment.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-review-shortcut">The Review Shortcut<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#the-review-shortcut" class="hash-link" aria-label="Direct link to The Review Shortcut" title="Direct link to The Review Shortcut" translate="no">​</a></h2>
<p>When reviewing AI-generated hooks, scan in this order:</p>
<ol>
<li class=""><strong>Scroll to the bottom</strong> — is <code>returnEventResult</code> the last statement?</li>
<li class=""><strong>Search for <code>.flowQuery()</code></strong> — does every chain have <code>.user(bob.flowUser)</code>?</li>
<li class=""><strong>Search for <code>.updateOne()</code> / <code>.updateMany()</code></strong> — does every write pass <code>bob.dbSession()</code>?</li>
<li class=""><strong>Read the catch block</strong> — are both <code>error = err</code> and <code>ok = false</code> present?</li>
<li class=""><strong>Read the first line of the try block</strong> — is <code>eventOptions</code> declared first?</li>
</ol>
<p>If all five pass, you're likely looking at a clean hook.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-takeaway">The Takeaway<a href="https://logicbee.ai/blog/developer-review-checklist-ai-hooks#the-takeaway" class="hash-link" aria-label="Direct link to The Takeaway" title="Direct link to The Takeaway" translate="no">​</a></h2>
<p>Print this. Pin it next to your monitor. Use it every time you review AI output:</p>
<blockquote>
<p><strong>Hard rules</strong> = merge blockers. <strong>Soft conventions</strong> = code quality. <strong>Both</strong> = production readiness.</p>
</blockquote>]]></content>
        <author>
            <name>Gabriel Paunescu</name>
            <uri>https://www.linkedin.com/in/gabrielpaunescu/</uri>
        </author>
        <category label="AI" term="AI"/>
        <category label="Best Practices" term="Best Practices"/>
        <category label="Hooks" term="Hooks"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[AI-Powered Connector Integration: Wiring Up External APIs Faster]]></title>
        <id>https://logicbee.ai/blog/ai-powered-connector-integration</id>
        <link href="https://logicbee.ai/blog/ai-powered-connector-integration"/>
        <updated>2026-01-19T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Every Stripe integration starts the same way — auth headers, request builders, error mappers, retry logic. Let the AI handle the boilerplate so you can focus on the business logic that makes your integration unique.]]></summary>
        <content type="html"><![CDATA[<p>Every Stripe integration starts the same way — auth headers, request builders, error mappers, retry logic. Let the AI handle the boilerplate so you can focus on the business logic that makes your integration unique.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-premise">The Premise<a href="https://logicbee.ai/blog/ai-powered-connector-integration#the-premise" class="hash-link" aria-label="Direct link to The Premise" title="Direct link to The Premise" translate="no">​</a></h2>
<p>Logic Bee's connector architecture separates external API communication into reusable connector classes in <code>libs/connectors/</code>. When a hook needs to talk to Stripe, QuickBooks, or UPS, it calls a connector — never the raw HTTP client. This pattern is perfect for AI generation because connectors follow a rigid contract.</p>
<p>The developer's role shifts from writing HTTP calls to validating auth flows, error mapping, and retry behavior.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-story">The Story<a href="https://logicbee.ai/blog/ai-powered-connector-integration#the-story" class="hash-link" aria-label="Direct link to The Story" title="Direct link to The Story" translate="no">​</a></h2>
<p>The team needs a new ShipStation integration for the <code>shipping-management</code> library. A developer prompts:</p>
<blockquote>
<p><em>"Add a ShipStation connector that creates shipment labels and tracks packages. Wire it into a new hook called create-shipment-label in shipping-management. Use the connectors, creating-hooks, and bob-request-api skills."</em></p>
</blockquote>
<p>The AI generates two things: the connector class and the hook that uses it.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="what-the-ai-generates">What the AI Generates<a href="https://logicbee.ai/blog/ai-powered-connector-integration#what-the-ai-generates" class="hash-link" aria-label="Direct link to What the AI Generates" title="Direct link to What the AI Generates" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="the-connector">The Connector<a href="https://logicbee.ai/blog/ai-powered-connector-integration#the-connector" class="hash-link" aria-label="Direct link to The Connector" title="Direct link to The Connector" translate="no">​</a></h3>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">class</span><span class="token plain"> </span><span class="token class-name">ShipStationConnector</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">private</span><span class="token plain"> baseUrl </span><span class="token operator">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'https://ssapi.shipstation.com'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token function" style="color:rgb(80, 250, 123)">constructor</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">private</span><span class="token plain"> apiKey</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">string</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">private</span><span class="token plain"> apiSecret</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">string</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">async</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">createLabel</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">shipmentData</span><span class="token operator">:</span><span class="token plain"> CreateLabelPayload</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">Promise</span><span class="token operator">&lt;</span><span class="token plain">ShipStationLabel</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> response </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">fetch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation keyword" style="color:rgb(189, 147, 249);font-style:italic">this</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation">baseUrl</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string string" style="color:rgb(255, 121, 198)">/shipments/createlabel</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      method</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'POST'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      headers</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token string-property property">'Content-Type'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'application/json'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token string-property property">'Authorization'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string string" style="color:rgb(255, 121, 198)">Basic </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">Buffer</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation function" style="color:rgb(80, 250, 123)">from</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string interpolation template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string interpolation template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation template-string interpolation keyword" style="color:rgb(189, 147, 249);font-style:italic">this</span><span class="token template-string interpolation template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation template-string interpolation">apiKey</span><span class="token template-string interpolation template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string interpolation template-string string" style="color:rgb(255, 121, 198)">:</span><span class="token template-string interpolation template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation template-string interpolation keyword" style="color:rgb(189, 147, 249);font-style:italic">this</span><span class="token template-string interpolation template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation template-string interpolation">apiSecret</span><span class="token template-string interpolation template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string interpolation template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation function" style="color:rgb(80, 250, 123)">toString</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token template-string interpolation string" style="color:rgb(255, 121, 198)">'base64'</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      body</span><span class="token operator">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(189, 147, 249)">JSON</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">stringify</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">shipmentData</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token operator">!</span><span class="token plain">response</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">ok</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">throw</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">naoFormatErrorById</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'bad_request'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        reason</span><span class="token operator">:</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string string" style="color:rgb(255, 121, 198)">ShipStation API error: </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">response</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation">status</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> response</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">json</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="the-hook">The Hook<a href="https://logicbee.ai/blog/ai-powered-connector-integration#the-hook" class="hash-link" aria-label="Direct link to The Hook" title="Direct link to The Hook" translate="no">​</a></h3>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token decorator at operator">@</span><span class="token decorator function" style="color:rgb(80, 250, 123)">LogicHook</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  name</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'ShippingManagementCreateShipmentLabel'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  path</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'shipping-management/create-shipment-label'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  library</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'shipping-management'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  method</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'create-shipment-label'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  legacy</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'app/app.shippingManagementHooks.createShipmentLabel'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">class</span><span class="token plain"> </span><span class="token class-name">ShippingManagementCreateShipmentLabel</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">public</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">static</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">execute</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token operator">:</span><span class="token plain"> BobRequest</span><span class="token operator">&lt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> data</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> data</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">any</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"> naoQueryOptions</span><span class="token operator">:</span><span class="token plain"> NaoQueryOptions </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token operator">&gt;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">let</span><span class="token plain"> ok </span><span class="token operator">=</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> error</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">any</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">null</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">try</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> eventOptions </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          shipmentQuery</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> docName</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'shipment'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> cfpPath</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'shipping/shipments'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token comment" style="color:rgb(98, 114, 164)">// --&gt;Get: shipment document</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> shipment </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowGlobal</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getFlowCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">shipmentQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">shipmentQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">docId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">dataPayload</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getOne</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token operator">!</span><span class="token plain">shipment</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">throw</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">naoFormatErrorById</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'not_found'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> reason</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'Shipment not found'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token comment" style="color:rgb(98, 114, 164)">// --&gt;Create: shipping label via connector</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> connector </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">new</span><span class="token plain"> </span><span class="token class-name">ShipStationConnector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          process</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">env</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token constant" style="color:rgb(189, 147, 249)">SHIPSTATION_API_KEY</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          process</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">env</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token constant" style="color:rgb(189, 147, 249)">SHIPSTATION_API_SECRET</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> label </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> connector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">createLabel</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          orderId</span><span class="token operator">:</span><span class="token plain"> shipment</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">orderId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          weight</span><span class="token operator">:</span><span class="token plain"> shipment</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">totalWeight</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          dimensions</span><span class="token operator">:</span><span class="token plain"> shipment</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">dimensions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          shipTo</span><span class="token operator">:</span><span class="token plain"> shipment</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">shippingAddress</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token comment" style="color:rgb(98, 114, 164)">// --&gt;Update: shipment with tracking info</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowGlobal</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getFlowCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">shipmentQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">shipmentQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">docId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">shipment</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">updateOne</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token string-property property">'data.trackingNumber'</span><span class="token operator">:</span><span class="token plain"> label</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">trackingNumber</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token string-property property">'data.labelUrl'</span><span class="token operator">:</span><span class="token plain"> label</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">labelUrl</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token string-property property">'data.status'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'label-created'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">dbSession</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        ok </span><span class="token operator">=</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        data </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> docIds</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain">shipment</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> trackingNumber</span><span class="token operator">:</span><span class="token plain"> label</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">trackingNumber </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">err</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> error </span><span class="token operator">=</span><span class="token plain"> err</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"> ok </span><span class="token operator">=</span><span class="token plain"> </span><span class="token boolean">false</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">returnEventResult</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> ok</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> error</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="what-you-need-to-verify">What You Need to Verify<a href="https://logicbee.ai/blog/ai-powered-connector-integration#what-you-need-to-verify" class="hash-link" aria-label="Direct link to What You Need to Verify" title="Direct link to What You Need to Verify" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="1-credential-management">1. Credential Management<a href="https://logicbee.ai/blog/ai-powered-connector-integration#1-credential-management" class="hash-link" aria-label="Direct link to 1. Credential Management" title="Direct link to 1. Credential Management" translate="no">​</a></h3>
<p>AI often hardcodes <code>process.env.VARIABLE_NAME</code> directly. In Logic Bee, credentials should flow through the configuration layer:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ AI default</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> connector </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">new</span><span class="token plain"> </span><span class="token class-name">ShipStationConnector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  process</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">env</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token constant" style="color:rgb(189, 147, 249)">SHIPSTATION_API_KEY</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  process</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">env</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token constant" style="color:rgb(189, 147, 249)">SHIPSTATION_API_SECRET</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Better: use workspace-scoped config</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> config </span><span class="token operator">=</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getWorkspaceConfig</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'shipstation'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> connector </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">new</span><span class="token plain"> </span><span class="token class-name">ShipStationConnector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">config</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">apiKey</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> config</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">apiSecret</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="2-error-response-mapping">2. Error Response Mapping<a href="https://logicbee.ai/blog/ai-powered-connector-integration#2-error-response-mapping" class="hash-link" aria-label="Direct link to 2. Error Response Mapping" title="Direct link to 2. Error Response Mapping" translate="no">​</a></h3>
<p>The AI generates a generic error handler. Real APIs return structured errors — map them:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Map API-specific errors to Logic Bee error format</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token operator">!</span><span class="token plain">response</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">ok</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> errorBody </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> response</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">json</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">throw</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">naoFormatErrorById</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'bad_request'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    reason</span><span class="token operator">:</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token template-string string" style="color:rgb(255, 121, 198)">ShipStation: </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">${</span><span class="token template-string interpolation">errorBody</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation">ExceptionMessage </span><span class="token template-string interpolation operator">||</span><span class="token template-string interpolation"> response</span><span class="token template-string interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token template-string interpolation">statusText</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token template-string template-punctuation string" style="color:rgb(255, 121, 198)">`</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    details</span><span class="token operator">:</span><span class="token plain"> errorBody</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="3-rate-limiting-and-retries">3. Rate Limiting and Retries<a href="https://logicbee.ai/blog/ai-powered-connector-integration#3-rate-limiting-and-retries" class="hash-link" aria-label="Direct link to 3. Rate Limiting and Retries" title="Direct link to 3. Rate Limiting and Retries" translate="no">​</a></h3>
<p>External APIs have rate limits. The AI rarely adds retry logic unless prompted.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="4-payload-validation">4. Payload Validation<a href="https://logicbee.ai/blog/ai-powered-connector-integration#4-payload-validation" class="hash-link" aria-label="Direct link to 4. Payload Validation" title="Direct link to 4. Payload Validation" translate="no">​</a></h3>
<p>Verify the connector validates outbound payloads before sending — missing required fields should fail fast, not at the API level.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-takeaway">The Takeaway<a href="https://logicbee.ai/blog/ai-powered-connector-integration#the-takeaway" class="hash-link" aria-label="Direct link to The Takeaway" title="Direct link to The Takeaway" translate="no">​</a></h2>
<p>The connector integration checklist:</p>
<ul class="contains-task-list containsTaskList_QswE">
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Credentials loaded from workspace config, not <code>process.env</code></li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->API errors mapped to <code>naoFormatErrorById</code> with descriptive reasons</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Rate limiting and retry logic included</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Outbound payload validated before API call</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Response types match TypeScript interfaces</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->API-specific edge cases documented in connector class</li>
</ul>
<p><strong>Let AI wire the plumbing. You verify the valves.</strong></p>]]></content>
        <author>
            <name>Gabriel Paunescu</name>
            <uri>https://www.linkedin.com/in/gabrielpaunescu/</uri>
        </author>
        <category label="AI" term="AI"/>
        <category label="Connectors" term="Connectors"/>
        <category label="Hooks" term="Hooks"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Prompt Engineering for ERP Logic: How to Talk to Your AI Agent]]></title>
        <id>https://logicbee.ai/blog/prompt-engineering-for-erp-logic</id>
        <link href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic"/>
        <updated>2026-01-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The difference between a hook that needs 20 minutes of fixing and one that's merge-ready comes down to how you write the prompt. Garbage in, garbage out — but structured prompts unlock structured code.]]></summary>
        <content type="html"><![CDATA[<p>The difference between a hook that needs 20 minutes of fixing and one that's merge-ready comes down to how you write the prompt. Garbage in, garbage out — but structured prompts unlock structured code.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-premise">The Premise<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#the-premise" class="hash-link" aria-label="Direct link to The Premise" title="Direct link to The Premise" translate="no">​</a></h2>
<p>Logic Bee's AI agent has skills — structured knowledge files about the codebase's conventions, patterns, and tools. But skills are only activated when the AI recognizes them as relevant. A vague prompt activates vague knowledge. A precise prompt activates exactly the right skill at the right depth.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-story">The Story<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#the-story" class="hash-link" aria-label="Direct link to The Story" title="Direct link to The Story" translate="no">​</a></h2>
<p>Two developers need the same hook: a function in the <code>inventory-management</code> library that adjusts stock levels after a sales order is confirmed. Here are their prompts:</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="the-vague-prompt">The Vague Prompt<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#the-vague-prompt" class="hash-link" aria-label="Direct link to The Vague Prompt" title="Direct link to The Vague Prompt" translate="no">​</a></h3>
<blockquote>
<p><em>"Create a hook that updates inventory when an order is placed."</em></p>
</blockquote>
<p>The AI generates a functional but generic hook. It uses a basic query pattern, doesn't reference the correct collection names, and invents a field structure that doesn't match the actual schema.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="the-precise-prompt">The Precise Prompt<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#the-precise-prompt" class="hash-link" aria-label="Direct link to The Precise Prompt" title="Direct link to The Precise Prompt" translate="no">​</a></h3>
<blockquote>
<p><em>"Create a new hook in inventory-management called adjust-stock-on-order-confirm. When a sales order status changes to 'confirmed', decrement the stock quantity for each line item. Use flowQuery to look up items by SKU in the inventory/items collection. Throw a bad_request error if any item has insufficient stock. Use the creating-hooks, flow-query, and hook-code-style skills."</em></p>
</blockquote>
<p>The AI generates code that follows every convention, queries the right collections, handles edge cases, and validates inputs.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-anatomy-of-an-effective-prompt">The Anatomy of an Effective Prompt<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#the-anatomy-of-an-effective-prompt" class="hash-link" aria-label="Direct link to The Anatomy of an Effective Prompt" title="Direct link to The Anatomy of an Effective Prompt" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="1-name-the-library-and-method">1. Name the Library and Method<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#1-name-the-library-and-method" class="hash-link" aria-label="Direct link to 1. Name the Library and Method" title="Direct link to 1. Name the Library and Method" translate="no">​</a></h3>
<p>Always specify where the hook lives. The AI uses this to set the file path, decorator metadata, and naming conventions.</p>
<div class="language-text codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-text codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token plain">❌ "Create a hook that..."</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✅ "Create a new hook in finance-bills called calculate-late-fees..."</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="2-describe-the-trigger">2. Describe the Trigger<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#2-describe-the-trigger" class="hash-link" aria-label="Direct link to 2. Describe the Trigger" title="Direct link to 2. Describe the Trigger" translate="no">​</a></h3>
<p>ERP logic doesn't exist in isolation. Tell the AI <em>when</em> this logic runs.</p>
<div class="language-text codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-text codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token plain">❌ "Update inventory"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✅ "When a sales order status changes to 'confirmed'"</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="3-specify-collections-and-fields">3. Specify Collections and Fields<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#3-specify-collections-and-fields" class="hash-link" aria-label="Direct link to 3. Specify Collections and Fields" title="Direct link to 3. Specify Collections and Fields" translate="no">​</a></h3>
<p>The AI will guess field names if you don't provide them, and it will guess wrong.</p>
<div class="language-text codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-text codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token plain">❌ "Look up the product"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✅ "Use flowQuery to look up items by SKU in the inventory/items collection"</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="4-define-error-conditions">4. Define Error Conditions<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#4-define-error-conditions" class="hash-link" aria-label="Direct link to 4. Define Error Conditions" title="Direct link to 4. Define Error Conditions" translate="no">​</a></h3>
<p>Guard clauses and error handling are where AI-generated code is weakest. Explicitly state what should fail and how.</p>
<div class="language-text codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-text codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token plain">❌ "Handle errors"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✅ "Throw a bad_request error if any item has insufficient stock"</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="5-reference-skills-by-name">5. Reference Skills by Name<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#5-reference-skills-by-name" class="hash-link" aria-label="Direct link to 5. Reference Skills by Name" title="Direct link to 5. Reference Skills by Name" translate="no">​</a></h3>
<p>This is the multiplier. Skill references tell the AI exactly which knowledge to load.</p>
<div class="language-text codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-text codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token plain">❌ (no skill reference)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">✅ "Use the creating-hooks, flow-query, and hook-code-style skills"</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="prompt-template">Prompt Template<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#prompt-template" class="hash-link" aria-label="Direct link to Prompt Template" title="Direct link to Prompt Template" translate="no">​</a></h2>
<p>Here's a copy-paste template for creating hooks:</p>
<div class="language-text codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-text codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Create a new hook in [library-slug] called [method-slug].</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">When [trigger condition], [primary action].</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Use flowQuery to [query description] in the [collection-path] collection.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">[Additional business rules].</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Throw a [error-type] error if [failure condition].</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Use the creating-hooks, flow-query, and hook-code-style skills.</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="example-using-the-template">Example using the template:<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#example-using-the-template" class="hash-link" aria-label="Direct link to Example using the template:" title="Direct link to Example using the template:" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-text codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Create a new hook in shipping-management called calculate-shipping-rates.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">When a sales order is ready for fulfillment, calculate shipping rates </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">for all available carriers. Use flowQuery to look up the order's line </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">items in the sales/orders collection and the customer's shipping address </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">in the contacts/addresses collection. Apply weight-based rate tiers </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">from the shipping/rate-tables collection. Throw a bad_request error if </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">the shipping address is missing or if total weight exceeds carrier limits.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Use the creating-hooks, flow-query, and hook-code-style skills.</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="advanced-techniques">Advanced Techniques<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#advanced-techniques" class="hash-link" aria-label="Direct link to Advanced Techniques" title="Direct link to Advanced Techniques" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="ask-for-a-pattern-search-first">Ask for a Pattern Search First<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#ask-for-a-pattern-search-first" class="hash-link" aria-label="Direct link to Ask for a Pattern Search First" title="Direct link to Ask for a Pattern Search First" translate="no">​</a></h3>
<p>Before generating new code, ask the AI to find similar existing hooks:</p>
<blockquote>
<p><em>"Search for hooks that match the pattern 'calculate' in the finance-bills library."</em></p>
</blockquote>
<p>This gives the AI a concrete reference implementation, producing much better results than generating from skills alone.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="chain-prompts-for-complex-hooks">Chain Prompts for Complex Hooks<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#chain-prompts-for-complex-hooks" class="hash-link" aria-label="Direct link to Chain Prompts for Complex Hooks" title="Direct link to Chain Prompts for Complex Hooks" translate="no">​</a></h3>
<p>For hooks with multiple steps, break the work into sequential prompts:</p>
<ol>
<li class=""><em>"Scaffold the hook structure for..."</em></li>
<li class=""><em>"Now implement the query logic using..."</em></li>
<li class=""><em>"Add validation for..."</em></li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="specify-what-not-to-do">Specify What NOT to Do<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#specify-what-not-to-do" class="hash-link" aria-label="Direct link to Specify What NOT to Do" title="Direct link to Specify What NOT to Do" translate="no">​</a></h3>
<p>Negative constraints are surprisingly effective:</p>
<blockquote>
<p><em>"Do not fetch all documents — use pagination. Do not calculate totals in JavaScript — use a database aggregation pipeline."</em></p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-takeaway">The Takeaway<a href="https://logicbee.ai/blog/prompt-engineering-for-erp-logic#the-takeaway" class="hash-link" aria-label="Direct link to The Takeaway" title="Direct link to The Takeaway" translate="no">​</a></h2>
<p>Effective prompts for ERP logic follow a formula: <strong>name the location</strong>, <strong>describe the trigger</strong>, <strong>specify the data</strong>, <strong>define the errors</strong>, and <strong>reference the skills</strong>. The five minutes you spend writing a precise prompt save thirty minutes of fixing vague output.</p>
<p>Your prompt is your spec. Write it like one.</p>]]></content>
        <author>
            <name>Gabriel Paunescu</name>
            <uri>https://www.linkedin.com/in/gabrielpaunescu/</uri>
        </author>
        <category label="AI" term="AI"/>
        <category label="Developer Experience" term="Developer Experience"/>
        <category label="Best Practices" term="Best Practices"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Letting AI Write Your FlowQuery — And Why You Still Need to Review It]]></title>
        <id>https://logicbee.ai/blog/letting-ai-write-your-flowquery</id>
        <link href="https://logicbee.ai/blog/letting-ai-write-your-flowquery"/>
        <updated>2025-12-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[AI can chain FlowQuery calls with impressive accuracy — until it silently drops a tenant scope or builds an unindexed aggregation pipeline. Here's how to catch the mistakes that compile but corrupt.]]></summary>
        <content type="html"><![CDATA[<p>AI can chain FlowQuery calls with impressive accuracy — until it silently drops a tenant scope or builds an unindexed aggregation pipeline. Here's how to catch the mistakes that compile but corrupt.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-premise">The Premise<a href="https://logicbee.ai/blog/letting-ai-write-your-flowquery#the-premise" class="hash-link" aria-label="Direct link to The Premise" title="Direct link to The Premise" translate="no">​</a></h2>
<p>FlowQuery is Logic Bee's chainable ORM for tenant-scoped database operations. Its fluent API reads like pseudocode, which makes it a dream for AI code generation. The problem? Syntactically correct FlowQuery can still be semantically dangerous.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-story">The Story<a href="https://logicbee.ai/blog/letting-ai-write-your-flowquery#the-story" class="hash-link" aria-label="Direct link to The Story" title="Direct link to The Story" translate="no">​</a></h2>
<p>A developer asks the AI to build a reporting hook that aggregates monthly revenue across all posted invoices. The AI generates clean, readable code:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> invoices </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> fc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">invoiceNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.status'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'posted'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getMany</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'FinanceInterface.Invoice'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>Looks perfect. But during code review, the developer catches three issues that would have gone unnoticed in a test environment.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="where-ai-flowquery-goes-wrong">Where AI FlowQuery Goes Wrong<a href="https://logicbee.ai/blog/letting-ai-write-your-flowquery#where-ai-flowquery-goes-wrong" class="hash-link" aria-label="Direct link to Where AI FlowQuery Goes Wrong" title="Direct link to Where AI FlowQuery Goes Wrong" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="1-missing-tenant-boundaries">1. Missing Tenant Boundaries<a href="https://logicbee.ai/blog/letting-ai-write-your-flowquery#1-missing-tenant-boundaries" class="hash-link" aria-label="Direct link to 1. Missing Tenant Boundaries" title="Direct link to 1. Missing Tenant Boundaries" translate="no">​</a></h3>
<p>The most critical mistake is also the quietest. When AI generates a helper function that internally creates a new FlowQuery chain, it sometimes forgets to pass the user context:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ AI-generated helper — no user scoping</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">getLineItems</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">fc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> docId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> fc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.parentId'</span><span class="token operator">:</span><span class="token plain"> docId </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)">// missing .user()</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getMany</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Corrected</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">async</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">getLineItems</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">fc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> docId</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> fc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)">// always scope to tenant</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">lineNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.parentId'</span><span class="token operator">:</span><span class="token plain"> docId </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getMany</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'FinanceInterface.InvoiceLine'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="2-fetching-too-much-data">2. Fetching Too Much Data<a href="https://logicbee.ai/blog/letting-ai-write-your-flowquery#2-fetching-too-much-data" class="hash-link" aria-label="Direct link to 2. Fetching Too Much Data" title="Direct link to 2. Fetching Too Much Data" translate="no">​</a></h3>
<p>AI tends to use <code>.getMany()</code> when <code>.getOne()</code> would suffice, or fetches full documents when only a few fields are needed. In production with thousands of documents, this matters:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ AI default: fetch everything</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> allOrders </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> fc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">orderNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.customerId'</span><span class="token operator">:</span><span class="token plain"> customerId </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getMany</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Better: limit and project</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> recentOrders </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> fc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">orderNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.customerId'</span><span class="token operator">:</span><span class="token plain"> customerId </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">sort</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.createdAt'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token operator">-</span><span class="token number">1</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">limit</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token number">10</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getMany</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'SalesInterface.Order'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="3-aggregation-pipeline-misuse">3. Aggregation Pipeline Misuse<a href="https://logicbee.ai/blog/letting-ai-write-your-flowquery#3-aggregation-pipeline-misuse" class="hash-link" aria-label="Direct link to 3. Aggregation Pipeline Misuse" title="Direct link to 3. Aggregation Pipeline Misuse" translate="no">​</a></h3>
<p>When asked to "sum" or "group" data, AI sometimes fetches all documents into memory and reduces in JavaScript instead of using database-level aggregation:</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ❌ AI approach: fetch-then-reduce</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> invoices </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> fc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token operator">...</span><span class="token function" style="color:rgb(80, 250, 123)">getMany</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> total </span><span class="token operator">=</span><span class="token plain"> invoices</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">reduce</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">sum</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> inv</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> sum </span><span class="token operator">+</span><span class="token plain"> inv</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">amount</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ Better: use the database</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> pipeline </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> $match</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.status'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'posted'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> $group</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> _id</span><span class="token operator">:</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">null</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> total</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> $sum</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'$data.amount'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-3-point-flowquery-review">The 3-Point FlowQuery Review<a href="https://logicbee.ai/blog/letting-ai-write-your-flowquery#the-3-point-flowquery-review" class="hash-link" aria-label="Direct link to The 3-Point FlowQuery Review" title="Direct link to The 3-Point FlowQuery Review" translate="no">​</a></h2>
<p>Every time you review AI-generated FlowQuery code, check these three things:</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="scoping">Scoping<a href="https://logicbee.ai/blog/letting-ai-write-your-flowquery#scoping" class="hash-link" aria-label="Direct link to Scoping" title="Direct link to Scoping" translate="no">​</a></h3>
<ul class="contains-task-list containsTaskList_QswE">
<li class="task-list-item"><input type="checkbox" disabled=""> <code>.user(bob.flowUser)</code> on every chain — including helper functions</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <code>.flowOptions(eventOptions.*)</code> matches the correct collection</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="performance">Performance<a href="https://logicbee.ai/blog/letting-ai-write-your-flowquery#performance" class="hash-link" aria-label="Direct link to Performance" title="Direct link to Performance" translate="no">​</a></h3>
<ul class="contains-task-list containsTaskList_QswE">
<li class="task-list-item"><input type="checkbox" disabled=""> <code>.getMany()</code> has appropriate limits or pagination</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Aggregations happen at the database level, not in JavaScript</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Queries use indexed fields</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="correctness">Correctness<a href="https://logicbee.ai/blog/letting-ai-write-your-flowquery#correctness" class="hash-link" aria-label="Direct link to Correctness" title="Direct link to Correctness" translate="no">​</a></h3>
<ul class="contains-task-list containsTaskList_QswE">
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->TypeScript interface passed to <code>.getMany(undefined, 'Interface.Type')</code> for type safety</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <code>.getOne()</code> used when only one document is expected</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Null checks after <code>.getOne()</code> calls</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-takeaway">The Takeaway<a href="https://logicbee.ai/blog/letting-ai-write-your-flowquery#the-takeaway" class="hash-link" aria-label="Direct link to The Takeaway" title="Direct link to The Takeaway" translate="no">​</a></h2>
<p>FlowQuery's fluent API makes AI-generated code look deceptively correct. The developer's job isn't to rewrite it — it's to verify the three dimensions the AI consistently underweights: <strong>tenant scoping</strong>, <strong>query performance</strong>, and <strong>data volume awareness</strong>.</p>
<p>Trust the syntax. Verify the semantics.</p>]]></content>
        <author>
            <name>Gabriel Paunescu</name>
            <uri>https://www.linkedin.com/in/gabrielpaunescu/</uri>
        </author>
        <category label="AI" term="AI"/>
        <category label="FlowQuery" term="FlowQuery"/>
        <category label="Best Practices" term="Best Practices"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[AI-Scaffolded Hooks: From Prompt to Production in 5 Minutes]]></title>
        <id>https://logicbee.ai/blog/ai-scaffolded-hooks</id>
        <link href="https://logicbee.ai/blog/ai-scaffolded-hooks"/>
        <updated>2025-12-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[What if creating a new business logic hook took 5 minutes instead of 45? With AI-assisted scaffolding in Logic Bee, it can — but only if you know what to verify before hitting merge.]]></summary>
        <content type="html"><![CDATA[<p>What if creating a new business logic hook took 5 minutes instead of 45? With AI-assisted scaffolding in Logic Bee, it can — but only if you know what to verify before hitting merge.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-premise">The Premise<a href="https://logicbee.ai/blog/ai-scaffolded-hooks#the-premise" class="hash-link" aria-label="Direct link to The Premise" title="Direct link to The Premise" translate="no">​</a></h2>
<p>Every Logic Bee hook follows the same anatomy: a <code>@LogicHook</code> decorator, a static <code>execute()</code> method, the Bob Wrapper pattern, and a <code>returnEventResult</code> call. That's a lot of boilerplate that's identical across hundreds of hooks — and boilerplate is exactly what AI excels at.</p>
<p>But scaffolding is only half the story. The other half is knowing what the AI cannot know: your business rules, your tenant boundaries, and the edge cases that live in your head.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-story">The Story<a href="https://logicbee.ai/blog/ai-scaffolded-hooks#the-story" class="hash-link" aria-label="Direct link to The Story" title="Direct link to The Story" translate="no">​</a></h2>
<p>A developer needs a new hook in the <code>finance-bills</code> library to calculate late fees on overdue invoices. Instead of copy-pasting from an existing hook, they open their AI agent and type:</p>
<blockquote>
<p><em>"Create a new hook in finance-bills that calculates late fees on overdue invoices. Skip bills with zero balance. Use the creating-hooks and flow-query skills."</em></p>
</blockquote>
<p>In under a minute, the AI:</p>
<ol>
<li class=""><strong>Runs the CLI</strong> — <code>npx tsx scripts/logic-bee-create-new-hook.ts</code> scaffolds the folder, <code>.hook.ts</code>, <code>hook.yml</code>, and <code>context.yaml</code></li>
<li class=""><strong>Searches for patterns</strong> — finds <code>calculate-bill</code> as a reference implementation</li>
<li class=""><strong>Writes the logic</strong> — generates a complete hook with FlowQuery chains, <code>naoDateTime()</code> comparisons, and <code>naoUtils.mathChain()</code> for fee calculations</li>
<li class=""><strong>Self-validates</strong> — checks all 10 hard rules and 12 soft conventions</li>
</ol>
<p>The developer has working code. But is it production-ready?</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="what-the-ai-gets-right">What the AI Gets Right<a href="https://logicbee.ai/blog/ai-scaffolded-hooks#what-the-ai-gets-right" class="hash-link" aria-label="Direct link to What the AI Gets Right" title="Direct link to What the AI Gets Right" translate="no">​</a></h2>
<p>The generated hook follows every structural convention perfectly:</p>
<ul>
<li class=""><strong>File path</strong>: <code>hooks/finance-bills/calculate-late-fees/calculate-late-fees.finance-bills.hook.ts</code></li>
<li class=""><strong>Decorator metadata</strong>: name, path, library, method — all correctly derived</li>
<li class=""><strong>Bob Wrapper</strong>: <code>let ok = true, error: any = null, data</code> → <code>try/catch</code> → <code>returnEventResult</code></li>
<li class=""><strong>Arrow comments</strong>: <code>// --&gt;Get:</code>, <code>// --&gt;Set:</code>, <code>// --&gt;Iterate:</code></li>
<li class=""><strong>Error handling</strong>: <code>naoFormatErrorById('bad_request', { reason: '...' })</code></li>
</ul>
<p>This is the 80% that would have taken a human 30 minutes to type.</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="what-you-need-to-verify">What You Need to Verify<a href="https://logicbee.ai/blog/ai-scaffolded-hooks#what-you-need-to-verify" class="hash-link" aria-label="Direct link to What You Need to Verify" title="Direct link to What You Need to Verify" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="1-tenant-scoping">1. Tenant Scoping<a href="https://logicbee.ai/blog/ai-scaffolded-hooks#1-tenant-scoping" class="hash-link" aria-label="Direct link to 1. Tenant Scoping" title="Direct link to 1. Tenant Scoping" translate="no">​</a></h3>
<p>Every FlowQuery chain must pass <code>bob.flowUser</code>. The AI almost always includes it, but a missing <code>.user(bob.flowUser)</code> means cross-tenant data leakage.</p>
<div class="language-typescript codeBlockContainer_G9Q3 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_KPzx"><pre tabindex="0" class="prism-code language-typescript codeBlock_X5zZ thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_IHTV"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">// ✅ AI usually generates this correctly</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> bills </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> fc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">bob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">flowUser</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)">// ← verify this exists on EVERY query</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">flowOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">eventOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">billNaoQueryOptions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token string-property property">'data.status'</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'posted'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">getMany</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'FinanceInterface.Bill'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="2-business-logic-accuracy">2. Business Logic Accuracy<a href="https://logicbee.ai/blog/ai-scaffolded-hooks#2-business-logic-accuracy" class="hash-link" aria-label="Direct link to 2. Business Logic Accuracy" title="Direct link to 2. Business Logic Accuracy" translate="no">​</a></h3>
<p>The AI calculated late fees as a flat percentage. Your business rule says it should be tiered: 1.5% for 1–30 days, 3% for 31–60 days, 5% for 60+. The AI doesn't know this unless you told it.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="3-transaction-session-usage">3. Transaction Session Usage<a href="https://logicbee.ai/blog/ai-scaffolded-hooks#3-transaction-session-usage" class="hash-link" aria-label="Direct link to 3. Transaction Session Usage" title="Direct link to 3. Transaction Session Usage" translate="no">​</a></h3>
<p>For hooks that update multiple documents, verify <code>bob.dbSession()</code> is passed to all write operations. The AI may omit it on some update calls, breaking atomicity.</p>
<h3 class="anchor anchorTargetStickyNavbar_oPUI" id="4-edge-cases">4. Edge Cases<a href="https://logicbee.ai/blog/ai-scaffolded-hooks#4-edge-cases" class="hash-link" aria-label="Direct link to 4. Edge Cases" title="Direct link to 4. Edge Cases" translate="no">​</a></h3>
<p>The prompt said "skip bills with zero balance," and the AI added a guard clause. But what about negative balances (credits)? What about bills in <code>draft</code> status?</p>
<h2 class="anchor anchorTargetStickyNavbar_oPUI" id="the-takeaway">The Takeaway<a href="https://logicbee.ai/blog/ai-scaffolded-hooks#the-takeaway" class="hash-link" aria-label="Direct link to The Takeaway" title="Direct link to The Takeaway" translate="no">​</a></h2>
<p>AI scaffolding eliminates the mechanical overhead of creating hooks. Here's your pre-merge checklist:</p>
<ul class="contains-task-list containsTaskList_QswE">
<li class="task-list-item"><input type="checkbox" disabled=""> <code>.user(bob.flowUser)</code> on every FlowQuery chain</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <code>bob.dbSession()</code> on every write operation</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Business logic matches actual requirements (not AI assumptions)</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <!-- -->Edge cases covered: nulls, zero values, unexpected statuses</li>
<li class="task-list-item"><input type="checkbox" disabled=""> <code>eventOptions</code> declared at the top of the try block</li>
</ul>
<p><strong>The rule of thumb</strong>: let the AI write the structure, but own the logic.</p>]]></content>
        <author>
            <name>Gabriel Paunescu</name>
            <uri>https://www.linkedin.com/in/gabrielpaunescu/</uri>
        </author>
        <category label="AI" term="AI"/>
        <category label="Hooks" term="Hooks"/>
        <category label="Developer Experience" term="Developer Experience"/>
    </entry>
</feed>