<?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: Long Phan</title>
    <description>The latest articles on DEV Community by Long Phan (@minhlong2605).</description>
    <link>https://dev.to/minhlong2605</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%2F2947620%2F2c8c64b1-7170-4a87-ad81-7a303be9f437.gif</url>
      <title>DEV Community: Long Phan</title>
      <link>https://dev.to/minhlong2605</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/minhlong2605"/>
    <language>en</language>
    <item>
      <title>🚀LeadPilot – Your AI Staff Engineer in the Terminal</title>
      <dc:creator>Long Phan</dc:creator>
      <pubDate>Mon, 16 Feb 2026 07:57:18 +0000</pubDate>
      <link>https://dev.to/minhlong2605/ai-technical-lead-1o6b</link>
      <guid>https://dev.to/minhlong2605/ai-technical-lead-1o6b</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;&lt;strong&gt;Tagline:&lt;/strong&gt;&lt;br&gt;
“Because not everyone has a Staff Engineer reviewing their PR at 2AM.”&lt;/p&gt;
&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;LeadPilot&lt;/strong&gt; is a tiny CLI that turns your local &lt;code&gt;git diff&lt;/code&gt; into an actionable code review using &lt;strong&gt;GitHub Copilot CLI&lt;/strong&gt;-right from your terminal.&lt;/p&gt;

