<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: BrewHubPHL</title>
    <description>The latest articles on DEV Community by BrewHubPHL (@brewhubphl).</description>
    <link>https://dev.to/brewhubphl</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3756619%2F01432a8f-bd68-42b0-8007-0f67161c36cb.png</url>
      <title>DEV Community: BrewHubPHL</title>
      <link>https://dev.to/brewhubphl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/brewhubphl"/>
    <language>en</language>
    <item>
      <title>BrewHub PHL: Low Latency, High Caffeine (Notion MCP Operations Ledger)</title>
      <dc:creator>BrewHubPHL</dc:creator>
      <pubDate>Thu, 05 Mar 2026 04:08:14 +0000</pubDate>
      <link>https://dev.to/brewhubphl/brewhub-phl-low-latency-high-caffeine-notion-mcp-operations-ledger-27o1</link>
      <guid>https://dev.to/brewhubphl/brewhub-phl-low-latency-high-caffeine-notion-mcp-operations-ledger-27o1</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/notion-2026-03-04"&gt;Notion MCP Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;## What I Built&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&amp;lt;BrewHubPHL.com isn't just a software project; it's the digital infrastructure for a physical neighborhood coffee and parcel logistics shop. Managing a physical retail space requires strict security, fast transactions, and immutable audit logs. But reading database tables isn't a great experience for human store managers.&lt;/p&gt;

&lt;p&gt;To bridge the gap between our high-speed PostgreSQL database and our human management team, I built the Hub-to-Notion Operations Ledger.&lt;/p&gt;

&lt;p&gt;Whenever a barista completes an order on the POS, or a manager performs a high-security action (like an IRS-compliant payroll override), our database automatically and securely syncs that canonical data directly into a Notion Workspace. This turns Notion into a "Live Manager's Logbook" that updates in real-time, without any manual data entry.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;## Show us the code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&amp;lt;The magic happens through a highly secure, zero-trust architecture between Supabase, Netlify Functions, and Notion.&lt;/p&gt;

&lt;p&gt;Instead of trusting the payload from the database trigger, our Netlify function acts as a secure bridge that re-fetches the canonical data. We also built-in Graceful Degradation: if the Notion API ever goes down, the database catches the exception and returns NEW, ensuring we never stop selling coffee just because a sync failed.&lt;/p&gt;

