<?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>Forem: devin nicholson</title>
    <description>The latest articles on Forem by devin nicholson (@devinnicholson).</description>
    <link>https://forem.com/devinnicholson</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%2F3349434%2Fa4f1701e-51bf-4eb2-8c8e-ba67bc2b25d2.jpeg</url>
      <title>Forem: devin nicholson</title>
      <link>https://forem.com/devinnicholson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/devinnicholson"/>
    <language>en</language>
    <item>
      <title>VitalSense: Real-Time Patient Triage on Redis (Streams • Search • JSON • TimeSeries)</title>
      <dc:creator>devin nicholson</dc:creator>
      <pubDate>Mon, 11 Aug 2025 05:18:30 +0000</pubDate>
      <link>https://forem.com/devinnicholson/vitalsense-real-time-patient-triage-on-redis-streams-search-json-timeseries-3eem</link>
      <guid>https://forem.com/devinnicholson/vitalsense-real-time-patient-triage-on-redis-streams-search-json-timeseries-3eem</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/redis-2025-07-23"&gt;Redis AI Challenge&lt;/a&gt;: Beyond the Cache&lt;/em&gt;.&lt;/p&gt;

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

&lt;p&gt;A real-time patient triage dashboard that uses Redis 8 as the primary data platform. It ingests vitals (HR/SpO₂/BP) via Redis Streams, persists the latest state per patient in Hashes, indexes snapshots with RediSearch for instant querying, publishes alerts with Pub/Sub, stores adjustable alert thresholds in RedisJSON, and renders 24-hour trends from RedisTimeSeries. The React/Next.js UI is real-time (WebSocket), offline-first (IndexedDB hydration), supports threshold configuration (persisted in Redis), and provides a drill-down panel with a per-patient sparkline (via TS.RANGE).&lt;/p&gt;