&lt;p&gt;Instead of waiting for PR reviews (or context-switching to a web UI), I wanted something I can run &lt;strong&gt;immediately while coding&lt;/strong&gt;-especially for quick “sanity checks” before committing, pushing, or opening a PR.&lt;/p&gt;
&lt;h3&gt;
  
  
  What it does
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One command&lt;/strong&gt;: &lt;code&gt;leadpilot review&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two review personas&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Startup CTO Review&lt;/strong&gt; (default): pragmatic, shipping-focused, highlights the biggest risk + one improvement&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FAANG Staff Engineer Review&lt;/strong&gt;: stricter, architecture/scalability oriented, includes score + approval decision&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Branch-aware diffs&lt;/strong&gt;: compare against any git ref via &lt;code&gt;--branch&lt;/code&gt; (e.g. &lt;code&gt;--branch master&lt;/code&gt;, &lt;code&gt;--branch origin/main&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terminal-friendly output&lt;/strong&gt;: clean, boxed formatting that’s easy to skim&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’ve ever thought “I wish a senior engineer could look at this real quick”… LeadPilot is that, on-demand.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why I built it
&lt;/h3&gt;

&lt;p&gt;Code reviews are amazing… when you can get them.&lt;/p&gt;

&lt;p&gt;But in real life:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You might be working solo, late at night, or in a small team.&lt;/li&gt;
&lt;li&gt;Your teammate might be asleep (or in meetings) when you’re about to ship.&lt;/li&gt;
&lt;li&gt;Sometimes you don’t need a full PR discussion-you just want a quick, high-signal check.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;LeadPilot is designed for that moment: &lt;strong&gt;fast feedback, in the terminal, on the diff you’re already looking at&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  How it works (high-level)
&lt;/h3&gt;

&lt;p&gt;LeadPilot keeps the workflow intentionally simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It computes the diff you care about using &lt;code&gt;git diff &amp;lt;branch&amp;gt;&lt;/code&gt; (default &lt;code&gt;origin/main&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;It wraps that diff in a prompt tailored to the persona you chose (&lt;code&gt;startup&lt;/code&gt; or &lt;code&gt;faang&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;It asks GitHub Copilot CLI to review it via the &lt;code&gt;copilot&lt;/code&gt; command (prompt-in, review-out).&lt;/li&gt;
&lt;li&gt;It prints the result in a clean, boxed format so you can skim it quickly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach makes it easy to use in any repo without extra setup beyond having &lt;code&gt;git&lt;/code&gt; + &lt;code&gt;copilot&lt;/code&gt; available.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/longphanquangminh/leadpilot" rel="noopener noreferrer"&gt;https://github.com/longphanquangminh/leadpilot&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Quick start (global install)
&lt;/h3&gt;

&lt;p&gt;From the LeadPilot repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Suggested walkthrough
&lt;/h3&gt;

&lt;p&gt;1/ Open any git repository.&lt;br&gt;
2/ Make a small change (uncommitted is fine).&lt;br&gt;
3/ Run a pragmatic review against &lt;code&gt;master&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;leadpilot review &lt;span class="nt"&gt;--branch&lt;/span&gt; master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4/ Flip personas to get a stricter review:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;leadpilot review &lt;span class="nt"&gt;--mode&lt;/span&gt; faang &lt;span class="nt"&gt;--branch&lt;/span&gt; master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5/ Show the boxed output and discuss whether you’d “ship it” or iterate.&lt;/p&gt;

&lt;h3&gt;
  
  
  What you guys should do in your trials
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A diff that’s ~10–100 lines (enough to be interesting, small enough to review live)&lt;/li&gt;
&lt;li&gt;The Startup CTO output (biggest risk + one improvement)&lt;/li&gt;
&lt;li&gt;The FAANG output (score + approval decision)&lt;/li&gt;
&lt;li&gt;A quick branch switch (&lt;code&gt;--branch origin/main&lt;/code&gt; vs &lt;code&gt;--branch master&lt;/code&gt;) to show it’s flexible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Screenshots:&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%2Fi6mbw5v39x2gm6g07nm3.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%2Fi6mbw5v39x2gm6g07nm3.png" alt="Demo1" width="800" height="423"&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%2Fj056b8vi2rnu4qoikx34.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%2Fj056b8vi2rnu4qoikx34.png" alt="Demo2" width="800" height="295"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Experience with GitHub Copilot CLI
&lt;/h2&gt;

&lt;p&gt;GitHub Copilot CLI was my “pair reviewer” while building LeadPilot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It helped me &lt;strong&gt;iterate fast on prompts&lt;/strong&gt; so each persona produces consistent, scannable sections (instead of a wall of text).&lt;/li&gt;
&lt;li&gt;It was great for &lt;strong&gt;UX pressure-testing&lt;/strong&gt;: what output is actually actionable in a terminal (and what’s just noise).&lt;/li&gt;
&lt;li&gt;It made it easy to &lt;strong&gt;loop on edge cases&lt;/strong&gt; (no diff, wrong refs, setup issues) because everything stays in the command line.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I liked most is how natural it felt to keep everything in the terminal: edit → diff → review → refine.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Constraints create clarity&lt;/strong&gt;: forcing the Startup CTO persona to return “ship decision + biggest risk + one improvement” makes the review immediately usable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Different personas are surprisingly helpful&lt;/strong&gt;: the strict mode is great for architecture/design issues; the startup mode is great for “what could blow up in production tomorrow”.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terminal output matters&lt;/strong&gt;: boxing + consistent headings makes it feel like a real tool, not just AI text pasted into your console.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What I’d improve next
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Async reviews&lt;/strong&gt; for very large diffs or slower machines (queue the job, stream output, or provide a progress indicator).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More modes&lt;/strong&gt; (e.g., “Security reviewer”, “Performance reviewer”, “DX reviewer”) while keeping outputs structured.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context knobs&lt;/strong&gt; (optionally include commit messages, file paths only, or a summary first).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>cli</category>
      <category>githubcopilot</category>
    </item>
    <item>
      <title>🚀 Copilot CLI Plugin Marketplace - AI-Powered Productivity Hub</title>
      <dc:creator>Long Phan</dc:creator>
      <pubDate>Mon, 16 Feb 2026 07:50:02 +0000</pubDate>
      <link>https://dev.to/minhlong2605/copilot-cli-plugin-marketplace-ai-powered-productivity-hub-2am8</link>
      <guid>https://dev.to/minhlong2605/copilot-cli-plugin-marketplace-ai-powered-productivity-hub-2am8</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;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I created a &lt;strong&gt;production-ready web application&lt;/strong&gt; that transforms GitHub Copilot CLI into an accessible, user-friendly marketplace of AI-powered plugins. Instead of running commands in the terminal, users can now click beautifully designed cards and watch plugins execute in real-time with live output streaming.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 The Problem I Solved
&lt;/h3&gt;

&lt;p&gt;GitHub Copilot CLI is incredibly powerful but requires terminal familiarity. My marketplace makes these capabilities accessible to everyone with an intuitive web interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✨ Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;🎨 Beautiful Modern UI&lt;/strong&gt; - SaaS-style design with smooth animations and terminal-style output display&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;⚡ Fast &amp;amp; Responsive&lt;/strong&gt; - Built with Next.js 16 and TailwindCSS 4&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🔌 4 Powerful Pre-built Plugins&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;📄 &lt;strong&gt;Generate README&lt;/strong&gt; - Create comprehensive project documentation&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;Summarize Git Commits&lt;/strong&gt; - Analyze history and generate changelogs&lt;/li&gt;
&lt;li&gt;🧪 &lt;strong&gt;Generate Test Cases&lt;/strong&gt; - Create unit and integration test suites&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;Repository Review&lt;/strong&gt; - Comprehensive code review and suggestions&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;🔒 Security First&lt;/strong&gt; - No command injection vulnerabilities, whitelist validation&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;📦 Extensible&lt;/strong&gt; - Add new plugins in 2 minutes with minimal code&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;🧪 Production Ready&lt;/strong&gt; - Full TypeScript, comprehensive error handling, security hardened&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  💻 Technology Stack
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend: React 19 + TypeScript + TailwindCSS
Backend: Next.js 16 (App Router) + API Routes
Runtime: Node.js child_process
CLI: GitHub Copilot CLI
Database: None (plugins configured in code)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;h3&gt;
  
  
  🎬 Live Project
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Repository&lt;/strong&gt;: &lt;a href="https://github.com/longphanquangminh/copilot-plugin-marketplace" rel="noopener noreferrer"&gt;GitHub - copilot-plugin-marketplace&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  📸 Screenshots
&lt;/h3&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%2Fesntg2fezeoeesv4h45x.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%2Fesntg2fezeoeesv4h45x.png" alt="Demo" width="800" height="622"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Homepage
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────┐
│                                                     │
│  Copilot CLI Plugin Marketplace                    │
│                                                     │
│  Supercharge your workflow with                    │
│  AI-powered productivity plugins                   │
│                                                     │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐         │
│  │📄 README │  │🔗 Commits│  │🧪 Tests  │         │
│  │Generate  │  │Summarize │  │Generate  │         │
│  │[ Run ]   │  │[ Run ]   │  │[ Run ]   │         │
│  └──────────┘  └──────────┘  └──────────┘         │
│                                                     │
│  ┌──────────┐                                       │
│  │🔍 Review │                                       │
│  │Repository│                                       │
│  │[ Run ]   │                                       │
│  └──────────┘                                       │
└─────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Plugin Execution
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 1: User clicks "Run Plugin"
Step 2: Loading spinner appears
Step 3: Copilot CLI executes prompt
Step 4: Results stream in real-time
Step 5: Terminal-style output displayed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Output Display
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────────────────────────────────────┐
│ $ Plugin Output                    │
├────────────────────────────────────┤
│ # My Project README                │
│                                    │
│ A modern web application...        │
│                                    │
│ ## Installation                    │
│ npm install                        │
│ npm run dev                        │
│                                    │
│ ## Features                        │
│ - Feature 1                        │
│ - Feature 2                        │
│                                    │
│ [Scroll for more...]               │
└────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🚀 Getting Started (2 Minutes)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone the repository&lt;/span&gt;
git clone https://github.com/longphanquangminh/copilot-plugin-marketplace.git
&lt;span class="nb"&gt;cd &lt;/span&gt;copilot-plugin-marketplace

&lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Start development server&lt;/span&gt;
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open &lt;strong&gt;&lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;/strong&gt; and explore the marketplace!&lt;/p&gt;

&lt;h3&gt;
  
  
  📋 Requirements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Node.js 18+&lt;/li&gt;
&lt;li&gt;GitHub Copilot CLI (&lt;code&gt;copilot&lt;/code&gt; command available in PATH)&lt;/li&gt;
&lt;li&gt;npm or yarn&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  My Experience with GitHub Copilot CLI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🎯 Why I Chose Copilot CLI
&lt;/h3&gt;

&lt;p&gt;I wanted to build something that showcased the &lt;strong&gt;real power&lt;/strong&gt; of GitHub Copilot CLI in a practical, business-ready application. Instead of a simple demo, I created a production-grade platform that makes AI-powered tools accessible to non-technical users.&lt;/p&gt;

&lt;h3&gt;
  
  
  💡 How I Used Copilot CLI
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. &lt;strong&gt;Direct Process Execution&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The marketplace executes Copilot CLI commands directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;exec&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`copilot prompt -m "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Capture and display output in real-time&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. &lt;strong&gt;Custom Prompts for Each Plugin&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Each plugin sends tailored prompts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;README Plugin&lt;/strong&gt;: "Create a comprehensive README.md"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commit Summarizer&lt;/strong&gt;: "Analyze recent commits and create changelog"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Generator&lt;/strong&gt;: "Generate comprehensive test cases"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository Review&lt;/strong&gt;: "Perform detailed code review"&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. &lt;strong&gt;Real-Time Output Streaming&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Users see results appear in a terminal-style interface as Copilot CLI processes the prompt.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚀 Impact on Development Experience
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Dramatically Improved&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Accessibility&lt;/strong&gt;: Non-terminal users can now leverage Copilot CLI&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;User Experience&lt;/strong&gt;: Beautiful, responsive interface with real-time feedback&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Scalability&lt;/strong&gt;: Easy to add new plugins without modifying core code&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Safety&lt;/strong&gt;: Robust error handling and security validation&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Speed&lt;/strong&gt;: 2-minute startup, plugin execution in seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What Copilot CLI Enabled&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Documentation Generation&lt;/strong&gt; - Copilot creates professional README files instantly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Changelog Creation&lt;/strong&gt; - Analyzes git history and generates summaries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Case Creation&lt;/strong&gt; - Suggests comprehensive test coverage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Review&lt;/strong&gt; - Provides architectural and quality recommendations&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  🎓 Learning Journey
&lt;/h3&gt;

&lt;p&gt;Building this project taught me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to safely integrate CLI tools into web applications&lt;/li&gt;
&lt;li&gt;Best practices for process management and error handling&lt;/li&gt;
&lt;li&gt;Creating extensible plugin architectures&lt;/li&gt;
&lt;li&gt;Security hardening against command injection&lt;/li&gt;
&lt;li&gt;Next.js App Router and modern React patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⚡ Performance &amp;amp; Scale
&lt;/h3&gt;

&lt;p&gt;The marketplace is optimized for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;30-second timeout&lt;/strong&gt; on executions (prevents hanging)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;10MB output buffer&lt;/strong&gt; (handles large outputs safely)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time streaming&lt;/strong&gt; (users see progress immediately)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error resilience&lt;/strong&gt; (graceful degradation on failures)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔐 Security Considerations
&lt;/h3&gt;

&lt;p&gt;I implemented multiple layers of protection:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Whitelist Validation&lt;/strong&gt; - Only registered plugins can execute&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No User Input&lt;/strong&gt; - Prompts are hardcoded per plugin&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Process Isolation&lt;/strong&gt; - Child processes are contained&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Buffer Limits&lt;/strong&gt; - Prevents memory exhaustion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Containment&lt;/strong&gt; - Safe error messages without data leakage&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  💬 Why This Matters
&lt;/h3&gt;

&lt;p&gt;GitHub Copilot CLI is a game-changer for developers, but it lives in the terminal. By creating this marketplace, I've shown that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copilot CLI can power sophisticated web applications&lt;/li&gt;
&lt;li&gt;AI tools don't need to be complex - they can be beautifully simple&lt;/li&gt;
&lt;li&gt;Teams can standardize on AI-assisted workflows&lt;/li&gt;
&lt;li&gt;Security and usability aren't mutually exclusive&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📊 Project Highlights
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Build Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&amp;lt;3 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dev Start&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~5 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page Load&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&amp;lt;500ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TypeScript Coverage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security Issues&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0 vulnerabilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Plugins&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4 pre-built + extensible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Documentation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5 comprehensive guides&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🎯 Perfect For
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🏆 Hackathon showcase&lt;/li&gt;
&lt;li&gt;📚 Portfolio projects&lt;/li&gt;
&lt;li&gt;👥 Team productivity tools&lt;/li&gt;
&lt;li&gt;🔬 Learning modern web development&lt;/li&gt;
&lt;li&gt;💼 Enterprise tool templates&lt;/li&gt;
&lt;li&gt;🤖 AI/ML demonstrations&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📚 Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/longphanquangminh/copilot-plugin-marketplace/blob/master/README.md" rel="noopener noreferrer"&gt;Full Project README&lt;/a&gt;&lt;/strong&gt; - Complete documentation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/longphanquangminh/copilot-plugin-marketplace/blob/master/QUICKSTART.md" rel="noopener noreferrer"&gt;Quick Start Guide&lt;/a&gt;&lt;/strong&gt; - Get running in 2 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/longphanquangminh/copilot-plugin-marketplace/blob/master/SETUP.md" rel="noopener noreferrer"&gt;Setup Instructions&lt;/a&gt;&lt;/strong&gt; - Detailed installation guide&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/longphanquangminh/copilot-plugin-marketplace/blob/master/EXAMPLES.md" rel="noopener noreferrer"&gt;Usage Examples&lt;/a&gt;&lt;/strong&gt; - Plugin usage scenarios&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/longphanquangminh/copilot-plugin-marketplace" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🙏 Special Thanks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/github/cli" rel="noopener noreferrer"&gt;GitHub Copilot CLI&lt;/a&gt; - The powerful backbone&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; - Modern web framework&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tailwindcss.com" rel="noopener noreferrer"&gt;TailwindCSS&lt;/a&gt; - Beautiful styling&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://react.dev" rel="noopener noreferrer"&gt;React 19&lt;/a&gt; - Latest React features&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎉 Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;This project demonstrates how GitHub Copilot CLI can be integrated into real-world applications to create tangible value. By combining security, usability, and powerful AI capabilities, we can build tools that help developers work smarter, not harder.&lt;/p&gt;

&lt;p&gt;The marketplace is ready to use, extend, and deploy. Whether you're a developer looking to learn Next.js or a team seeking to streamline your workflow, this project provides a solid foundation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thanks for checking out my submission for the GitHub Copilot CLI Challenge!&lt;/strong&gt; 🚀&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with ❤️ using Next.js, TypeScript, TailwindCSS, and GitHub Copilot CLI&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>cli</category>
      <category>githubcopilot</category>
    </item>
    <item>
      <title>🍔 FoodSnap Tutor – Snap a meal, get a recipe (Gemini 2.5 Flash)</title>
      <dc:creator>Long Phan</dc:creator>
      <pubDate>Mon, 15 Sep 2025 06:30:40 +0000</pubDate>
      <link>https://dev.to/minhlong2605/foodsnap-tutor-snap-a-meal-get-a-recipe-gemini-25-flash-10lo</link>
      <guid>https://dev.to/minhlong2605/foodsnap-tutor-snap-a-meal-get-a-recipe-gemini-25-flash-10lo</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-ai-studio-2025-09-03"&gt;Google AI Studio Multimodal Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;FoodSnap Tutor is a frontend-only app that turns any food photo into instant cooking guidance. Upload an image and the app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detects whether the image is food&lt;/li&gt;
&lt;li&gt;Identifies the likely dish name (with alternatives when uncertain)&lt;/li&gt;
&lt;li&gt;Generates a step-by-step recipe&lt;/li&gt;
&lt;li&gt;Estimates nutrition per serving (calories, protein, carbs, fat)&lt;/li&gt;
&lt;li&gt;Suggests a healthier variation and friendly moderation tips&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tech stack: React 19, TypeScript, Vite 6, Tailwind (CDN), and &lt;strong&gt;@google/genai&lt;/strong&gt; calling Gemini 2.5 Flash. Everything runs in the browser — no backend required.&lt;/p&gt;

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

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/criJO6OhDY0"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Live demo: &lt;a href="https://foodsnap-tutor.vercel.app" rel="noopener noreferrer"&gt;https://foodsnap-tutor.vercel.app&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Youtube video demo: &lt;a href="https://youtu.be/criJO6OhDY0" rel="noopener noreferrer"&gt;https://youtu.be/criJO6OhDY0&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Github repository: &lt;a href="https://github.com/longphanquangminh/foodsnap-tutor" rel="noopener noreferrer"&gt;https://github.com/longphanquangminh/foodsnap-tutor&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Screenshots:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✨ Upload screen:&lt;br&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%2Fmq026e8s8rio4rgp9fvl.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%2Fmq026e8s8rio4rgp9fvl.png" alt="Upload screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✨ Analysis screen:&lt;br&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%2F4f3elmz0j1yvgpia73ca.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%2F4f3elmz0j1yvgpia73ca.png" alt="Analysis screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✨ Error screen:&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%2Ft8fxbxjsnz4rr2uan55v.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%2Ft8fxbxjsnz4rr2uan55v.png" alt="Error screen"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How I Used Google AI Studio
&lt;/h2&gt;

&lt;p&gt;I leveraged the &lt;strong&gt;@google/genai&lt;/strong&gt; SDK to call Gemini 2.5 Flash with:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An inline &lt;strong&gt;image&lt;/strong&gt; part (base64-encoded upload).&lt;/li&gt;
&lt;li&gt;A structured &lt;strong&gt;prompt&lt;/strong&gt; telling the model to reply in JSON.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;response schema&lt;/strong&gt; so the SDK validates the output client-side.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GoogleGenAI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/genai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Strict JSON schema&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OBJECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;isFood&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BOOLEAN&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;dishName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;recipe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OBJECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;ingredients&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ARRAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ARRAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ingredients&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;steps&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;nutrition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OBJECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;calories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;protein&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;carbs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;fat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;calories&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;protein&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;carbs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;healthierVariation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;friendlyAdvice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;isFood&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dishName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;recipe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nutrition&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;healthierVariation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Convert upload to an image part&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileToPart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dataUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rej&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FileReader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readAsDataURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;res&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rej&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dataUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/:&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;?)&lt;/span&gt;&lt;span class="sr"&gt;;/&lt;/span&gt;&lt;span class="p"&gt;)?.[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image/jpeg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;inlineData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;mimeType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;analyzeFoodImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GoogleGenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imagePart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fileToPart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You are FoodSnap Tutor, an expert AI chef and nutritionist...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateContent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gemini-2.5-flash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;imagePart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;responseMimeType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;responseSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Environment wiring (Vite):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// vite.config.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loadEnv&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;loadEnv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;define&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;process.env.API_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .env.local
GEMINI_API_KEY=ai-xxxxxxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Multimodal Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vision input:&lt;/strong&gt; Users upload a dish photo that the SDK sends as inline image data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured output:&lt;/strong&gt; Gemini returns validated JSON (recipe, nutrition, advice) for deterministic UI rendering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single multimodal call:&lt;/strong&gt; Image + text prompt → cohesive culinary analysis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UX touches:&lt;/strong&gt; Drag-and-drop upload, instant preview, animated results, retry flow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Robustness:&lt;/strong&gt; UI handles blocked content or JSON parse errors gracefully with friendly messages.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Notes&lt;br&gt;
• Frontend-only: In production restrict the API key to allowed origins or proxy requests through a lightweight backend.&lt;br&gt;
• Built with React + Vite + Tailwind for fast iteration and static deployment.&lt;/p&gt;

&lt;p&gt;Thanks for reading! If you’d like to try it out or peek at the code, check the demo and repo links above. 🚀&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>googleaichallenge</category>
      <category>ai</category>
      <category>gemini</category>
    </item>
    <item>
      <title>🔭 Nocturne – A Blockchain Explorer for Midnight Network ⛓️</title>
      <dc:creator>Long Phan</dc:creator>
      <pubDate>Mon, 08 Sep 2025 06:29:22 +0000</pubDate>
      <link>https://dev.to/minhlong2605/nocturne-a-blockchain-explorer-for-midnight-network-3041</link>
      <guid>https://dev.to/minhlong2605/nocturne-a-blockchain-explorer-for-midnight-network-3041</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/midnight-2025-08-20"&gt;Midnight Network "Privacy First" Challenge&lt;/a&gt; - Enhance the Ecosystem prompt&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Nocturne — Midnight Explorer&lt;/strong&gt; is a privacy-first block explorer for the Midnight Network &lt;strong&gt;testnet&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It solves two problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Visibility&lt;/strong&gt; – Developers need an easy way to inspect blocks, extrinsics and events on the new privacy chain without spinning up their own node or indexer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy &amp;amp; Security&lt;/strong&gt; – Traditional explorers embed analytics and permissive CSPs. Nocturne ships with a &lt;em&gt;strict&lt;/em&gt;, developer-friendly setup that respects user privacy out-of-the-box.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ul&gt;
&lt;li&gt;Live data via &lt;code&gt;@polkadot/api&lt;/code&gt; WebSocket, no 3rd-party indexer required.&lt;/li&gt;
&lt;li&gt;Built with &lt;strong&gt;Next.js 15 App Router&lt;/strong&gt; + &lt;strong&gt;TypeScript&lt;/strong&gt; + &lt;strong&gt;Tailwind&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Dark theme, responsive, zero external fonts/analytics.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/longphanquangminh/midnight-explorer" rel="noopener noreferrer"&gt;https://github.com/longphanquangminh/midnight-explorer&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://midnight-explorer-sand.vercel.app" rel="noopener noreferrer"&gt;https://midnight-explorer-sand.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Screen&lt;/th&gt;
&lt;th&gt;Preview&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Home – Latest blocks &amp;amp; txs&lt;/td&gt;
&lt;td&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%2F14t49nwyjqngt7u5blth.png" alt="Home screenshot" width="800" height="536"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block list with paging&lt;/td&gt;
&lt;td&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%2Fjk8vt4sv6220bpnmmptd.png" alt="Blocks screenshot" width="800" height="799"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transaction detail&lt;/td&gt;
&lt;td&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%2Fulf7dndoq2e4pizbiuyg.png" alt="Tx screenshot" width="800" height="279"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How I Used Midnight's Technology
&lt;/h2&gt;

&lt;p&gt;Midnight Explorer connects directly to the &lt;strong&gt;Midnight RPC endpoint&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
It uses methods such as:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;chain_getBlockHash&lt;/code&gt; → to get block hashes
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chain_getBlock&lt;/code&gt; → to fetch full block details
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chain_getHeader&lt;/code&gt; → to check block headers and metadata
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By calling these RPC endpoints, the explorer can dynamically list new blocks and transactions without needing a centralized backend.&lt;/p&gt;

&lt;p&gt;This demonstrates how to integrate with Midnight’s Substrate-based architecture while keeping everything privacy-first and user-friendly.&lt;/p&gt;

&lt;p&gt;As I mentioned before, Midnight is Substrate-based, so I connected directly to the &lt;strong&gt;public testnet RPC&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApiPromise&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WsProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@polkadot/api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ApiPromise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WsProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wss://rpc.testnet-02.midnight.network&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Blocks:&lt;/strong&gt; &lt;code&gt;api.rpc.chain.getBlock(hash)&lt;/code&gt; and header queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transactions:&lt;/strong&gt; Iterated extrinsics + &lt;code&gt;system.events&lt;/code&gt; to derive success / failure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tip height:&lt;/strong&gt; &lt;code&gt;api.rpc.chain.getFinalizedHead()&lt;/code&gt; → header.number.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because the Polkadot API loads WASM crypto that calls &lt;code&gt;WebAssembly.instantiate&lt;/code&gt;, I extended the Content-Security-Policy with &lt;code&gt;'wasm-unsafe-eval'&lt;/code&gt; to keep things locked down yet functional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Experience Improvements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No need for manual RPC calls:&lt;/strong&gt; Developers can quickly inspect blocks without using &lt;code&gt;curl&lt;/code&gt; or custom scripts.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved debugging:&lt;/strong&gt; When building dApps on Midnight, seeing live transaction details in the explorer helps troubleshoot faster.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open source &amp;amp; extendable:&lt;/strong&gt; The codebase is kept simple so other developers can fork it and add features like search, account pages, or charts.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pain Point&lt;/th&gt;
&lt;th&gt;Nocturne’s Solution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hard to explore live data without indexer&lt;/td&gt;
&lt;td&gt;Direct node connection, lazy loaded singleton API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSP errors with WASM&lt;/td&gt;
&lt;td&gt;Pre-configured strict CSP allowing only what Polkadot needs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pagination UX&lt;/td&gt;
&lt;td&gt;“Next” &lt;strong&gt;and&lt;/strong&gt; “Previous” buttons with offset cursors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boilerplate&lt;/td&gt;
&lt;td&gt;Scaffolded project with Tailwind, linting, TypeScript, ready-to-deploy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Set Up Instructions / Tutorial
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Clone &amp;amp; install
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/YOUR_GH_ORG/midnight-explorer.git
&lt;span class="nb"&gt;cd &lt;/span&gt;midnight-explorer
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Configure environment
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;.env.local&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# optional – uses public RPC if omitted
NEXT_PUBLIC_RPC_URL=wss://rpc.testnet-02.midnight.network

# reserved for future indexer
NEXT_PUBLIC_INDEXER_URL=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Run locally
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;span class="c"&gt;# http://localhost:3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch the terminal for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Connecting to Midnight RPC at wss://...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Build for production
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build     &lt;span class="c"&gt;# Turbopack compile&lt;/span&gt;
npm start         &lt;span class="c"&gt;# Next.js server on port 3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Deploy to Vercel
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Import the repo → Framework preset &lt;strong&gt;Next.js&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Add the env vars above.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt; – done!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Future Improvements
&lt;/h2&gt;

&lt;p&gt;While Midnight Explorer already provides basic block and transaction browsing, there are many directions to expand and improve the user experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full transaction details&lt;/strong&gt;: Show event logs, method calls, gas usage, and execution status for every transaction.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internal transactions&lt;/strong&gt;: Support viewing internal calls (similar to RoninChain Explorer), so developers can trace contract-to-contract interactions and hidden flows inside a block.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich search functionality&lt;/strong&gt;: Enable search by block number, transaction hash, or account address.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Account pages&lt;/strong&gt;: Display balances, recent transactions, and contract code for each account.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Charts and statistics&lt;/strong&gt;: Add dashboards with real-time metrics like block time, TPS, gas consumption, and transaction volume.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better UX for developers&lt;/strong&gt;: Include copy-to-clipboard buttons for hashes/addresses, human-readable method names, and ABI decoding for contract calls.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy-first features&lt;/strong&gt;: Integrate Midnight’s unique privacy tech so that sensitive data can be hidden while still showing useful metadata (e.g., zk-proofs, shielded transactions).
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The long-term goal is to evolve Midnight Explorer into a &lt;strong&gt;comprehensive block explorer&lt;/strong&gt;, making it as powerful as established explorers like Etherscan or RoninChain Explorer, but optimized for Midnight’s privacy-first ecosystem.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;DEV username: &lt;code&gt;@minhlong2605&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thanks for reading &amp;amp; happy hacking on Midnight! 🌑🚀&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>midnightchallenge</category>
      <category>web3</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>AI Agent for real-time startup funding &amp; stock market monitoring</title>
      <dc:creator>Long Phan</dc:creator>
      <pubDate>Mon, 01 Sep 2025 06:51:48 +0000</pubDate>
      <link>https://dev.to/minhlong2605/ai-agent-for-real-time-startup-funding-stock-market-monitoring-52e7</link>
      <guid>https://dev.to/minhlong2605/ai-agent-for-real-time-startup-funding-stock-market-monitoring-52e7</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/brightdata-n8n-2025-08-13"&gt;AI Agents Challenge powered by n8n and Bright Data&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I built an AI Agent for real-time startup funding &amp;amp; stock market monitoring.&lt;br&gt;
The agent continuously scrapes funding announcements, investment news, and stock-related articles from trusted sources using Bright Data.&lt;br&gt;
It then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Normalizes the data (startup name, funding round, amount, investor, location).&lt;/li&gt;
&lt;li&gt;Stores results in a structured database.&lt;/li&gt;
&lt;li&gt;Sends instant alerts when new investment or stock news is detected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This solves the problem of information overload for investors, founders, and analysts—delivering curated, actionable insights in real time.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;



&lt;p&gt;👉 &lt;a href="https://minhlong26052001.app.n8n.cloud/workflow/bWgqbqTXwlJdOekE" rel="noopener noreferrer"&gt;Demo Link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The demo showcases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;News scraping with Bright Data.&lt;/li&gt;
&lt;li&gt;AI-powered classification (e.g., Seed / Series A / IPO news).&lt;/li&gt;
&lt;li&gt;Slack/Telegram notifications when a new funding round is published.&lt;/li&gt;
&lt;li&gt;Historical record stored in Supabase for querying.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  n8n Workflow
&lt;/h3&gt;



&lt;p&gt;The core workflow is built in n8n. It runs every 30 minutes, scrapes investment/stock news, stores the data, and pushes alerts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trigger: Cron Node (every 30m)&lt;/li&gt;
&lt;li&gt;Bright Data Verified Node: Scrape financial/startup sources&lt;/li&gt;
&lt;li&gt;Function Node: Parse + classify news&lt;/li&gt;
&lt;li&gt;Supabase Node: Save to investment_alerts table&lt;/li&gt;
&lt;li&gt;Slack/Telegram Node: Alert user on new deals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔗 &lt;a href="https://gist.github.com/longphanquangminh/ed542655ec3a2378ed8375f9f82f4dea" rel="noopener noreferrer"&gt;Workflow JSON on GitHub Gist&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Technical Implementation
&lt;/h2&gt;



&lt;ul&gt;
&lt;li&gt;System Instructions:&lt;/li&gt;
&lt;li&gt;- Extract relevant entities (company, funding round, amount, investor).&lt;/li&gt;
&lt;li&gt;- Filter only startup funding or stock-related events.&lt;/li&gt;
&lt;li&gt;- Categorize severity/importance.&lt;/li&gt;
&lt;li&gt;Model Choice: OpenAI GPT-4 mini (n8n OpenAI node).&lt;/li&gt;
&lt;li&gt;Memory: No long-term memory needed, but history is stored in Supabase for querying.&lt;/li&gt;
&lt;li&gt;Tools used:&lt;/li&gt;
&lt;li&gt;- Bright Data Verified Node (scraping)&lt;/li&gt;
&lt;li&gt;- Supabase (free Postgres DB with REST API)&lt;/li&gt;
&lt;li&gt;- n8n Function Node (data cleaning)&lt;/li&gt;
&lt;li&gt;- Slack/Telegram (notification)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Bright Data Verified Node
&lt;/h3&gt;



&lt;p&gt;Bright Data provides reliable, real-time scraping of news and financial data sources.&lt;br&gt;
In my workflow, the Bright Data node fetches startup funding announcements and stock-related articles.&lt;/p&gt;

&lt;p&gt;Example JSON returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FinTechX raises $20M Series A led by Sequoia&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://news.example.com/fintechx-seriesa&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2025-08-31T12:00:00Z&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;category&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;funding&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This output is parsed, classified, and stored into Supabase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Journey
&lt;/h2&gt;

&lt;p&gt;At first, I tried connecting multiple news APIs, but they had rate limits and lacked coverage for private startup deals.&lt;br&gt;
By leveraging &lt;strong&gt;Bright Data&lt;/strong&gt;, I was able to scrape diverse sources reliably.&lt;br&gt;
Challenges included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Normalizing inconsistent data (dates, company names, funding formats).&lt;/li&gt;
&lt;li&gt;Avoiding duplicate entries in the DB.&lt;/li&gt;
&lt;li&gt;Designing a lightweight schema that works for both startup funding and stock alerts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I learned how powerful &lt;strong&gt;n8n + Bright Data&lt;/strong&gt; are together: low-code workflow automation + enterprise-grade data pipelines.&lt;br&gt;
The best part? I can extend this agent to cover &lt;strong&gt;M&amp;amp;A, IPOs, or crypto markets&lt;/strong&gt; next. 🚀&lt;/p&gt;

&lt;p&gt;👉 That’s my submission! Thanks to n8n &amp;amp; Bright Data for making real-time AI agents possible.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>n8nbrightdatachallenge</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Real-Time Donation Leaderboard with AI Predictions: Powered by Redis 8</title>
      <dc:creator>Long Phan</dc:creator>
      <pubDate>Mon, 11 Aug 2025 06:53:52 +0000</pubDate>
      <link>https://dev.to/minhlong2605/real-time-donation-leaderboard-with-ai-predictions-powered-by-redis-8-1m2o</link>
      <guid>https://dev.to/minhlong2605/real-time-donation-leaderboard-with-ai-predictions-powered-by-redis-8-1m2o</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;: Real-Time AI Innovators&lt;/em&gt;.&lt;/p&gt;

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

&lt;p&gt;I created a &lt;strong&gt;Real-Time Donation Leaderboard&lt;/strong&gt; that combines the power of Redis 8 with OpenAI to deliver instant donation tracking, live leaderboards, and AI-powered predictions. This full-stack TypeScript application demonstrates how Redis can serve as the backbone for real-time applications while enabling intelligent insights through AI integration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;⚡ &lt;strong&gt;Real-time donation tracking&lt;/strong&gt; with instant leaderboard updates&lt;/li&gt;
&lt;li&gt;🏆 &lt;strong&gt;Live leaderboard&lt;/strong&gt; with automatic polling every 3 seconds&lt;/li&gt;
&lt;li&gt;🤖 &lt;strong&gt;AI-powered predictions&lt;/strong&gt; for rising donors and daily totals&lt;/li&gt;
&lt;li&gt;📊 &lt;strong&gt;Comprehensive analytics&lt;/strong&gt; with donation patterns and trends&lt;/li&gt;
&lt;li&gt;🎨 &lt;strong&gt;Modern responsive UI&lt;/strong&gt; with smooth animations&lt;/li&gt;
&lt;li&gt;🔒 &lt;strong&gt;Production-ready&lt;/strong&gt; with security, error handling, and health checks&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h3&gt;
  
  
  🔗 Links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repo&lt;/strong&gt;: &lt;a href="https://github.com/longphanquangminh/leaderboard-donation" rel="noopener noreferrer"&gt;https://github.com/longphanquangminh/leaderboard-donation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📱 Screenshots
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Main leaderboard interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fambzb1na1k7iqf80jog3.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%2Fambzb1na1k7iqf80jog3.png" alt="Image 1" width="800" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Donation form in action&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;AI predictions panel&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Mobile responsive design&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvc3h82cbvnfgu3x6c399.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%2Fvc3h82cbvnfgu3x6c399.png" alt="Image 4" width="800" height="1100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time updates in progress&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F03jv7bauptif116735p3.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%2F03jv7bauptif116735p3.png" alt="Image 5" width="764" height="136"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Redis 8 serves as the &lt;strong&gt;complete real-time data layer&lt;/strong&gt; for this application, leveraging multiple Redis data structures and features:&lt;/p&gt;

&lt;h3&gt;
  
  
  🏗️ Core Redis Architecture
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. &lt;strong&gt;Sorted Sets for Leaderboard Rankings&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Real-time leaderboard updates using Redis Sorted Sets&lt;/span&gt;
&lt;span class="c1"&gt;// Increment donor's total amount atomically&lt;/span&gt;
&lt;span class="nx"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zIncrBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;leaderboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Get top donors with scores (descending order)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zRangeWithScores&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;leaderboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;REV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. &lt;strong&gt;Streams for Event Sourcing&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Track all donation events with Redis Streams&lt;/span&gt;
&lt;span class="nx"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;donations:stream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Retrieve recent donations for AI analysis&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;streamData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;donations:stream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. &lt;strong&gt;Hash Maps for Donor Information&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Store donor name mapping efficiently&lt;/span&gt;
&lt;span class="nx"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;donor:names&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Get donor names for leaderboard display&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;donorIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hmGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;donor:names&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donorIds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. &lt;strong&gt;Atomic Multi-Operations&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Use Redis multi for atomic operations&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;multi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Add to streams for event history&lt;/span&gt;
&lt;span class="nx"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;donations:stream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donationData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Update leaderboard (sorted set)&lt;/span&gt;
&lt;span class="nx"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zIncrBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;leaderboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Store donor name mapping&lt;/span&gt;
&lt;span class="nx"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;donor:names&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Execute all commands atomically&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🚀 Real-Time Performance Benefits
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Connection Management with Retry Logic&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIS_USERNAME&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIS_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIS_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;localhost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIS_PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;6379&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;reconnectStrategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Health Monitoring&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ensureConnection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PONG&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Redis ping failed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🤖 AI Integration with Redis
&lt;/h3&gt;

&lt;p&gt;Redis serves as the &lt;strong&gt;intelligent data pipeline&lt;/strong&gt; for AI predictions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;generatePredictions&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PredictionData&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Get current leaderboard and recent donations from Redis&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;recentDonations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;totalDonations&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;redisService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLeaderboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;redisService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRecentDonations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;redisService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTotalDonations&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="c1"&gt;// Prepare data for AI analysis&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;donationTrends&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;analyzeDonationTrends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recentDonations&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;leaderboardData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Generate AI predictions using OpenAI&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;completion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-3.5-turbo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;You are an AI analyst specializing in donation pattern analysis and predictions.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;buildPredictionPrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;leaderboardData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donationTrends&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;totalDonations&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📊 Data Analysis from Redis Streams
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;analyzeDonationTrends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;donations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Donation&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hourlyTrends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;donorActivity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oneHour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;donations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;donation&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;oneHour&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;hourlyTrends&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hourlyTrends&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;donorActivity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;donorActivity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;donorActivity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;donorActivity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Count recent activity (last 6 hours)&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;oneHour&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;donorActivity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;recent&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;hourlyTrends&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donorActivity&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Technical Architecture
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🏗️ Full Stack Implementation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Backend&lt;/strong&gt;: Node.js + Express + TypeScript&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RESTful API with comprehensive error handling&lt;/li&gt;
&lt;li&gt;Redis integration with connection pooling&lt;/li&gt;
&lt;li&gt;OpenAI API integration for predictions&lt;/li&gt;
&lt;li&gt;Security middleware (Helmet, CORS)&lt;/li&gt;
&lt;li&gt;Health monitoring and graceful shutdown&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Frontend&lt;/strong&gt;: React 18 + TypeScript + Vite&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time polling every 3 seconds&lt;/li&gt;
&lt;li&gt;Responsive design with SCSS&lt;/li&gt;
&lt;li&gt;Smooth animations and loading states&lt;/li&gt;
&lt;li&gt;Error boundaries and user feedback&lt;/li&gt;
&lt;li&gt;Accessibility-compliant interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Database&lt;/strong&gt;: Redis as primary data store&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sorted Sets for rankings&lt;/li&gt;
&lt;li&gt;Streams for event history&lt;/li&gt;
&lt;li&gt;Hash Maps for metadata&lt;/li&gt;
&lt;li&gt;Atomic operations for consistency&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔧 Key Technical Decisions
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Why Redis Over Traditional Databases?&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: In-memory operations for instant leaderboard updates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time&lt;/strong&gt;: Native support for live data structures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: Single data store for multiple use cases&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI-Ready&lt;/strong&gt;: Fast data aggregation for ML pipelines&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Actual Redis Data Model&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;leaderboard (Sorted Set)
├── john_doe → 1500.00
├── jane_smith → 1200.50
└── bob_johnson → 950.25

donations:stream (Stream)
├── 1691234567890-0: {donorId: "john_doe", donorName: "John Doe", amount: "25.00", ...}
├── 1691234567891-0: {donorId: "jane_smith", donorName: "Jane Smith", amount: "50.00", ...}
└── 1691234567892-0: {donorId: "john_doe", donorName: "John Doe", amount: "75.00", ...}

donor:names (Hash)
├── "john_doe" → "John Doe"
├── "jane_smith" → "Jane Smith"
└── "bob_johnson" → "Bob Johnson"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🚀 Performance Optimizations
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Connection Management with Retry Logic&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIS_USERNAME&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIS_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIS_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;localhost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIS_PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;6379&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;reconnectStrategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Atomic Multi-Operations&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Use Redis multi for atomic operations&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;multi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Add to streams for event history&lt;/span&gt;
&lt;span class="nx"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;donations:stream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Update leaderboard (sorted set)&lt;/span&gt;
&lt;span class="nx"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zIncrBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;leaderboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Store donor name mapping&lt;/span&gt;
&lt;span class="nx"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;donor:names&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Execute all commands atomically&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Efficient Data Retrieval&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Get leaderboard with scores in one operation&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zRangeWithScores&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;leaderboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;REV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Batch get donor names&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;donorIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hmGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;donor:names&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donorIds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  AI-Powered Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🤖 Intelligent Predictions
&lt;/h3&gt;

&lt;p&gt;The application uses OpenAI GPT-3.5-turbo to analyze donation patterns and generate predictions:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Real AI Implementation&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;generatePredictions&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PredictionData&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Get current leaderboard and recent donations from Redis&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;recentDonations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;totalDonations&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="nx"&gt;redisService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLeaderboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;redisService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRecentDonations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;redisService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTotalDonations&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="c1"&gt;// Prepare data for AI analysis&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;donationTrends&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;analyzeDonationTrends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recentDonations&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;leaderboardData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Generate AI predictions using OpenAI&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;completion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-3.5-turbo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;You are an AI analyst specializing in donation pattern analysis and predictions.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;buildPredictionPrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;leaderboardData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;donationTrends&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;totalDonations&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;predictions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validateAndEnhancePredictions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;totalDonations&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AI prediction error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateFallbackPredictions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Data Analysis Pipeline&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;analyzeDonationTrends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;donations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Donation&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hourlyTrends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;donorActivity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oneHour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;donations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;donation&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;oneHour&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;hourlyTrends&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hourlyTrends&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;donorActivity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;donorActivity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;recent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;donorActivity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;donorActivity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Count recent activity (last 6 hours)&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;oneHour&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;donorActivity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;recent&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;hourlyTrends&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;donorActivity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;totalDonations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;totalAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;AI Prompt Engineering&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;buildPredictionPrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LeaderboardEntry&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;trends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;totalDonations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`
Analyze the following donation data and provide predictions in JSON format:

CURRENT LEADERBOARD:
&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: $&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalAmount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;

DONATION TRENDS:
- Total donations today: $&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;totalDonations&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
- Recent donor activity: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trends&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorActivity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;
- Hourly trends: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trends&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hourlyTrends&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;

Please provide predictions in this EXACT JSON format:
{
  "risingStars": [
    {
      "donorId": "donor_id",
      "donorName": "Donor Name", 
      "currentAmount": 100,
      "predictedGrowth": 25.5,
      "confidence": 0.75
    }
  ],
  "dailyTotal": {
    "currentTotal": &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;totalDonations&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;,
    "predictedTotal": estimated_end_of_day_total,
    "confidence": 0.8,
    "timeRemaining": "X hours remaining"
  }
}
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🧠 Fallback Intelligence
&lt;/h3&gt;

&lt;p&gt;When OpenAI is unavailable, the system uses Redis-based heuristics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;generateFallbackPredictions&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PredictionData&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;totalDonations&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;redisService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLeaderboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;redisService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTotalDonations&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="c1"&gt;// Simple heuristic-based predictions&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;risingStars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;leaderboard&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Pick middle-ranking donors as potential rising stars&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;currentAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalAmount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;predictedGrowth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Random growth between 10-60&lt;/span&gt;
      &lt;span class="na"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}));&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentHour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getHours&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hoursRemaining&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;currentHour&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;growthFactor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 10-50% growth&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;risingStars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dailyTotal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;currentTotal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;totalDonations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;predictedTotal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;totalDonations&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;growthFactor&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;timeRemaining&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hoursRemaining&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; hours remaining`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Prediction Validation&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;validateAndEnhancePredictions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LeaderboardEntry&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="nx"&gt;totalDonations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;PredictionData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Ensure rising stars exist and are valid&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;risingStars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;risingStars&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;currentAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentAmount&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;predictedGrowth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;predictedGrowth&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="na"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;confidence&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;}));&lt;/span&gt;

  &lt;span class="c1"&gt;// Validate daily total prediction&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentHour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getHours&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hoursRemaining&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;currentHour&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dailyTotal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;currentTotal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;totalDonations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;predictedTotal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;totalDonations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dailyTotal&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;predictedTotal&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;totalDonations&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dailyTotal&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;confidence&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="na"&gt;timeRemaining&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hoursRemaining&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; hours remaining`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;risingStars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dailyTotal&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real-World Impact