&lt;p&gt;Here is a snippet of our Double-Guarded Postgres Trigger for Auto-Syncing completed orders: &lt;br&gt;
-- 20260304_schema86b_orders_notion_sync.sql&lt;br&gt;
CREATE OR REPLACE FUNCTION public.fn_trg_orders_notion_sync()&lt;br&gt;
RETURNS trigger&lt;br&gt;
LANGUAGE plpgsql&lt;br&gt;
SECURITY DEFINER SET search_path = public, extensions&lt;br&gt;
AS $$&lt;br&gt;
BEGIN&lt;br&gt;
  -- Defense-in-depth guard: Only fire on transition to 'completed'&lt;br&gt;
  IF (NEW.status = 'completed') AND (OLD.status IS DISTINCT FROM 'completed') THEN&lt;br&gt;
    BEGIN&lt;br&gt;
      -- Fire webhook to Netlify with signed headers and ONLY the record_id&lt;br&gt;
      PERFORM net.http_post(&lt;br&gt;
          url := coalesce(current_setting('app.settings.notion_sync_webhook_url', true), '&lt;a href="https://brewhubphl.com/.netlify/functions/notion-sync'" rel="noopener noreferrer"&gt;https://brewhubphl.com/.netlify/functions/notion-sync'&lt;/a&gt;),&lt;br&gt;
          headers := jsonb_build_object(&lt;br&gt;
              'Content-Type', 'application/json',&lt;br&gt;
              'X-BrewHub-Action', 'true',&lt;br&gt;
              'x-brewhub-secret', current_setting('app.settings.internal_sync_secret', true)&lt;br&gt;
          ),&lt;br&gt;
          body := jsonb_build_object('table', 'orders', 'record_id', NEW.id, 'type', 'UPDATE')&lt;br&gt;
      );&lt;br&gt;
    EXCEPTION WHEN undefined_function THEN&lt;br&gt;
      RAISE WARNING 'pg_net missing, skipping Notion sync';&lt;br&gt;
    WHEN OTHERS THEN&lt;br&gt;
      RAISE WARNING 'Notion sync trigger failed, but allowing order to complete: %', SQLERRM;&lt;br&gt;
    END;&lt;br&gt;
  END IF;&lt;br&gt;
  RETURN NEW;&lt;br&gt;
END;&lt;br&gt;
$$;&lt;/p&gt;

&lt;p&gt;CREATE TRIGGER trg_orders_notion_sync&lt;br&gt;
  AFTER UPDATE ON public.orders&lt;br&gt;
  FOR EACH ROW&lt;br&gt;
  -- Double guard: Postgres level check before invoking function&lt;br&gt;
  WHEN (NEW.status = 'completed' AND OLD.status IS DISTINCT FROM 'completed')&lt;br&gt;
  EXECUTE FUNCTION public.fn_trg_orders_notion_sync();&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;## How I Used Notion MCP&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&amp;lt;While the Postgres triggers and Netlify functions populate the data, Notion MCP (Model Context Protocol) acts as our "AI Shift Manager."&lt;/p&gt;

&lt;p&gt;By adding the Notion MCP server to our .vscode/mcp.json configuration, our AI concierge ("Elise", powered by Claude) has direct read/write access to the Shop Command Center in Notion.&lt;/p&gt;

&lt;p&gt;This unlocks an incredible Human-in-the-Loop workflow:&lt;/p&gt;

&lt;p&gt;The Daily Pulse: I can ask the AI to "Check the Ledger." The AI uses MCP to read the Sales Ledger database in Notion, summarizes the total revenue and completed orders for the day, and cross-references it with our physical parcel logistics.&lt;/p&gt;

&lt;p&gt;Security Audits: The AI scans the Audit Trail page in Notion for any new Manager Overrides (synced via our zero-trust webhooks). If it sees an unusual comp or payroll adjustment, it flags it for my review.&lt;/p&gt;

&lt;p&gt;Drafting Briefings: Instead of just outputting text, the AI uses MCP to draft a neat "Morning Briefing" page directly inside my Notion workspace for the opening manager to read the next day.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>notionchallenge</category>
      <category>mcp</category>
      <category>ai</category>
    </item>
    <item>
      <title>I built an Infinite AI Debate Arena using the GitHub Copilot CLI 🥊</title>
      <dc:creator>BrewHubPHL</dc:creator>
      <pubDate>Wed, 11 Feb 2026 19:29:41 +0000</pubDate>
      <link>https://dev.to/brewhubphl/i-built-an-infinite-ai-debate-arena-using-the-github-copilot-cli-421l</link>
      <guid>https://dev.to/brewhubphl/i-built-an-infinite-ai-debate-arena-using-the-github-copilot-cli-421l</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github-2026-01-21"&gt;GitHub Copilot CLI Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;💡 The Idea&lt;br&gt;
What happens if you lock two AI personalities in a room and force them to argue about "Is a hotdog a sandwich?" forever?&lt;/p&gt;

&lt;p&gt;For the GitHub Copilot CLI Challenge, I didn't want to just build a utility tool. I wanted to build something chaotic. Enter the AI Debate Arena.&lt;/p&gt;

&lt;p&gt;It’s a terminal-based "fighting game" where:&lt;/p&gt;

&lt;p&gt;Captain Capslock (An angry Boomer) fights Lil' Zoomer (A Gen-Z teen).&lt;/p&gt;

&lt;p&gt;They argue in an infinite loop.&lt;/p&gt;

&lt;p&gt;Sentiment Analysis determines who is "winning" (getting angrier).&lt;/p&gt;

&lt;p&gt;🎥 The Demo&lt;br&gt;
[&lt;a href="https://youtu.be/-RBdUKZY9zA" rel="noopener noreferrer"&gt;https://youtu.be/-RBdUKZY9zA&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;🛠️ How it Works&lt;br&gt;
The project uses Python to orchestrate the chaos, but the "brains" are entirely powered by the GitHub Copilot CLI.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The "Persona Injection"
I used the gh copilot explain command to generate the dialogue. By injecting a specific persona into the prompt, we can force Copilot to break character.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Python&lt;/p&gt;

&lt;h1&gt;
  
  
  The Secret Sauce
&lt;/h1&gt;

&lt;p&gt;prompt = f"{persona} Your opponent said: '{last_response}'. Reply in one short, funny sentence."&lt;br&gt;
cmd = ["gh", "copilot", "explain", "-p", prompt]&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Loop
The script creates a feedback loop:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fighter A generates a response using Copilot.&lt;/p&gt;

&lt;p&gt;TextBlob analyzes the sentiment (Politeness = Weakness, Anger = Power).&lt;/p&gt;

&lt;p&gt;Fighter B takes that response and generates a counter-argument.&lt;/p&gt;

&lt;p&gt;Rich renders the ASCII faces and health bars in real-time.&lt;/p&gt;

&lt;p&gt;🎨 The Tech Stack&lt;br&gt;
GitHub CLI (gh): The AI engine.&lt;/p&gt;

&lt;p&gt;Rich: For the beautiful terminal UI and layouts.&lt;/p&gt;

&lt;p&gt;TextBlob: For the "Rage Meter" logic.&lt;/p&gt;

&lt;p&gt;Python: To glue it all together.&lt;/p&gt;

&lt;p&gt;🏆 The Outcome&lt;br&gt;
Sometimes they argue about politics, sometimes about cereal. The CLI handles the roleplay surprisingly well. My favorite line so far?&lt;/p&gt;

&lt;p&gt;"Milk-first people stay taking Ls fr fr, that's giving unhinged villain energy." — Lil' Zoomer&lt;/p&gt;

&lt;p&gt;🔗 The Code&lt;br&gt;
Check out the repository here to run it yourself! [&lt;a href="https://github.com/BrewHubPHL/ai-debate.git" rel="noopener noreferrer"&gt;https://github.com/BrewHubPHL/ai-debate.git&lt;/a&gt;]&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>cli</category>
      <category>githubcopilot</category>
    </item>
    <item>
      <title>How I Built an AI Barista using Square, Supabase, and ElevenLabs</title>
      <dc:creator>BrewHubPHL</dc:creator>
      <pubDate>Fri, 06 Feb 2026 12:28:28 +0000</pubDate>
      <link>https://dev.to/brewhubphl/how-i-built-an-ai-barista-using-square-supabase-and-elevenlabs-3hbb</link>
      <guid>https://dev.to/brewhubphl/how-i-built-an-ai-barista-using-square-supabase-and-elevenlabs-3hbb</guid>
      <description>&lt;h1&gt;
  
  
  How I Built an AI Barista using Square, Supabase, and ElevenLabs
&lt;/h1&gt;

&lt;p&gt;I run a tech-forward coffee hub in Philadelphia called &lt;strong&gt;&lt;a href="https://brewhubphl.com" rel="noopener noreferrer"&gt;BrewHubPHL&lt;/a&gt;&lt;/strong&gt;. When we opened, I didn't just want a screen flashing "Order Ready"—I wanted the shop to speak.&lt;/p&gt;

&lt;p&gt;Here is how I used &lt;strong&gt;Supabase Edge Functions&lt;/strong&gt; to glue &lt;strong&gt;Square POS&lt;/strong&gt; and &lt;strong&gt;ElevenLabs&lt;/strong&gt; together, creating an automated announcer for our orders.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Database &amp;amp; Auth:&lt;/strong&gt; &lt;a href="https://supabase.com" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payments:&lt;/strong&gt; Square (POS and Webhooks)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Voice AI:&lt;/strong&gt; ElevenLabs (Turbo v2 model)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compute:&lt;/strong&gt; Netlify Functions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Workflow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Square&lt;/strong&gt; detects a payment (&lt;code&gt;payment.updated&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Supabase&lt;/strong&gt; receives the webhook and routes it.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;ElevenLabs&lt;/strong&gt; generates the audio file ("Order for John is ready!").&lt;/li&gt;
&lt;li&gt; The frontend plays the audio automatically.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 1: Catching the Square Webhook
&lt;/h2&gt;

&lt;p&gt;First, we need to know when an order is actually paid. We set up a serverless function to listen for Square's &lt;code&gt;payment.updated&lt;/code&gt; event.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
javascript
// square-webhook.js
exports.handler = async (event) =&amp;gt; {
  const body = JSON.parse(event.body);

  if (body.type === 'payment.updated' &amp;amp;&amp;amp; body.data.object.payment.status === 'COMPLETED') {
    const orderId = body.data.object.payment.reference_id;

    // Update Supabase
    await supabase.from('orders').update({ status: 'paid' }).eq('id', orderId);

    // Trigger the Announcer
    await triggerVoiceAnnouncement(orderId);
  }
};

## Step 2: Generating the Voice
This is where the magic happens. We don't want a robotic "text-to-speech" voice; we want personality. I used the ElevenLabs Turbo v2 model because it has low latency (essential for real-time retail).

We send the text to their API and get back an audio buffer.

// text-to-speech.js
const response = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${VOICE_ID}`, {
    method: 'POST',
    headers: {
        'xi-api-key': process.env.ELEVENLABS_API_KEY
    },
    body: JSON.stringify({
        text: "Order ready for specific_customer!",
        model_id: 'eleven_turbo_v2',
        voice_settings: { stability: 0.5, similarity_boost: 0.75 }
    })
});

Why build this?
It’s not just a gimmick. In a busy shop, customers tune out shouting baristas. A distinct, consistent AI voice cuts through the noise. Plus, by integrating it directly with Square and Supabase, we have zero manual work—the barista just taps "Charge," and the code does the rest.

For the developers, I've open-sourced the sync logic on GitHub: https://gist.github.com/BrewHubPHL/53937283c5eaa7cafedb9555e851c509
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>supabase</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