&lt;p&gt;Key properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Primary DB: No external database; Redis is the system of record for runtime state + settings.&lt;/li&gt;
&lt;li&gt;Search &amp;amp; Rules: RediSearch powers numeric queries for “critical” patients (low SpO₂ / high HR), pulled by a watcher that publishes alerts.&lt;/li&gt;
&lt;li&gt;Streams + Pub/Sub: Streams for ingestion/fan-out; Pub/Sub for real-time alert fan-out to the browser.&lt;/li&gt;
&lt;li&gt;Time series: Per-patient SpO₂ time series with 24h retention for drill-down trends.&lt;/li&gt;
&lt;li&gt;UX: Progressive skeletons, dark mode, drill-down, offline cache, threshold modal (live-reconfigures the watcher).&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Github: &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/devinnicholson" rel="noopener noreferrer"&gt;
        devinnicholson
      &lt;/a&gt; / &lt;a href="https://github.com/devinnicholson/vitalsense" rel="noopener noreferrer"&gt;
        vitalsense
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;VitalSense Hackathon Project&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A real-time health data pipeline using Redis Streams, RedisJSON, RediSearch
Pub/Sub, and a beautiful Tailwind/Next.js dashboard.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Prerequisites&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Node.js&lt;/strong&gt; v16+&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Redis 8&lt;/strong&gt; instance with modules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RedisJSON&lt;/li&gt;
&lt;li&gt;Redis Streams&lt;/li&gt;
&lt;li&gt;RediSearch&lt;/li&gt;
&lt;li&gt;(Optional) RedisAI&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Environment variable&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;export&lt;/span&gt; REDIS_URL=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;redis://default:&amp;lt;PASSWORD&amp;gt;@&amp;lt;HOST&amp;gt;:&amp;lt;PORT&amp;gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;1. Vitals Generator&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Emits synthetic patient vitals into &lt;code&gt;patients:stream&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;cd&lt;/span&gt; vital-sense-generator
npm install
npm start&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;You’ll see logs like:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;Emitted &amp;lt;streamId&amp;gt; { patientId: 'P01', hr: 82, spo2: 95, sys: 120, dia: 80 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;2. Stream Consumer&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Reads from &lt;code&gt;patients:stream&lt;/code&gt;, writes snapshots to &lt;code&gt;patient:&amp;lt;ID&amp;gt;:snapshot&lt;/code&gt;, and
acknowledges.&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;cd&lt;/span&gt; vital-sense-consumer
npm install
npm start&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;You’ll see:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;✔ Consumer group "consumer-group" created on "patients:stream"
▶ Listening for new entries…
🗂 Got 1 msg(s) from stream "patients:stream"
✅ Processed &amp;lt;streamId&amp;gt; → patient:P01:snapshot { hr: '82', spo2: '95', sys: '120', dia: '80' }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;3. Index Creation (RediSearch)&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Drop &amp;amp; recreate the snapshots index to cover all &lt;code&gt;patient:*:snapshot&lt;/code&gt; keys.&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; in vital-sense-consumer/&lt;/span&gt;
npm run&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/devinnicholson/vitalsense" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;
Demo: &lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://drive.google.com/file/d/1tSQ_JCx7IM7SQP_48MLai7a1zhZEboq9/view?usp=sharing" rel="noopener noreferrer" class="c-link"&gt;
            vitalsense.mov - Google Drive
          &lt;/a&gt;
        &lt;/h2&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fssl.gstatic.com%2Fimages%2Fbranding%2Fproduct%2F1x%2Fdrive_2020q4_32dp.png"&gt;
          drive.google.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fskx1z0iwkd0ruop8wxw0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fskx1z0iwkd0ruop8wxw0.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7h84zcd3bxmda0qhap6x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7h84zcd3bxmda0qhap6x.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fplw1u79emg483ynpsqkw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fplw1u79emg483ynpsqkw.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5r3bnz7wp56q31n1nu48.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5r3bnz7wp56q31n1nu48.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Used Redis 8
&lt;/h2&gt;

&lt;p&gt;Data ingestion (Streams)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;XADD patients:stream * id P01 heart_rate 82 spo2 95 bp_systolic 120 bp_diastolic 80&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Consumer group (&lt;code&gt;XGROUP CREATE / XREADGROUP&lt;/code&gt;) provides reliable processing and back-pressure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Primary state (Hashes)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Latest snapshot per patient in Hash:&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HSET patient:P01:snapshot hr 82 spo2 95 sys 120 dia 80 timestamp &amp;lt;iso&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No external DB; Redis holds the live source of truth.&lt;/p&gt;

&lt;p&gt;Indexed queries (RediSearch)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FT.CREATE idx:snapshots ON HASH PREFIX 1 "patient:" SCHEMA hr NUMERIC SORTABLE spo2 NUMERIC SORTABLE sys NUMERIC dia NUMERIC timestamp TAG&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Query examples used by the watcher/UI:&lt;/li&gt;
&lt;li&gt;Low oxygen: &lt;code&gt;@spo2:[-inf 92]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;High HR: &lt;code&gt;@hr:[120 +inf]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Combined: &lt;code&gt;(@spo2:[-inf 92]) | (@hr:[120 +inf])&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Event fan-out (Pub/Sub)&lt;/li&gt;
&lt;li&gt;Watcher runs a periodic RediSearch query, publishes critical hits to alerts:critical.&lt;/li&gt;
&lt;li&gt;A Node WS proxy subscribes and forwards JSON to browser WebSockets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Time series analytics (RedisTimeSeries)&lt;/p&gt;

&lt;p&gt;Per-patient SpO₂:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TS.CREATE ts:patient:Pxx:spo2 RETENTION 86400000 LABELS patient Pxx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TS.ADD ts:patient:Pxx:spo2 &amp;lt;ts&amp;gt; &amp;lt;spo2&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Drill-down: &lt;code&gt;TS.RANGE ts:patient:Pxx:spo2 &amp;lt;now-24h&amp;gt; &amp;lt;now&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Dynamic configuration (RedisJSON)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alert thresholds live in JSON:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;JSON.SET settings:thresholds . '{"spo2":92,"hr":100}'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Next API &lt;code&gt;GET/PATCH /api/settings/thresholds&lt;/code&gt; reads/writes this key.&lt;/li&gt;
&lt;li&gt;Watcher reloads thresholds each loop → instant effect.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Team Submissions: &lt;br&gt;
Devin Nicholson&lt;/p&gt;

</description>
      <category>redischallenge</category>
      <category>devchallenge</category>
      <category>database</category>
      <category>ai</category>
    </item>
    <item>
      <title>EmberAI: Algolia MCP Server Challenge</title>
      <dc:creator>devin nicholson</dc:creator>
      <pubDate>Mon, 28 Jul 2025 06:50:39 +0000</pubDate>
      <link>https://forem.com/devinnicholson/emberai-algolia-mcp-server-challenge-38pm</link>
      <guid>https://forem.com/devinnicholson/emberai-algolia-mcp-server-challenge-38pm</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/algolia-2025-07-09"&gt;Algolia MCP Server Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;An open‑source, AI‑powered mapping dashboard for tracking wildfires and shelter locations in real time.&lt;/p&gt;

&lt;p&gt;EmberAI combines lightning‑fast search with meaningful AI insights to equip communities, first responders, and volunteers with the information they need to act quickly during fire emergencies.&lt;/p&gt;

&lt;p&gt;🚀 Key Features&lt;br&gt;
Geo‑Aware Search with Algolia MCP&lt;/p&gt;

&lt;p&gt;Unified proxy for multiple indices (fires, shelters, aqi).&lt;br&gt;
Instant insideBoundingBox filtering for map viewport queries.&lt;br&gt;
High‑performance faceting (e.g. severity:4+, state:CA).&lt;br&gt;
AI Enrichment via n8n Workflows&lt;/p&gt;

&lt;p&gt;Fire Severity Classification: Automated LLM calls convert raw satellite data into a 1–5 urgency score and one‑sentence summary.&lt;br&gt;
Shelter Capacity Forecasting: Time‑series API + LLM or ARIMA predicts near‑future capacity risks (boolean flag).&lt;br&gt;
Modular workflows in n8n, no additional server code required.&lt;br&gt;
Real‑Time Data Ingestion&lt;/p&gt;

&lt;p&gt;MODIS / VIIRS fire data from NASA FIRMS (7‑day CSV feeds).&lt;br&gt;
FEMA shelter locations via open data API.&lt;br&gt;
Optional Air Quality Index (AQI) from AirNow.&lt;br&gt;
Secure, batch indexing into Algolia with a Python pipeline (update_indices.py).&lt;br&gt;
Interactive Map UI&lt;/p&gt;

&lt;p&gt;React + Leaflet front‑end with colored circle markers: scale up severity from green→purple.&lt;br&gt;
Popups display date, confidence, AI summary, and capacity forecasts.&lt;br&gt;
Search bar for date, confidence, and full‑text queries.&lt;br&gt;
Responsive design for desktop and tablet use.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/devinnicholson" rel="noopener noreferrer"&gt;
        devinnicholson
      &lt;/a&gt; / &lt;a href="https://github.com/devinnicholson/emberAI" rel="noopener noreferrer"&gt;
        emberAI
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;EmberAI&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;An open‑source, AI‑powered mapping dashboard for tracking wildfires and shelter
locations in real time.&lt;/p&gt;
&lt;p&gt;EmberAI combines lightning‑fast search with meaningful AI insights to equip
communities, first responders, and volunteers with the information they need to
act quickly during fire emergencies.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚀 Key Features&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Geo‑Aware Search with Algolia MCP&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unified proxy for multiple indices (&lt;code&gt;fires&lt;/code&gt;, &lt;code&gt;shelters&lt;/code&gt;, &lt;code&gt;aqi&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Instant &lt;strong&gt;insideBoundingBox&lt;/strong&gt; filtering for map viewport queries.&lt;/li&gt;
&lt;li&gt;High‑performance faceting (e.g. &lt;code&gt;severity:4+&lt;/code&gt;, &lt;code&gt;state:CA&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;AI Enrichment via n8n Workflows&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fire Severity Classification&lt;/strong&gt;: Automated LLM calls convert raw satellite
data into a 1–5 urgency score and one‑sentence summary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shelter Capacity Forecasting&lt;/strong&gt;: Time‑series API + LLM or ARIMA predicts
near‑future capacity risks (boolean flag).&lt;/li&gt;
&lt;li&gt;Modular workflows in n8n, no additional server code required.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Real‑Time Data Ingestion&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MODIS / VIIRS&lt;/strong&gt; fire data from NASA FIRMS (7‑day CSV feeds).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FEMA&lt;/strong&gt; shelter locations via open data API.&lt;/li&gt;
&lt;li&gt;Optional &lt;strong&gt;Air Quality Index (AQI)&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/devinnicholson/emberAI" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://drive.google.com/file/d/15_zrdsIvDyFeaNjLbLJrZVluVqevZm6C/view?usp=sharing" rel="noopener noreferrer"&gt;https://drive.google.com/file/d/15_zrdsIvDyFeaNjLbLJrZVluVqevZm6C/view?usp=sharing&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Utilized the Algolia MCP Server
&lt;/h2&gt;

&lt;p&gt;Unified proxy for multiple indices (fires, shelters, aqi).&lt;br&gt;
Instant insideBoundingBox filtering for map viewport queries.&lt;br&gt;
High‑performance faceting (e.g. severity:4+, state:CA).&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;Over the past few weeks I built EmberAI end‑to‑end. I started with a Python pipeline to pull in 7‑day fire data from NASA FIRMS and shelter locations from FEMA, then batch‑indexing everything into Algolia through the MCP proxy. I ran into CORS and scaling issues when trying to serve search requests directly, so I introduced Algolia’s MCP Server to unify multiple indices and handle geo‑filtered queries in under 100 ms.&lt;/p&gt;

&lt;p&gt;Including AI enrichment in n8n was both powerful and tricky. I had to batch millions of fire records into a single webhook call to avoid hours‑long loops, and design LLM prompts that reliably output a 1–5 severity score plus a concise human summary. Integrating these Webhook→HTTP Request→partialUpdateObject steps taught me how to version workflows as code and keep everything reproducible.&lt;/p&gt;

&lt;p&gt;On the UI side, I used React and Leaflet to visualize severity colored markers alongside shelter capacity forecasts, and refined the UX. I had fun UI issues where I needed to keep moving the search bar out of the way of map controls. Also spent time ensuring every marker displays fallback values if AI enrichment isn’t yet available. Throughout the project I learned the importance of batching over per‑record requests, the flexibility of n8n for no server AI workflows, and how Algolia MCP can turn large, fast‑moving datasets into a truly interactive, life‑saving search experience.&lt;/p&gt;

&lt;p&gt;Team Submissions: Devin Nicholson&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>algoliachallenge</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