&lt;/h2&gt;

&lt;h3&gt;
  
  
  📈 Technical Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Response Time&lt;/strong&gt;: Fast in-memory Redis operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Consistency&lt;/strong&gt;: Atomic multi-operations ensure data integrity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Redis can handle high concurrent loads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory Efficiency&lt;/strong&gt;: Optimized data structures for leaderboard use case&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Updates&lt;/strong&gt;: 3-second polling provides near real-time experience&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🎯 Use Cases
&lt;/h3&gt;

&lt;p&gt;This architecture is perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Charity Fundraising&lt;/strong&gt;: Real-time donation tracking and leaderboards&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gaming Leaderboards&lt;/strong&gt;: Live player rankings and achievements&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sales Competitions&lt;/strong&gt;: Team performance tracking and motivation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Social Media&lt;/strong&gt;: Trending content and engagement rankings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E-commerce&lt;/strong&gt;: Real-time inventory and sales tracking&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🔮 Future Enhancements
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;WebSocket Integration&lt;/strong&gt;: Replace polling with real-time push notifications&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis Pub/Sub&lt;/strong&gt;: Instant updates to all connected clients&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced Analytics&lt;/strong&gt;: More sophisticated trend analysis&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Machine Learning&lt;/strong&gt;: Custom prediction models trained on historical data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geographic Analytics&lt;/strong&gt;: Location-based donation insights&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mobile App&lt;/strong&gt;: Native mobile applications with push notifications&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🚀 Quick Setup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone the repository&lt;/span&gt;
git clone &lt;span class="o"&gt;[&lt;/span&gt;your-repo-url]
&lt;span class="nb"&gt;cd &lt;/span&gt;leaderboard-donation

&lt;span class="c"&gt;# Run automated setup&lt;/span&gt;
./setup.sh

&lt;span class="c"&gt;# Configure environment variables&lt;/span&gt;
&lt;span class="nb"&gt;cp &lt;/span&gt;backend/.env.example backend/.env
&lt;span class="nb"&gt;cp &lt;/span&gt;frontend/.env.example frontend/.env

&lt;span class="c"&gt;# Start the application&lt;/span&gt;
&lt;span class="c"&gt;# Terminal 1: Backend&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;backend &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run dev

&lt;span class="c"&gt;# Terminal 2: Frontend  &lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;frontend &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run dev

&lt;span class="c"&gt;# Optional: Seed test data&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;backend &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run seed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔧 Configuration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Backend (.env)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PORT=3001
REDIS_URL=redis://your-redis-host:6379
REDIS_PASSWORD=your-redis-password
OPENAI_API_KEY=your-openai-api-key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Frontend (.env)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VITE_API_URL=http://localhost:3001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📚 API Implementation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Donation Submission&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;submitDonation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;DonationRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Validation&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;donorName&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;donorName&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Donor name is required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Valid donation amount is required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Donation amount cannot exceed $10,000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Create donation object&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Donation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;uuidv4&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;donorId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Round to 2 decimal places&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// Save to Redis&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redisService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addDonation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;donorName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;donation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error submitting donation:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Internal server error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Leaderboard Retrieval&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getLeaderboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Limit cannot exceed 50&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;leaderboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redisService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLeaderboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error fetching leaderboard:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Internal server error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Statistics Calculation&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getStats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;totalDonations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;recentDonations&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="nx"&gt;redisService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTotalDonations&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nx"&gt;redisService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRecentDonations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;totalDonations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;donationsToday&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;recentDonations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;averageDonation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;recentDonations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
          &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;recentDonations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;recentDonations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;
          &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error fetching stats:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Internal server error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This project demonstrates how &lt;strong&gt;Redis 8&lt;/strong&gt; can serve as a complete real-time data platform, enabling both high-performance applications and intelligent AI integrations. By leveraging Redis's diverse data structures and combining them with OpenAI's predictive capabilities, we've created a system that's not just fast and reliable, but also intelligent and insightful.&lt;/p&gt;

&lt;p&gt;The combination of Redis's sub-millisecond performance with AI-powered predictions creates a new category of applications that are both reactive and predictive - responding instantly to user actions while providing intelligent insights about future trends.&lt;/p&gt;

&lt;h3&gt;
  
  
  🏆 Why This Matters
&lt;/h3&gt;

&lt;p&gt;In today's real-time world, users expect instant feedback and intelligent insights. This project shows how Redis 8 makes it possible to deliver both, creating applications that are not just fast, but smart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redis isn't just a cache anymore - it's an intelligent real-time data platform.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with ❤️ using Redis 8, OpenAI, TypeScript, React, and Node.js&lt;/em&gt;&lt;/p&gt;

</description>
      <category>redischallenge</category>
      <category>devchallenge</category>
      <category>database</category>
      <category>ai</category>
    </item>
    <item>
      <title>Real-Time Job Recommender with Bright Data MCP</title>
      <dc:creator>Long Phan</dc:creator>
      <pubDate>Mon, 26 May 2025 06:25:56 +0000</pubDate>
      <link>https://dev.to/minhlong2605/real-time-job-recommender-with-bright-data-mcp-44n8</link>
      <guid>https://dev.to/minhlong2605/real-time-job-recommender-with-bright-data-mcp-44n8</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/brightdata-2025-05-07"&gt;Bright Data AI Web Access Hackathon&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I built a &lt;strong&gt;Real-Time Job Recommender&lt;/strong&gt; system that empowers users to search for jobs using natural language queries and receive up-to-date job listings from across the web. Powered by &lt;strong&gt;LLMs&lt;/strong&gt; and &lt;strong&gt;Bright Data’s Model Context Protocol (MCP)&lt;/strong&gt;, this AI agent autonomously navigates job websites, retrieves structured data in real time, and matches results based on intent rather than keywords.&lt;/p&gt;

&lt;p&gt;This project solves the issue of outdated or irrelevant job recommendations by enabling live, intelligent search through current listings on the open web.&lt;/p&gt;

&lt;h2&gt;
  
  
  📽️ Demo
&lt;/h2&gt;

&lt;p&gt;🔗 GitHub Repository: &lt;a href="https://github.com/longphanquangminh/llm-job-suggestor" rel="noopener noreferrer"&gt;https://github.com/longphanquangminh/llm-job-suggestor&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Used Bright Data's Infrastructure
&lt;/h2&gt;

&lt;p&gt;right Data’s Model Context Protocol (MCP) was essential to building an autonomous AI agent that can operate on the live web.&lt;/p&gt;

&lt;p&gt;Here's how MCP enhanced the system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Discover&lt;/strong&gt;: The agent locates relevant job listings across multiple platforms and job boards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access&lt;/strong&gt;: MCP enables seamless access to modern, JavaScript-heavy job sites.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extract&lt;/strong&gt;: The agent retrieves structured data—job titles, companies, locations, requirements—in real time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interact&lt;/strong&gt;: The system mimics human interaction with dynamic interfaces (e.g., pagination, filters) and adapts to changes in website structure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MCP acts as a control layer for AI agents, providing real-time interaction with external web contexts. This allowed my job recommender to function as a self-sufficient explorer of the web, without preloaded data or brittle scrapers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Improvements
&lt;/h2&gt;

&lt;p&gt;Using real-time web access via MCP led to substantial improvements over traditional approaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live results&lt;/strong&gt;: Users receive job opportunities that are currently available—not days or weeks old.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Richer understanding&lt;/strong&gt;: LLMs analyze complete job descriptions, not just titles or summaries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Semantic search&lt;/strong&gt;: Vector search ensures the results match the user’s intent, even with fuzzy or casual phrasing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic adaptability&lt;/strong&gt;: The system can adapt to layout changes or new websites without reprogramming extractors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compared to static datasets or basic keyword scraping, this approach is significantly more intelligent, flexible, and responsive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;✅ Real-time job discovery from multiple online sources&lt;br&gt;
✅ Natural language job search (e.g., “remote backend roles in fintech”)&lt;br&gt;
✅ LLM-based classification, summarization, and sentiment scoring&lt;br&gt;
✅ Vector-based semantic search using OpenAI embeddings&lt;br&gt;
✅ Gradio-powered interactive dashboard&lt;br&gt;
✅ Filtering by industry, experience level, job type, and location&lt;br&gt;
✅ Scheduled crawling to keep the dataset fresh and relevant&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.11&lt;/li&gt;
&lt;li&gt;Bright Data MCP&lt;/li&gt;
&lt;li&gt;OpenAI + LangChain&lt;/li&gt;
&lt;li&gt;Chroma (Vector DB)&lt;/li&gt;
&lt;li&gt;Gradio (Web UI)&lt;/li&gt;
&lt;li&gt;Pandas and SQLite for lightweight data storage&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;Some future directions I’m excited about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Personalized job recommendations based on resume data&lt;/li&gt;
&lt;li&gt;Real-time salary benchmarking&lt;/li&gt;
&lt;li&gt;Company culture analysis using scraped reviews&lt;/li&gt;
&lt;li&gt;Auto-application tools for integrated platforms&lt;/li&gt;
&lt;li&gt;User profiles with alerts and saved searches&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Acknowledgements
&lt;/h2&gt;

&lt;p&gt;Shoutout to &lt;strong&gt;Bright Data&lt;/strong&gt; for creating the infrastructure to empower agents to explore and interact with the web in real time. If you're building anything with AI agents or live web data, MCP is a game-changer.&lt;/p&gt;




&lt;p&gt;Want to connect or collaborate? Reach out—I’d love to hear your thoughts 😊&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>brightdatachallenge</category>
      <category>ai</category>
      <category>webdata</category>
    </item>
    <item>
      <title>🔐 Build &amp; Run Your Own TOTP Generator in Under 5 Minutes — with Amazon Q Developer</title>
      <dc:creator>Long Phan</dc:creator>
      <pubDate>Mon, 12 May 2025 06:14:30 +0000</pubDate>
      <link>https://dev.to/minhlong2605/build-run-your-own-totp-generator-in-under-5-minutes-with-amazon-q-developer-1f6d</link>
      <guid>https://dev.to/minhlong2605/build-run-your-own-totp-generator-in-under-5-minutes-with-amazon-q-developer-1f6d</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/aws-amazon-q-v2025-04-30"&gt;Amazon Q Developer "Quack The Code" Challenge&lt;/a&gt;: Crushing the Command Line&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;We all know that &lt;strong&gt;Multi-Factor Authentication (MFA)&lt;/strong&gt; is essential for securing our accounts. But let’s be honest—how many times have you felt frustrated opening your phone, launching the authenticator app, and copying the OTP code every time you're logging in somewhere on your work computer or laptop?&lt;/p&gt;

&lt;p&gt;Worse, what if your phone is &lt;strong&gt;de*d, lost, or simply not nearby&lt;/strong&gt;? You’re locked out.&lt;/p&gt;

&lt;p&gt;That’s why I built this project: a &lt;strong&gt;TOTP (Time-based One-Time Password) generator tool&lt;/strong&gt; available as both a &lt;strong&gt;command-line interface&lt;/strong&gt; and a &lt;strong&gt;lightweight frontend&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It lets you instantly generate TOTP codes from a saved secret—no phone required.&lt;/p&gt;

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

&lt;p&gt;I built a TOTP (Time-based One-Time Password) generator tool that runs on both the &lt;strong&gt;command line&lt;/strong&gt; and a simple &lt;strong&gt;frontend web interface&lt;/strong&gt;. This tool solves the problem of securely generating one-time passwords commonly used in 2FA (Two-Factor Authentication) systems.&lt;/p&gt;

&lt;p&gt;⚙️ &lt;strong&gt;CLI tool&lt;/strong&gt;: Instantly generates TOTP codes from a shared secret via terminal. It supports auto-copying the generated code using the clipboard.&lt;/p&gt;

&lt;p&gt;🌐 &lt;strong&gt;Frontend demo&lt;/strong&gt;: A minimal web interface that visualizes the TOTP flow and shows the code updating every 30 seconds.&lt;/p&gt;

&lt;p&gt;This tool is lightweight and designed for developers who frequently work with authentication flows, or for testing their 2FA setup during app development.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;🌍︎ Live page&lt;/strong&gt;: &lt;a href="https://longphanquangminh.github.io/totp-generator-project/web" rel="noopener noreferrer"&gt;https://longphanquangminh.github.io/totp-generator-project/web&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After asking Amazon Q Developer to build the application and generate an initial flow diagram, I took the time to deepen my understanding of how TOTP works. I then created my own visual explanation to solidify and share that understanding (with a demo secret key, so it's just fine like that):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📊 My custom TOTP flow diagram&lt;/strong&gt; (made with Excalidraw): &lt;a href="https://excalidraw.com/#json=vGtrTjCItd2t9qXrGN-kh,HUWCStHXAj-EsZmagqmayw" rel="noopener noreferrer"&gt;Link&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%2F5ckyva0mall23k4zqt5o.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%2F5ckyva0mall23k4zqt5o.png" alt="Diagram" width="800" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔑 Extracting a TOTP Secret Key from a GitHub QR Code&lt;/strong&gt;&lt;br&gt;
This screenshot shows how I used my CLI tool to scan a QR code (e.g., from GitHub's 2FA setup) and retrieve the base32 secret key.&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%2F6so3i6r7zq9vkdabk5py.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%2F6so3i6r7zq9vkdabk5py.png" alt="Demo" width="800" height="703"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When scanning a QR code with my Samsung phone (just once), you can extract the secret key from the QR's value, which typically follows this format: &lt;code&gt;otpauth://[OTP_type]/[issuer]:[user_identity]?secret=[secret_key]&amp;amp;issuer=[issuer]&lt;/code&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%2Fookhbmr3jzpndbzfkbmx.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%2Fookhbmr3jzpndbzfkbmx.png" alt="Camera" width="602" height="1352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, if the value is: &lt;code&gt;otpauth://totp/GitHub:longphanquangminh?secret=ggg&amp;amp;issuer=GitHub&lt;/code&gt; =&amp;gt; Then the secret_key would be &lt;code&gt;ggg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🖥️📱 Matching OTPs on Both CLI and Web UI&lt;/strong&gt;&lt;br&gt;
To demonstrate accuracy, I used the same TOTP secret in both the CLI and web tool. As shown below, both generated the same OTP codes, just like a real authenticator app would:&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%2Fgfpjjsipjpdd7aznwcur.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%2Fgfpjjsipjpdd7aznwcur.png" alt="LiveWeb" width="800" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Repository
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;🔗 GitHub Repo&lt;/strong&gt;: &lt;a href="https://github.com/longphanquangminh/totp-generator-project" rel="noopener noreferrer"&gt;https://github.com/longphanquangminh/totp-generator-project&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/cli&lt;/code&gt; – Node.js terminal utility with clipboard integration.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/web&lt;/code&gt; – Frontend TOTP display tool with diagram and styling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How I Used Amazon Q Developer
&lt;/h2&gt;

&lt;p&gt;Amazon Q Developer played a huge role in helping me build and polish this tool quickly. Here’s how I used it:&lt;/p&gt;

&lt;h3&gt;
  
  
  🧠 Idea to Execution — Powered by Amazon Q
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Logged into &lt;strong&gt;Amazon Q Developer&lt;/strong&gt; via &lt;code&gt;q login&lt;/code&gt; from my terminal.&lt;/li&gt;
&lt;li&gt;Opened &lt;strong&gt;Q Chat&lt;/strong&gt; via &lt;code&gt;q chat&lt;/code&gt; to brainstorm implementation details and flow.&lt;/li&gt;
&lt;li&gt;Prompted Q:
&lt;code&gt;How do I implement a TOTP generator CLI tool in Node.js that auto-copies the result to clipboard?&lt;/code&gt;
→ Q provided sample code using &lt;code&gt;otplib&lt;/code&gt; and &lt;code&gt;clipboardy&lt;/code&gt;. But in this case, after doing some research, I decided to use &lt;code&gt;otpauth&lt;/code&gt; instead of &lt;code&gt;otplib&lt;/code&gt; because it's newer and offers more flexible customization of the algorithm and time settings.&lt;/li&gt;
&lt;li&gt;Used Q to help draw a simple diagram explaining the TOTP flow (time + secret → HMAC → OTP).&lt;/li&gt;
&lt;li&gt;Asked Q to help improve the CLI experience (formatting, error handling, feedback, timer).&lt;/li&gt;
&lt;li&gt;Switched to the frontend: I asked Q to style the TOTP web page, make it responsive, and implement the 30-second countdown bar.&lt;/li&gt;
&lt;li&gt;Completed both tools in a much shorter time than building from scratch.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🚀 With the help of Amazon Q, I built both the CLI tool and the frontend app in literally under 5 minutes.&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%2F41r95whz5fm5wke0hop8.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%2F41r95whz5fm5wke0hop8.png" alt="AmazonQ" width="800" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  💡 Tips for Using Amazon Q Developer
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Be clear and specific in your prompts.&lt;/li&gt;
&lt;li&gt;Ask for architecture and visual explanations too—not just code.&lt;/li&gt;
&lt;li&gt;Iterate with Q! Ask it to improve or adapt to your stack.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;This tool was built for educational purposes and as a submission for the &lt;strong&gt;Amazon Q Developer “Quack The Code” Challenge&lt;/strong&gt;. Please use it responsibly. Personally, I believe if you're using a work or company-issued computer — especially as a software engineer — it's acceptable to store TOTP secrets locally for convenience, as long as your device is secured. Relying solely on a phone with many apps also carries potential risks.&lt;/p&gt;

&lt;p&gt;👨‍💻 Built by &lt;a href="https://github.com/longphanquangminh" rel="noopener noreferrer"&gt;longphanquangminh&lt;/a&gt; and &lt;strong&gt;Amazon Q Developer&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>awschallenge</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Implementing authorization for a Web3-based CMS</title>
      <dc:creator>Long Phan</dc:creator>
      <pubDate>Mon, 05 May 2025 06:54:25 +0000</pubDate>
      <link>https://dev.to/minhlong2605/implementing-authorization-for-a-web3-based-cms-2fk1</link>
      <guid>https://dev.to/minhlong2605/implementing-authorization-for-a-web3-based-cms-2fk1</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/permit_io"&gt;Permit.io Authorization Challenge&lt;/a&gt;: Permissions Redefined&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I built a Web3-based CMS (Content Management System) designed for managing decentralized content like collections, banners, presale campaigns, and other on-chain/off-chain data. The CMS provides an admin dashboard where team members can log in using their crypto wallets and manage the platform’s content in a more structured and user-friendly way.&lt;/p&gt;

&lt;p&gt;The key problem it solves is the lack of permission control in many Web3 tools. Typically, dApps allow wallet login but don’t differentiate between users. In my CMS, I introduced fine-grained access control so that different roles (e.g., admin, content editor, viewer/analyst) have access only to the features relevant to them. This improves security, collaboration, and overall project maintainability — especially in teams working on Web3 marketplaces, launchpads, or NFT collections.&lt;/p&gt;

&lt;p&gt;By combining decentralized login with centralized permission logic, the CMS balances Web3 principles with real-world admin needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&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%2Fa8aweko7hdjxcdg7n73b.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%2Fa8aweko7hdjxcdg7n73b.png" alt="Demo" width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live page: &lt;a href="https://web3-cms-app.vercel.app" rel="noopener noreferrer"&gt;https://web3-cms-app.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Theoretical Authorization Workflow: &lt;a href="https://tinyurl.com/web3-cms-mermaid" rel="noopener noreferrer"&gt;Mermaid link&lt;/a&gt; - supported by Tempo 😂&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Project Repo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Github repository: &lt;a href="https://github.com/longphanquangminh/web3-cms-fe" rel="noopener noreferrer"&gt;https://github.com/longphanquangminh/web3-cms-fe&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My Journey
&lt;/h2&gt;

&lt;p&gt;When I started building a Web3 CMS, one of the core features I knew I needed was authorization. Since the app relies on wallet-based authentication, I couldn’t use traditional username/password systems or standard backend session management. Instead, I had to find a way to manage access control in a decentralized environment — where users log in with wallets and identities aren't stored in a typical user table.&lt;/p&gt;

&lt;p&gt;I used &lt;a href="https://tempo.new" rel="noopener noreferrer"&gt;Tempo&lt;/a&gt; to quickly generate the UI, so I could focus on implementing authorization and integrating with services like Permit.io and Web3Auth.&lt;/p&gt;

&lt;p&gt;To solve the wallet login part, I integrated &lt;a href="https://web3auth.io" rel="noopener noreferrer"&gt;Web3Auth&lt;/a&gt;, which provides a seamless wallet-based login experience. I chose to keep the social login options (like Google or Facebook) out of view via CSS, so users interact with the app purely through wallet connections. Web3Auth still handles the heavy lifting behind the scenes and gives me a consistent way to identify users — whether they connect through &lt;a href="https://metamask.io" rel="noopener noreferrer"&gt;MetaMask&lt;/a&gt; or other supported wallets.&lt;/p&gt;

&lt;p&gt;My goal was to support roles like "admin", "editor", and "viewer", and ensure that each role had access to the appropriate parts of the CMS. For example, only admins should be able to manage collections or settings, while editors might only be able to modify content. It sounds simple, but handling this securely and flexibly in a Web3 setup required some research.&lt;/p&gt;

&lt;p&gt;I faced a few challenges along the way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mapping wallet addresses to roles&lt;/strong&gt; without a central user database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enforcing access rules on both frontend and backend&lt;/strong&gt; (especially when much of the logic lives client-side).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keeping the system flexible&lt;/strong&gt; enough to add more roles or change rules without constantly redeploying code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Using Permit.io for Authorization
&lt;/h2&gt;

&lt;p&gt;After evaluating a few options, I decided to use &lt;a href="https://www.permit.io" rel="noopener noreferrer"&gt;Permit.io&lt;/a&gt; to handle authorization. What I liked about Permit.io was that it gave me a way to define roles, resources, and actions externally — separate from my app logic. This separation made it easier to manage permissions over time and adapt as my CMS evolved.&lt;/p&gt;

&lt;p&gt;I used Permit.io’s CLI to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define resource (like &lt;code&gt;content&lt;/code&gt;) and actions (&lt;code&gt;read&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;, &lt;code&gt;create&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Create roles (&lt;code&gt;admin&lt;/code&gt;, &lt;code&gt;editor&lt;/code&gt;, &lt;code&gt;viewer&lt;/code&gt;) and associate them with policies.&lt;/li&gt;
&lt;li&gt;Assign policies to wallet addresses based on user roles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the app side, I integrated Permit.io’s SDK to check whether a user is authorized before allowing them to perform certain actions. For example, when a user submits a form to update content, I run a permission check to ensure they're allowed to update the &lt;code&gt;content&lt;/code&gt; resource before proceeding.&lt;/p&gt;

&lt;p&gt;This made the authorization logic easy to follow and more secure, since decisions were centralized and clearly defined. It also helped me avoid scattering hardcoded role checks throughout the app.&lt;/p&gt;

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

&lt;p&gt;Working on this helped me understand the importance of clean separation between authentication and authorization — especially in a decentralized context. Web3 introduces new identity patterns, and pairing them with a permission management system like Permit.io helped me build a more scalable and maintainable CMS.&lt;/p&gt;

&lt;p&gt;If you're building a dApp or Web3 admin tool that requires role-based access control, I recommend considering a similar setup. Having a proper authorization layer early on can save a lot of headaches as your app grows.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>permitchallenge</category>
      <category>webdev</category>
      <category>security</category>
    </item>
    <item>
      <title>🎮 Robot Recognition Game: Deploying the game to the web with Alibaba Cloud has never been easier</title>
      <dc:creator>Long Phan</dc:creator>
      <pubDate>Mon, 28 Apr 2025 06:58:44 +0000</pubDate>
      <link>https://dev.to/minhlong2605/robot-recognition-game-deploying-the-game-to-the-web-with-alibaba-cloud-has-never-been-easier-2cca</link>
      <guid>https://dev.to/minhlong2605/robot-recognition-game-deploying-the-game-to-the-web-with-alibaba-cloud-has-never-been-easier-2cca</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://int.alibabacloud.com/m/1000402443/" rel="noopener noreferrer"&gt;Alibaba Cloud&lt;/a&gt; Challenge: &lt;a href="https://dev.to/challenges/alibaba"&gt;Build a Web Game&lt;/a&gt;.&lt;/em&gt;*&lt;/p&gt;

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

&lt;p&gt;I developed a fun and engaging robot-themed game where players are shown images of different robots along with their names. The challenge is for users to memorize the robots and their corresponding names. Once they've had enough time, they must correctly identify the robot by name to progress to the next level. The game tests both memory and recognition skills in a playful and interactive way.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Live page: &lt;a href="http://game.robotrecognition.xyz" rel="noopener noreferrer"&gt;http://game.robotrecognition.xyz&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Replacement page (for backup purposes only): &lt;a href="https://robot-recognition-web-game.vercel.app" rel="noopener noreferrer"&gt;https://robot-recognition-web-game.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Github repository: &lt;a href="https://github.com/longphanquangminh/robot-recognition-web-game" rel="noopener noreferrer"&gt;https://github.com/longphanquangminh/robot-recognition-web-game&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🎯 The opening screen of the game application:&lt;br&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%2Fakhd2a3v8sgwutc8po37.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%2Fakhd2a3v8sgwutc8po37.png" alt="step0" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎯 The robot name memorization stage at the level:&lt;br&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%2Fpur8tzoa0csn9g52bnvz.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%2Fpur8tzoa0csn9g52bnvz.png" alt="step1" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎯 The step to choose the correct character name that matches the provided image:&lt;br&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%2Fnnm2jj4p3wz9cia6anw3.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%2Fnnm2jj4p3wz9cia6anw3.png" alt="step2" width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎯 Game Over – Better Luck Next Time:&lt;br&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%2F0lnrvrn1thj3f4ar4q7s.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%2F0lnrvrn1thj3f4ar4q7s.png" alt="step3" width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎯 Leaderboard – Showcasing Players with Top Memory Skills:&lt;br&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%2Fknfi8450a4i8ke1x7upr.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%2Fknfi8450a4i8ke1x7upr.png" alt="step4" width="800" height="657"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Alibaba Cloud Services Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Elastic Compute Service (ECS)
&lt;/h3&gt;

&lt;p&gt;My Robot Recognition Game is hosted on Alibaba Cloud's ECS, providing several key benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance : ECS instances deliver consistent, low-latency performance crucial for my memory-based game mechanics&lt;/li&gt;
&lt;li&gt;Scalability : Easy vertical and horizontal scaling capabilities to handle increased user load&lt;/li&gt;
&lt;li&gt;Cost-Effective : Pay-as-you-go pricing model ideal for my game's hosting needs&lt;/li&gt;
&lt;li&gt;Reliability : High availability with 99.975% SLA ensuring stable game access&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Integration
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Deploy directly via Alibaba Cloud ECS Console&lt;/li&gt;
&lt;li&gt;Use static build from Vite (npm run build)&lt;/li&gt;
&lt;li&gt;Manage instance through Alibaba Cloud dashboard&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Benefits
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Simplified deployment process&lt;/li&gt;
&lt;li&gt;Excellent uptime metrics&lt;/li&gt;
&lt;li&gt;Global accessibility with low latency&lt;/li&gt;
&lt;li&gt;Cost-effective hosting solution&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Challenges &amp;amp; Solutions
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Initial setup learning curve&lt;/li&gt;
&lt;li&gt;Resolved through comprehensive documentation&lt;/li&gt;
&lt;li&gt;Fine-tuned server configurations for optimal performance&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Object Storage Service (OSS)
&lt;/h3&gt;

&lt;p&gt;My Robot Recognition Game leverages Alibaba Cloud's Object Storage Service (OSS) for storing and serving image assets, providing several key benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance: OSS ensures fast and reliable access to robot images, critical for seamless game rendering during memorization and guessing stages&lt;/li&gt;
&lt;li&gt;Scalability: Automatically scales to handle growing numbers of image assets as the game expands with new levels or robot types&lt;/li&gt;
&lt;li&gt;Cost-Effective: Pay-as-you-go pricing model aligns with the game’s asset storage needs, minimizing costs for static content.&lt;/li&gt;
&lt;li&gt;Global Accessibility: OSS’s distributed architecture enables low-latency image delivery to players worldwide&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Integration
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Configured an OSS bucket via the Alibaba Cloud OSS Console to store robot image files&lt;/li&gt;
&lt;li&gt;Uploaded image assets (e.g., PNG files for robots) using the OSS web interface or SDK, ensuring proper naming conventions for easy retrieval&lt;/li&gt;
&lt;li&gt;Integrated OSS URLs into the game’s frontend (built with Vite) to dynamically load images during gameplay&lt;/li&gt;
&lt;li&gt;Set appropriate access permissions (public read-only) to allow secure image access without exposing sensitive data.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Benefits
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Simplified asset management with a centralized storage solution&lt;/li&gt;
&lt;li&gt;High reliability and uptime for image assets, ensuring consistent gameplay&lt;/li&gt;
&lt;li&gt;Reduced load on the hosting server by offloading static content to OSS&lt;/li&gt;
&lt;li&gt;Low-latency image loading for players across different regions&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Challenges &amp;amp; Solutions
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Initial learning curve in configuring OSS bucket settings and permissions&lt;/li&gt;
&lt;li&gt;Resolved by leveraging Alibaba Cloud’s detailed OSS documentation and tutorials&lt;/li&gt;
&lt;li&gt;Optimized image file sizes before uploading to OSS to balance quality and loading speed&lt;/li&gt;
&lt;li&gt;Implemented error handling in the frontend to gracefully manage any temporary OSS access issues&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Content Delivery Network (CDN)
&lt;/h3&gt;

&lt;p&gt;Alibaba Cloud’s CDN powers the delivery of images for my Robot Recognition Game, ensuring players get fast, seamless access to visuals no matter where they are. It’s been a game-changer for keeping load times snappy and the experience smooth.&lt;/p&gt;

&lt;h4&gt;
  
  
  Integration
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Purchase: Activate the CDN service through Alibaba Cloud’s CDN Console with a few clicks to get started.&lt;/li&gt;
&lt;li&gt;Configure: Add the game’s domain to the CDN, set up caching rules for images (like PNGs and JPEGs), and link it to my ECS instance or Object Storage Service (OSS) as the origin server.&lt;/li&gt;
&lt;li&gt;Use: Test the accelerated domain to confirm images load quickly from nearby edge nodes, then roll it out for players.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Benefits
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Dead-simple setup with a clean console to manage everything.&lt;/li&gt;
&lt;li&gt;Images load crazy fast thanks to over 3,200 global edge nodes.&lt;/li&gt;
&lt;li&gt;Saves bandwidth costs by caching images closer to players.&lt;/li&gt;
&lt;li&gt;Built-in protections like HTTPS and DDoS defense keep things secure.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Domain Name Service (DNS)
&lt;/h3&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%2F91k4ieipjaji2fft4y69.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%2F91k4ieipjaji2fft4y69.png" alt="domain" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alibaba Cloud’s DNS service keeps the domain for my Robot Recognition Game running smoothly, ensuring players can access it without hiccups. It’s been a solid choice for managing domain resolution with minimal fuss.&lt;/p&gt;

&lt;h4&gt;
  
  
  Integration
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Purchase: Head to Alibaba Cloud’s Domain Name Registration page, search for a domain name, and pick an available one that fits the game&lt;/li&gt;
&lt;li&gt;Configure: Set up DNS records (like A or CNAME) in the DNS management panel to link it to my ECS instance&lt;/li&gt;
&lt;li&gt;Use: Activate the domain, test it to confirm it’s resolving correctly, and watch it route traffic to the game&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Benefits
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Super straightforward to manage everything in one clean dashboard&lt;/li&gt;
&lt;li&gt;Fast resolution times keep the game accessible no matter where players are&lt;/li&gt;
&lt;li&gt;Built-in security perks, like DDoS protection, add peace of mind&lt;/li&gt;
&lt;li&gt;Pricing is clear and doesn’t break the bank 💰&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Price Calculator
&lt;/h3&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%2Fp9i6peaw3ekt5rhkcj4f.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%2Fp9i6peaw3ekt5rhkcj4f.png" alt="cal_1" width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alibaba Cloud’s Price Calculator has been a clutch tool for practicing budget planning for my Robot Recognition Game. It lets me estimate costs for services like ECS, DNS, and CDN before locking in, so I can experiment with different setups and keep expenses in check.&lt;/p&gt;

&lt;h4&gt;
  
  
  Benefits
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Super intuitive interface to mix and match services for cost estimates.&lt;/li&gt;
&lt;li&gt;Breaks down pricing clearly, so I know exactly what I’m paying for.&lt;/li&gt;
&lt;li&gt;Saves time by letting me tweak configurations without digging through docs.&lt;/li&gt;
&lt;li&gt;Includes a share function to export estimates as a link or file, making it easy to discuss plans with the team.&lt;/li&gt;
&lt;/ol&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%2Fk5r9pd97pilhgdpy8xep.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%2Fk5r9pd97pilhgdpy8xep.png" alt="cal_2" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Game Development Highlights
&lt;/h2&gt;

&lt;p&gt;📌 &lt;strong&gt;Advanced State Management&lt;/strong&gt;: Implemented a robust state machine pattern using TypeScript enums (Idle, Preview, Guess, GameOver) for clear game flow control.&lt;/p&gt;

&lt;p&gt;📌 &lt;strong&gt;Dynamic Difficulty Scaling&lt;/strong&gt;: Created an engaging progression system that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Starts with ~3 robots at level 1 (based on the number of robots in defined data)&lt;/li&gt;
&lt;li&gt;Incrementally adds more robots&lt;/li&gt;
&lt;li&gt;Implements Fisher-Yates shuffle for true randomization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📌 &lt;strong&gt;Progressive UI/UX&lt;/strong&gt;: Custom progress bar component providing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visual countdown feedback&lt;/li&gt;
&lt;li&gt;Smooth animations&lt;/li&gt;
&lt;li&gt;Responsive design&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📌 &lt;strong&gt;Persistent Leaderboard System&lt;/strong&gt;: Implemented local storage-based leaderboard featuring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Persistent score tracking&lt;/li&gt;
&lt;li&gt;Automatic sorting&lt;/li&gt;
&lt;li&gt;Clean data structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📌 &lt;strong&gt;Smart Scoring Algorithm&lt;/strong&gt;: Designed an engaging scoring system with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Level-based point multiplication&lt;/li&gt;
&lt;li&gt;Automatic difficulty progression&lt;/li&gt;
&lt;li&gt;Balanced reward structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These technical implementations create an engaging, challenging, and fair gaming experience while maintaining clean, maintainable code architecture.&lt;/p&gt;

</description>
      <category>alibabachallenge</category>
      <category>devchallenge</category>
      <category>gamedev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Github Milestone Motivator: An innovative idea from Pulumi intriguing challenge 🏆</title>
      <dc:creator>Long Phan</dc:creator>
      <pubDate>Mon, 07 Apr 2025 06:57:17 +0000</pubDate>
      <link>https://dev.to/minhlong2605/github-milestone-motivator-an-innovative-idea-from-pulumi-intriguing-challenge-ej2</link>
      <guid>https://dev.to/minhlong2605/github-milestone-motivator-an-innovative-idea-from-pulumi-intriguing-challenge-ej2</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/pulumi"&gt;Pulumi Deploy and Document Challenge&lt;/a&gt;: Get Creative with Pulumi and GitHub&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Managing GitHub milestones can be a tedious task, especially when it comes to tracking progress and keeping teams motivated. The "GitHub Milestone Motivator" is a creative solution built with Pulumi and the GitHub API to automate this process. It tracks milestone progress across repositories, posts encouraging comments on open issues (e.g., "Halfway there at 50%!") when progress hits key thresholds (25%, 50%, 75%, 100%), and assigns a "Milestone Star" label when a milestone is fully completed. Using Pulumi’s Automation API, this tool simplifies repository management and boosts team morale with minimal effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  Live Demo Link
&lt;/h2&gt;

&lt;p&gt;Demo link:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/demo-longphan/frontend" rel="noopener noreferrer"&gt;https://github.com/demo-longphan/frontend&lt;/a&gt; (my tested repo before publishing this submission)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/demo-longphan/smart-contract" rel="noopener noreferrer"&gt;https://github.com/demo-longphan/smart-contract&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Project Repo
&lt;/h2&gt;

&lt;p&gt;Github repository: &lt;a href="https://github.com/longphanquangminh/creative-pulumi-github-contest" rel="noopener noreferrer"&gt;https://github.com/longphanquangminh/creative-pulumi-github-contest&lt;/a&gt; (Including complete README documentation)&lt;/p&gt;

&lt;h2&gt;
  
  
  My Journey
&lt;/h2&gt;

&lt;p&gt;Before proceeding with the implementation, I drafted a business logic diagram as follows:&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%2Fv45x26la9xo7la3q2g4d.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%2Fv45x26la9xo7la3q2g4d.png" alt="Logic" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Explaination: When the program is executed, it will scan all the repositories defined by the user. For each repository, it will check its milestones, and within each milestone, it will examine the related issues. There are two possible scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the milestone is not completed yet, the program will check the progress percentage. Based on the percentage (25%, 50%, 75%, or 100%), it will display an encouraging message accordingly.&lt;/li&gt;
&lt;li&gt;If the milestone is 100% complete, a congratulatory comment will be added by the manager to the representative issue (the last issue) to celebrate the team’s success.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn’t just my story — it’s an instruction manual for anyone on a similar journey. To apply these lessons effectively in a management context, follow the steps below:&lt;/p&gt;

&lt;p&gt;👣 &lt;strong&gt;Step 1&lt;/strong&gt;: Create a milestone in the repository (Go to Repo -&amp;gt; click Issues -&amp;gt; click Milestone tag to create.&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%2F2h2fp1g8pxvzplvkunrj.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%2F2h2fp1g8pxvzplvkunrj.png" alt="Step1" width="800" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👣 &lt;strong&gt;Step 2&lt;/strong&gt;: Once the milestone is created, start working on the project. There will be tasks/issues — when creating them, make sure to tag them with the corresponding milestone.&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%2Fiu6wvhg2pt12fe94ia6m.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%2Fiu6wvhg2pt12fe94ia6m.png" alt="Step2" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👣 &lt;strong&gt;Step 3&lt;/strong&gt;: After creating an issue/task, typically following the SDLC (Software Development Life Cycle), we will start coding or fixing bugs for those features. Once completed, we simply close the issue and move on to the next one.&lt;br&gt;
In this demo, I will only create one issue.&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%2Fpu0i8df0guss6vcyr74m.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%2Fpu0i8df0guss6vcyr74m.png" alt="Step3" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👣 &lt;strong&gt;Step 4&lt;/strong&gt;: Run "npm run dev" and wait for the result.&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%2Fgjzpvwvlkc2ha1kc1p80.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%2Fgjzpvwvlkc2ha1kc1p80.png" alt="Step4" width="800" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the image, the comment has been created and a label has been assigned to highlight the issue and boost the morale of software engineers.&lt;br&gt;
With this setup, managers no longer need to manually go through each step via the UI — the tool already contains the necessary logic. Just by running a single command, it will execute everything automatically.&lt;/p&gt;




&lt;p&gt;While building the "GitHub Milestone Motivator" with Pulumi, I hit a roadblock: the GitHub Provider doesn’t support &lt;strong&gt;IssueComment&lt;/strong&gt;. I wanted to post motivational messages on issues to track milestone progress, so I turned to Octokit to fill the gap. Integrating Octokit let me add comments like "Halfway there at 50%!" directly to issues, bypassing Pulumi’s limitation. The challenge was finding a clean way to weave this into my workflow, but once I got it working, I learned how powerful it is to combine Pulumi’s infrastructure management with Octokit’s flexibility for dynamic GitHub interactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Pulumi with GitHub
&lt;/h2&gt;

&lt;p&gt;In the "GitHub Milestone Motivator," I used Pulumi to declaratively manage GitHub repositories and create the "Milestone Star" label when a milestone hits 100%. By leveraging Pulumi’s Automation API, I automated resource provisioning in a repeatable, code-driven way. This was beneficial because it ensured consistent setup across runs, simplified tracking of infrastructure state, and let me focus on the logic rather than manual API calls. While Pulumi couldn’t handle issue comments due to the missing &lt;strong&gt;IssueComment&lt;/strong&gt; resource, its strength in managing static resources paired perfectly with Octokit for dynamic actions.&lt;/p&gt;

&lt;p&gt;📣 &lt;strong&gt;Dev Community&lt;/strong&gt; shared this on X – 3,770+ views as of April 2025: &lt;a href="https://x.com/ThePracticalDev/status/1911621746974679521" rel="noopener noreferrer"&gt;https://x.com/ThePracticalDev/status/1911621746974679521&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>pulumichallenge</category>
      <category>github</category>
      <category>api</category>
    </item>
    <item>
      <title>SSS Portfolio: A Developer’s Digital Showcase ✨</title>
      <dc:creator>Long Phan</dc:creator>
      <pubDate>Mon, 24 Mar 2025 05:58:58 +0000</pubDate>
      <link>https://dev.to/minhlong2605/sss-portfolio-a-developers-digital-showcase-1h22</link>
      <guid>https://dev.to/minhlong2605/sss-portfolio-a-developers-digital-showcase-1h22</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/kendoreact"&gt;KendoReact Free Components Challenge&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;SSS (stands for Super-Simple-Sample) Portfolio is my personal developer portfolio, built using 10 components from Kendo React to create a sleek and interactive experience.&lt;/p&gt;

&lt;p&gt;It includes the following sections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Intro&lt;/strong&gt;: A dynamic opening with animations featuring my name and position.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;About&lt;/strong&gt;: A brief introduction to who I am.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills&lt;/strong&gt;: A showcase of my technical expertise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Projects&lt;/strong&gt;: Highlights of my key development work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contact&lt;/strong&gt;: A simple way to reach out to me.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This portfolio reflects my skills and design approach while leveraging Kendo React to deliver a smooth UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Live page: &lt;a href="https://new-contest-portfolio.vercel.app" rel="noopener noreferrer"&gt;https://new-contest-portfolio.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Github repository: &lt;a href="https://github.com/longphanquangminh/new-contest-portfolio" rel="noopener noreferrer"&gt;https://github.com/longphanquangminh/new-contest-portfolio&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🎉 Intro:&lt;/strong&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%2Ft6g4cuvu3wg9ngq3w5ta.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%2Ft6g4cuvu3wg9ngq3w5ta.png" alt="Intro" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When hovering over the image, it animates with a pixel effect and displays my position:&lt;br&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%2Fr0ee3hbdmzi61kbg8lhp.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%2Fr0ee3hbdmzi61kbg8lhp.png" alt="PictureEffect" width="800" height="770"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🎉 Popup message&lt;/strong&gt;:&lt;br&gt;
When scrolling down, a pop-up message appears, allowing users to interact with me on LinkedIn without needing to scroll all the way to the Contact section. Users can close the pop-up by clicking the icon on the right.&lt;br&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%2Fliy0rl6wqgn006nsio36.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%2Fliy0rl6wqgn006nsio36.png" alt="Popup message" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🎉 About and Skills&lt;/strong&gt;:&lt;br&gt;
There will be a slight animation for the progress bars when scrolling to them.&lt;br&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%2Fewzogjd2kzxtxbk2s7pc.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%2Fewzogjd2kzxtxbk2s7pc.png" alt="About and Skills" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🎉 Projects:&lt;/strong&gt;&lt;br&gt;
Header for &lt;strong&gt;Projects&lt;/strong&gt; section:&lt;br&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%2F2g5aitdlsztp359y7g71.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%2F2g5aitdlsztp359y7g71.png" alt="Projects" width="800" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project cards will have a sticky effect and stack on top of each other. Recruiters can view project details and access either the live site or the documentation (similar to a whitepaper).&lt;br&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%2Fyyokr9ltfd7u5ottwmv5.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%2Fyyokr9ltfd7u5ottwmv5.png" alt="ProjectsCardEffect" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🎉 Contact and Footer:&lt;/strong&gt;&lt;br&gt;
This section only includes the contact area with a remix-style effect, a slider for interactive playground purposes, and a footer to display additional information about the project and the technologies used.&lt;br&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%2F8kcmyl902fjfkt8qen5q.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%2F8kcmyl902fjfkt8qen5q.png" alt="Contact and Footer" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  KendoReact Experience
&lt;/h2&gt;

&lt;p&gt;I built a sleek portfolio by experiencing and leveraging the following 10 free high-quality components from Kendo React:&lt;br&gt;
🧩 &lt;strong&gt;AppBar&lt;/strong&gt;: Used for navigation at the top of the page.&lt;br&gt;
🧩 &lt;strong&gt;Avatar&lt;/strong&gt;: Displays my profile picture in the pop-up message section.&lt;br&gt;
🧩 &lt;strong&gt;Badge + BadgeContainer&lt;/strong&gt;: Used to attach a badge to the avatar—I added a blue checkmark to indicate that I’m a verified applicant.&lt;br&gt;
🧩 &lt;strong&gt;Button&lt;/strong&gt;: Navigation buttons placed in the AppBar.&lt;br&gt;
🧩 &lt;strong&gt;FloatingActionButton&lt;/strong&gt;: Used for other buttons on the page. I know that a Floating Action Button is typically a fixed-position CTA button to keep it accessible throughout the user experience, but since it has a clean UI and a large, clear design, I used it as a button with a position: relative value in different sections of my portfolio.&lt;br&gt;
🧩 &lt;strong&gt;Typography&lt;/strong&gt;: Displays text on the page.&lt;br&gt;
🧩 &lt;strong&gt;SvgIcon + Kendo React icon set&lt;/strong&gt;: Enhances the visual appeal of interactive elements on the page.&lt;br&gt;
🧩 &lt;strong&gt;ProgressBar&lt;/strong&gt;: Shows my proficiency levels for different skills—this is a creative way to use a ProgressBar beyond just indicating loading states.&lt;br&gt;
🧩 &lt;strong&gt;Fade animation&lt;/strong&gt;: Adds a dynamic effect to my name in the contact section near the footer—this idea was inspired by remix music videos from my country (or maybe from other places too, I guess).&lt;br&gt;
🧩 &lt;strong&gt;Slider&lt;/strong&gt;: Adjusts the scrolling speed of the text mentioned above—I treated it as a mini playground for users to experiment with.&lt;/p&gt;

&lt;p&gt;I originally planned to use the Pie Chart component to display my LeetCode stats from API response, but since it’s a premium component and to save time, I decided to skip it for now.&lt;/p&gt;

&lt;h3&gt;
  
  
  AIm to Impress
&lt;/h3&gt;

&lt;p&gt;My idea is to use AI to learn about my data/information and integrate a live chat section with this AI so that recruiters can chat as if they were talking directly to me. They could ask what I’m capable of, what roles I’m suitable for, my weaknesses, and how I solve specific problems—helping them gain accurate and quick insights about me.&lt;/p&gt;

&lt;p&gt;However, due to time constraints (since I found out about the challenge quite late), I didn’t integrate AI into this project and am not applying for this award.&lt;/p&gt;

&lt;h3&gt;
  
  
  Delightfully Designed
&lt;/h3&gt;

&lt;p&gt;I’m not applying for this category since I only leveraged the UI and logic of the components to build this portfolio without using the theme. My main goal is to win the "Prompt Winner" award 🏆&lt;/p&gt;

&lt;p&gt;Thank you for reading my post! If you have any thoughts or feedback about the project, feel free to leave a comment below. I’m always open to suggestions and eager to learn from talented developers/engineers to enhance my value.&lt;/p&gt;

&lt;p&gt;P/s: We don’t need to know who created the design system or how long it has existed. As long as the UI is well-designed (and logically structured), we, as FE Engineers, will create the most outstanding products.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I don’t chase perfection, it follows me – Long Phan&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;🚀 This blog was highlighted on X by Dev Community: &lt;a href="https://x.com/The_React_Dev/status/1904931099626647768" rel="noopener noreferrer"&gt;https://x.com/The_React_Dev/status/1904931099626647768&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>kendoreactchallenge</category>
      <category>react</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
