<?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: Limani Ndou</title>
    <description>The latest articles on DEV Community by Limani Ndou (@limani).</description>
    <link>https://dev.to/limani</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3732979%2F49dd130b-fd29-4355-8a6e-a18ea57c6e06.png</url>
      <title>DEV Community: Limani Ndou</title>
      <link>https://dev.to/limani</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/limani"/>
    <language>en</language>
    <item>
      <title>Building a receipt-scanning budget tracker with Amazon Bedrock, Lambda, and DynamoDB</title>
      <dc:creator>Limani Ndou</dc:creator>
      <pubDate>Fri, 04 Sep 2026 16:16:26 +0000</pubDate>
      <link>https://dev.to/limani/building-a-receipt-scanning-budget-tracker-with-amazon-bedrock-lambda-and-dynamodb-4fg8</link>
      <guid>https://dev.to/limani/building-a-receipt-scanning-budget-tracker-with-amazon-bedrock-lambda-and-dynamodb-4fg8</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fexihrf9nr1vof1lktwmd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fexihrf9nr1vof1lktwmd.jpg" alt=" " width="800" height="447"&gt;&lt;/a&gt;---&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem I Kept Ignoring
&lt;/h2&gt;

&lt;p&gt;Every week, the same small annoyance played out: I'd snap a photo of a receipt, tell myself I'd log it later, and then completely forget. By the time I got around to reviewing my spending usually at the end of the month I'd already blown past a budget category without knowing it. Even when I did log expenses manually, I'd misclassify them, which quietly made my "budget tracking" useless.&lt;/p&gt;

&lt;p&gt;I didn't need another finance app with fifty features I'd never touch. I needed one thing done well: &lt;strong&gt;upload a receipt, get an instant answer on whether I'm still within budget.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's what I built. It's called &lt;strong&gt;BudgetSnap&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbpce28kuh6cnll66hcac.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbpce28kuh6cnll66hcac.png" alt=" " width="767" height="842"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What BudgetSnap Actually Does
&lt;/h2&gt;

&lt;p&gt;BudgetSnap is intentionally narrow in scope, and that's the point. The entire flow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upload a receipt image or PDF.&lt;/li&gt;
&lt;li&gt;Automatically extract the merchant, date, subtotal, tax, total, and category.&lt;/li&gt;
&lt;li&gt;Store the entry in a database.&lt;/li&gt;
&lt;li&gt;Compare the new spend against that category's budget limit.&lt;/li&gt;
&lt;li&gt;Return a clear, immediate status over budget or within budget with practical advice.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No end-of-month surprises. No manual spreadsheet updates. Just upload and know.&lt;/p&gt;

&lt;p&gt;On the UI side, I kept things lightweight but functional:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A responsive single-page interface that works on desktop and mobile.&lt;/li&gt;
&lt;li&gt;A budget period selector (week/month).&lt;/li&gt;
&lt;li&gt;A category override selector for when the AI gets it wrong.&lt;/li&gt;
&lt;li&gt;Editable budget limits per category.&lt;/li&gt;
&lt;li&gt;Real-time result cards showing spend status the moment a receipt is processed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How I Built It on AWS
&lt;/h2&gt;

&lt;p&gt;I built this incrementally so I always had something working, even as I layered in more capability.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Frontend — plain HTML, CSS, and JavaScript
&lt;/h3&gt;

&lt;p&gt;I skipped frameworks entirely to keep setup minimal and deployment fast. The frontend supports drag-and-drop uploads, a manual file picker, category budgeting controls, and a responsive layout.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. AI extraction — Amazon Bedrock (Nova models)
&lt;/h3&gt;

&lt;p&gt;This is the core intelligence of the app. I enabled model access in Amazon Bedrock and used a Nova model to read the receipt content and return structured fields merchant, date, totals, category that the rest of the pipeline can store and evaluate.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Data layer — Amazon DynamoDB
&lt;/h3&gt;

&lt;p&gt;Two tables power the app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;expenses&lt;/code&gt; — processed receipt entries.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;budgets&lt;/code&gt; — category limits.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h3&gt;
  
  
  4. Processing logic — a receipt processor AWS Lambda function
&lt;/h3&gt;

&lt;p&gt;It:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Receives the upload context.&lt;/li&gt;
&lt;li&gt;Extracts receipt data (via the Bedrock path, or a fallback path more on that below).&lt;/li&gt;
&lt;li&gt;Looks up the relevant budget limit.&lt;/li&gt;
&lt;li&gt;Computes spend-before, spend-after, and any over-budget amount.&lt;/li&gt;
&lt;li&gt;Writes the final expense row to DynamoDB.&lt;/li&gt;
&lt;li&gt;Returns normalized JSON back to the UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5hwlir4xnbs5ncd380gh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5hwlir4xnbs5ncd380gh.png" alt=" " width="800" height="513"&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F04kfghzviltfwrloycm7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F04kfghzviltfwrloycm7.png" alt=" " width="800" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. API layer — an upload Lambda behind Amazon API Gateway
&lt;/h3&gt;

&lt;p&gt;It accepts multipart uploads from the browser, stores the file in Amazon S3, invokes the processor Lambda, and relays the processed result back to the frontend.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  6. Event wiring — Amazon S3 triggers
&lt;/h3&gt;

&lt;p&gt;Tested end-to-end from upload through to the final budget status response.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  AWS Services Used
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon S3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stores uploaded receipt files and triggers processing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Lambda&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Runs the upload handler and the receipt processor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon API Gateway (HTTP API)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Exposes the upload endpoint to the frontend&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon DynamoDB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stores budgets and processed expense entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon Bedrock (Nova models)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Performs receipt understanding and categorization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon CloudWatch Logs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Debugging and operational visibility across the pipeline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Architecture Flow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;User uploads an image or PDF from the web app.&lt;/li&gt;
&lt;li&gt;API Gateway routes the request to the Upload Lambda.&lt;/li&gt;
&lt;li&gt;Upload Lambda writes the file to S3.&lt;/li&gt;
&lt;li&gt;The Processor Lambda runs using the S3 context.&lt;/li&gt;
&lt;li&gt;The processor checks budget data in DynamoDB.&lt;/li&gt;
&lt;li&gt;The processor writes the new expense entry to DynamoDB.&lt;/li&gt;
&lt;li&gt;The API returns budget status and advice back to the frontend all in one response payload.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F90z720vvj6iunhk19g26.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F90z720vvj6iunhk19g26.png" alt=" " width="800" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;A focused scope beats a broad scope.&lt;/strong&gt; By solving one annoying, recurring task really well, I ended up with a fully deployed, genuinely useful app instead of a half-finished feature list.&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical takeaways
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Apply least-privilege IAM policies and validate permissions early across Lambda, S3, API Gateway, and DynamoDB, this saved me from several silent failures later.&lt;/li&gt;
&lt;li&gt;Amazon CloudWatch Logs is the backbone of debugging serverless workflows. Without it, tracing failures across a multi-Lambda pipeline would have been guesswork.&lt;/li&gt;
&lt;li&gt;Standardizing request/response schemas across frontend and backend made integration, testing, and iteration dramatically simpler.&lt;/li&gt;
&lt;li&gt;Keeping the architecture lightweight and modular made the app easy to deploy, maintain, and extend.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Product takeaways
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Instant feedback is what users actually value in a budgeting tool not more data, faster answers.&lt;/li&gt;
&lt;li&gt;Over-budget nudges land better when they're short and practical, not verbose.&lt;/li&gt;
&lt;li&gt;Reducing user effort upload once, get an automatic budget check is what drives real adoption.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub repo:&lt;/strong&gt; &lt;a href="https://github.com/limanindou/BudgetSnap" rel="noopener noreferrer"&gt;github.com/limanindou/BudgetSnap&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Building BudgetSnap reminded me why serverless architectures are such a good fit for small, high-leverage tools like this: I could focus almost entirely on the &lt;em&gt;problem&lt;/em&gt; — accurate extraction, meaningful budget feedback instead of managing infrastructure. That's exactly the kind of building I want to keep doing.&lt;/p&gt;




&lt;p&gt;If you've built something similar with Bedrock or a serverless receipt/document pipeline, I'd love to hear how you approached extraction and fallback handling drop a comment below!&lt;/p&gt;

</description>
      <category>bedrock</category>
      <category>aws</category>
      <category>dynamodb</category>
      <category>s3</category>
    </item>
    <item>
      <title>🤖 Building an AI Compliance Assistant with Hugging Face, RAG &amp; Observability on AWS</title>
      <dc:creator>Limani Ndou</dc:creator>
      <pubDate>Sun, 23 Aug 2026 18:40:21 +0000</pubDate>
      <link>https://dev.to/limani/building-an-ai-compliance-assistant-with-hugging-face-rag-observability-on-aws-3gfc</link>
      <guid>https://dev.to/limani/building-an-ai-compliance-assistant-with-hugging-face-rag-observability-on-aws-3gfc</guid>
      <description>&lt;p&gt;I Built an AI Compliance Assistant That Runs Entirely on My Own GPU — Here's What I Learned&lt;/p&gt;

&lt;h3&gt;
  
  
  Combining RAG, local LLM inference, Terraform-provisioned AWS infrastructure, and full-stack observability to make South African financial regulation searchable
&lt;/h3&gt;




&lt;p&gt;If you've ever worked anywhere near banking compliance, you know the feeling: somewhere in a 200-page guidance note is the exact clause you need, and you have no idea which page it's on 📄🔍. South African financial institutions operate under a dense stack of regulation — AML, CTF, CPF, the FIC Act, cross-border EFT reporting, Prudential Authority requirements — and most of it lives in long, technical PDFs that don't search well.&lt;/p&gt;

&lt;p&gt;So I decided to build something that could actually &lt;em&gt;answer&lt;/em&gt; compliance questions, grounded in real regulatory text, running on infrastructure I control end to end 🛠️. No black-box SaaS API calls to a third-party model — the LLM inference happens locally, on my own GPU, provisioned entirely with &lt;strong&gt;Terraform&lt;/strong&gt; ⚙️, and I can watch every request move through the system in real time.&lt;/p&gt;

&lt;p&gt;This is the story of building &lt;strong&gt;Compliance RAG&lt;/strong&gt; 🤖: a Retrieval-Augmented Generation platform for South African regulatory intelligence, with local GPU inference, a vector database, infrastructure-as-code, and a full observability stack behind it.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 The Problem
&lt;/h2&gt;

&lt;p&gt;South African banks have to navigate obligations spanning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anti-Money Laundering (AML) and Counter-Terrorist Financing (CTF/CPF)&lt;/li&gt;
&lt;li&gt;Customer Due Diligence and risk-based approaches&lt;/li&gt;
&lt;li&gt;Cross-border electronic funds transfers and international reporting&lt;/li&gt;
&lt;li&gt;FIC Act implementation requirements&lt;/li&gt;
&lt;li&gt;Rules for representative offices of foreign banking institutions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A compliance officer might ask something like &lt;em&gt;"What information must a bank obtain when conducting customer due diligence?"&lt;/em&gt; — a completely reasonable question with an answer buried somewhere in a Guidance Note. Traditional keyword search either misses the context entirely or returns ten tangentially related pages 😩. What's actually needed is a system that understands the question, retrieves the &lt;em&gt;relevant&lt;/em&gt; passages, and answers using only what's actually in the source documents — no hallucinated legislation, no invented penalties.&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 The Solution: Retrieval-Augmented Generation, Self-Hosted
&lt;/h2&gt;

&lt;p&gt;The core idea behind RAG is simple: instead of asking a language model to answer from memory (where it might confidently make things up), you retrieve the most relevant chunks of real source documents first, and then ask the model to answer &lt;em&gt;using only that retrieved context&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Here's the pipeline I built:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PDF → Document Loader → Text Splitting → Embeddings → ChromaDB
    → Similarity Search → Relevant Regulatory Context → Gemma → Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Regulatory PDFs — the ML/TF/PF Sector Risk Assessment, Guidance Note 7B on the FIC Act, Guidance Note 8 on EFTs, and documentation on representative offices of foreign banks — are stored in an S3 "compliance document vault" 🪣, ingested, chunked, embedded, and stored in &lt;strong&gt;ChromaDB&lt;/strong&gt; for similarity search.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxd5h4xgsthgugxuluw3e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxd5h4xgsthgugxuluw3e.png" alt="S3 Bucket" width="799" height="333"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The regulatory document vault in S3 — each PDF is a primary source, ingested and re-embedded whenever it's updated.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When a question comes in, the system retrieves the most relevant chunks and passes them, along with the question, to a locally-hosted &lt;strong&gt;Google Gemma 2 2B IT&lt;/strong&gt; model for generation. I picked Gemma 2 2B specifically because it's small enough to run comfortably on a single GPU without breaking the bank, while still being capable enough to follow strict grounding instructions — exactly the tradeoff a self-hosted compliance tool needs 🎯. Running the model locally rather than calling an external API meant provisioning real GPU infrastructure.&lt;/p&gt;
&lt;h2&gt;
  
  
  🏗️ Provisioning It All With Terraform
&lt;/h2&gt;

&lt;p&gt;I didn't want to click around the AWS console to spin this up — I wanted it reproducible, versioned, and destroyable in one command. So every piece of AWS infrastructure — the GPU-enabled EC2 instance, the VPC, security groups, IAM roles, and the S3 bucket — is defined and deployed with &lt;strong&gt;Terraform&lt;/strong&gt; 🧱.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;infrastructure
terraform init
terraform plan
terraform apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One &lt;code&gt;terraform apply&lt;/code&gt; and I have a fully networked, GPU-ready EC2 instance with the right IAM permissions to talk to S3 — no manual setup, no configuration drift, and a clean &lt;code&gt;terraform destroy&lt;/code&gt; when I don't want to pay for idle GPU time 💸.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2jbmut1o89f36g9vjmwk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2jbmut1o89f36g9vjmwk.png" alt="EC2" width="800" height="180"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A &lt;code&gt;g5.xlarge&lt;/code&gt; EC2 instance with an NVIDIA A10G GPU — provisioned by Terraform, running 24/7, hosting the entire Dockerized stack.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🖥️ What It Looks Like in Practice
&lt;/h2&gt;

&lt;p&gt;The frontend is a React/Vite chat interface I called the "Enterprise Regulatory Advisor." I wanted answers that weren't just fluent-sounding text — they needed to cite exactly where in the source documents they came from, so a compliance officer could go verify it themselves in seconds ✅.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu31mbvlsp0mgaylqiz5c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu31mbvlsp0mgaylqiz5c.png" alt="UI" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Asking "What information must a bank obtain when conducting customer due diligence?" Notice the "AI Engine: Gemma-2 Active" status in the sidebar 🤖 — the model answers only from retrieved context, and — critically — flags when the source text doesn't specify something, rather than filling in the gap itself. Every answer comes with verified source references down to the page number.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That last detail mattered a lot to me. The system prompt explicitly instructs the model to avoid inventing legislation, requirements, penalties, or dates, and to say plainly when the answer isn't in the available documents. In a compliance context, a confident wrong answer is worse than no answer at all ⚠️.&lt;/p&gt;

&lt;h2&gt;
  
  
  📡 Watching the System Think: Observability
&lt;/h2&gt;

&lt;p&gt;Running your own LLM infrastructure means you can't just trust that it's "working" — you need to actually see what's happening under the hood 🔬. I instrumented the entire FastAPI backend with &lt;strong&gt;OpenTelemetry&lt;/strong&gt;, exporting traces and metrics through an OTEL Collector to &lt;strong&gt;Prometheus&lt;/strong&gt;, &lt;strong&gt;Grafana&lt;/strong&gt;, and &lt;strong&gt;Jaeger&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzc37v4kqm4ii0ha1b4ch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzc37v4kqm4ii0ha1b4ch.png" alt="Prometheus" width="800" height="385"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Prometheus querying metrics scraped from the OTEL Collector — request durations, active requests, histogram buckets, all labeled and queryable.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Prometheus gives me the raw metrics — request rates, latency histograms, active request counts 📊 — and Grafana turns those into dashboards I can actually read at a glance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftfxbhxm6fw4rrqjlvrlu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftfxbhxm6fw4rrqjlvrlu.png" alt="Grafana" width="800" height="424"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A live Grafana dashboard built on the Metrics Drilldown view — request duration buckets, throughput, and payload sizes updating in real time.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And when I need to understand &lt;em&gt;why&lt;/em&gt; a specific request was slow — was it the embedding step, the ChromaDB similarity search, or the Gemma generation itself? — Jaeger gives me the full distributed trace 🔎.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbiyrb77vcvywcqd6759n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbiyrb77vcvywcqd6759n.png" alt="Jaeger" width="800" height="422"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Jaeger tracing individual API calls through the RAG pipeline, down to the microsecond.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This turned what could have been a black box into something genuinely observable — I can see request rate, latency percentiles, GPU health, and trace-level detail on any single query.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧰 The Stack, End to End
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🐍 &lt;strong&gt;Backend:&lt;/strong&gt; Python, FastAPI, LangChain, ChromaDB, PyTorch, Hugging Face Transformers&lt;/li&gt;
&lt;li&gt;🤖 &lt;strong&gt;AI/ML:&lt;/strong&gt; Google Gemma 2 2B IT, local GPU inference on an NVIDIA A10G&lt;/li&gt;
&lt;li&gt;⚛️ &lt;strong&gt;Frontend:&lt;/strong&gt; React + Vite&lt;/li&gt;
&lt;li&gt;📈 &lt;strong&gt;Observability:&lt;/strong&gt; OpenTelemetry, Prometheus, Grafana, Jaeger&lt;/li&gt;
&lt;li&gt;☁️ &lt;strong&gt;Infrastructure:&lt;/strong&gt; AWS EC2 (GPU) + AWS S3, provisioned with &lt;strong&gt;Terraform&lt;/strong&gt;, containerized with Docker Compose, with Kubernetes/Helm manifests for scaling out&lt;/li&gt;
&lt;li&gt;🚀 &lt;strong&gt;CI/CD:&lt;/strong&gt; GitHub Actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything runs in Docker Compose for local/single-instance deployment, with a parallel Helm chart if I ever need to move this onto Kubernetes — and every underlying AWS resource traces back to a Terraform module, not a manual console click.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Grounding is everything.&lt;/strong&gt; 🎯 The hardest part wasn't wiring up the pipeline — it was getting the prompt-level guardrails right so the model would &lt;em&gt;refuse&lt;/em&gt; to speculate. A 2B parameter model is small enough to run affordably on a single GPU, but it also means you have to be deliberate about keeping it on a short leash: retrieved context in, grounded answer out, and an honest "not found" when the documents don't say.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Infrastructure-as-code pays for itself fast.&lt;/strong&gt; 🏗️ Provisioning the GPU instance, networking, and S3 vault with Terraform meant I could tear the whole environment down between sessions and bring it back identically an hour later — a huge win for both cost control and sanity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observability isn't optional once you self-host.&lt;/strong&gt; 🔭 The moment you're responsible for your own inference infrastructure, "is it working?" becomes a real question you need real tooling to answer. Watching a trace waterfall through embedding → retrieval → generation taught me more about where latency actually lives than any amount of guessing would have.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compliance AI has a very specific bar.&lt;/strong&gt; ⚖️ This project is explicitly &lt;em&gt;not&lt;/em&gt; a replacement for a compliance officer or legal advisor — the disclaimer sits front and center in the docs. The goal was never "trust the AI's judgment." It was "make the source material searchable, and always show your work."&lt;/p&gt;

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

&lt;p&gt;On the roadmap: hybrid search (BM25 + vector) with cross-encoder reranking, RAGAS-based evaluation for faithfulness and retrieval precision, regulatory change detection so the vault flags when a source document gets superseded, and proper enterprise auth via Cognito/OIDC before this goes anywhere near production data.&lt;/p&gt;

&lt;p&gt;If you're curious about the architecture or want to build something similar, the full project — Terraform configs, Helm charts, ingestion pipeline, and all — is open on GitHub. ⭐&lt;/p&gt;

&lt;p&gt;CODE: &lt;a href="https://github.com/limanindou/compliance-rag" rel="noopener noreferrer"&gt;https://github.com/limanindou/compliance-rag&lt;/a&gt;&lt;br&gt;
YOUTUBE DEMO PC:&lt;a href="https://youtu.be/MgLLihgKUuc?si=GoLwfbuwJBZNLQ9c" rel="noopener noreferrer"&gt;https://youtu.be/MgLLihgKUuc?si=GoLwfbuwJBZNLQ9c&lt;/a&gt;&lt;br&gt;
YOUTUBE DEMO MOBILE:&lt;a href="https://youtube.com/shorts/mRaoCBRngaY?si=RFCkVGLzyi1ohKOh" rel="noopener noreferrer"&gt;https://youtube.com/shorts/mRaoCBRngaY?si=RFCkVGLzyi1ohKOh&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built as an AI, cloud, and compliance engineering project focused on South African regulatory intelligence 🇿🇦. Not legal advice ⚠️ — always verify against the latest official regulatory publications.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>gemma</category>
      <category>rag</category>
      <category>aws</category>
    </item>
    <item>
      <title>Agentic AI for VMware migrations with AWS Transform for VMware</title>
      <dc:creator>Limani Ndou</dc:creator>
      <pubDate>Tue, 09 Jun 2026 11:41:16 +0000</pubDate>
      <link>https://dev.to/limani/agentic-ai-for-vmware-migrations-with-aws-transform-for-vmware-28fe</link>
      <guid>https://dev.to/limani/agentic-ai-for-vmware-migrations-with-aws-transform-for-vmware-28fe</guid>
      <description>&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%2Fzyxkbkl2ccopd0ycnzy6.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%2Fzyxkbkl2ccopd0ycnzy6.png" alt=" " width="800" height="551"&gt;&lt;/a&gt;&lt;br&gt;
I recently learned about Agentic AI for VMware migrations from AWS through a session on AWS Transform for VMware. The session explained how enterprise VMware migrations are often slow and complex because of legacy systems, manual processes, and coordination challenges across multiple teams.&lt;/p&gt;

&lt;p&gt;What stood out to me was how AWS Transform uses Agentic AI to simplify migration workflows like discovery, assessment, planning, network conversion, and deployment. Instead of relying heavily on manual effort, the platform uses AI agents to automate and accelerate large-scale cloud transformations.&lt;/p&gt;

&lt;p&gt;The session also highlighted benefits such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Faster VMware migrations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reduced operational and licensing costs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improved scalability and security&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Better collaboration between customers, AWS teams, and partners&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It was interesting to see how AWS is moving beyond traditional migration tools and using AI-driven systems to modernize enterprise infrastructure at scale.&lt;/p&gt;

&lt;p&gt;You can learn more here:&lt;br&gt;
• &lt;a href="https://aws.amazon.com/transform/vmware/" rel="noopener noreferrer"&gt;https://aws.amazon.com/transform/vmware/&lt;/a&gt;&lt;br&gt;
• &lt;a href="https://youtu.be/BHO_45PxguI?si=FWAlu0vvqHbLuHmB" rel="noopener noreferrer"&gt;https://youtu.be/BHO_45PxguI?si=FWAlu0vvqHbLuHmB&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>aws</category>
      <category>vmware</category>
      <category>devops</category>
    </item>
    <item>
      <title>🚀 How I Ran 11 Microservices with OpenChoreo</title>
      <dc:creator>Limani Ndou</dc:creator>
      <pubDate>Wed, 25 Mar 2026 22:05:07 +0000</pubDate>
      <link>https://dev.to/limani/how-i-ran-11-microservices-with-openchoreo-ag3</link>
      <guid>https://dev.to/limani/how-i-ran-11-microservices-with-openchoreo-ag3</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;I used OpenChoreo to deploy and manage the Google Cloud microservices demo (11 services) on my local machine. The result was a cleaner developer workflow, better service visibility, and a production-like platform experience without building custom platform tooling from scratch.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;1️⃣ &lt;strong&gt;What OpenChoreo?&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;OpenChoreo&lt;/strong&gt; is a developer platform for &lt;strong&gt;Kubernetes&lt;/strong&gt; offering development and architecture abstractions, a Backstage-powered developer portal, application CI/CD, GitOps, and observability. It composes &lt;strong&gt;CNCF&lt;/strong&gt; and complementary projects into a modular, extensible framework that provides both strong governance for platform engineers and simplified abstractions for developers.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;OpenChoreo was developed by WSO2 and is now part of the Cloud Native Computing Foundation (CNCF) ecosystem.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;2️⃣ &lt;strong&gt;Why OpenChoreo?&lt;/strong&gt;&lt;br&gt;
OpenChoreo it provides all essential building blocks of an Internal Developer Platform (IDP) :&lt;/p&gt;

&lt;p&gt;High-level APIs for modeling cloud-native applications&lt;br&gt;
A Control Plane that understands and enforces these APIs with GitOps support&lt;br&gt;
A built-in workflow engine for CI/CD pipelines and automation&lt;br&gt;
An opinionated Data Plane with runtime enforcement of design-time semantics&lt;br&gt;
Built-in security, networking, and observability integrations&lt;br&gt;
This is the key reason I used it for this 11-microservice demo.&lt;/p&gt;

&lt;p&gt;3️⃣ &lt;strong&gt;GCP Microservices Demo: What It Includes&lt;/strong&gt;&lt;br&gt;
Repository: &lt;a href="https://github.com/GoogleCloudPlatform/microservices-demo" rel="noopener noreferrer"&gt;https://github.com/GoogleCloudPlatform/microservices-demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🌐 frontend (Go): Serves the website and auto-generates user session IDs.&lt;br&gt;
🛒 cartservice (C#): Stores/retrieves cart items in Redis.&lt;br&gt;
📚 productcatalogservice (Go): Product listing, search, and product details from JSON.&lt;br&gt;
💱 currencyservice (Node.js): Converts money values using ECB exchange rates (highest QPS).&lt;br&gt;
💳 paymentservice (Node.js): Mock credit card charge and transaction ID generation.&lt;br&gt;
🚚 shippingservice (Go): Shipping cost estimates and mock shipping execution.&lt;br&gt;
✉️ emailservice (Python): Mock order confirmation emails.&lt;br&gt;
🎯 checkoutservice (Go): Orchestrates cart, payment, shipping, and email flow.&lt;br&gt;
💡 recommendationservice (Python): Suggests products from cart context.&lt;br&gt;
📢 adservice (Java): Returns text ads based on context words.&lt;br&gt;
🔄 loadgenerator (Python/Locust): Simulates realistic shopping traffic.&lt;br&gt;
4️⃣ What I Did (Step by Step)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚙️ Prerequisites&lt;br&gt;
Ensure the following before you begin:&lt;br&gt;
-Docker (Engine 26.0+ recommended)&lt;br&gt;
-Allocate at least 4 GB RAM and 2 CPUs.&lt;br&gt;
-If you plan to install with WorkflowPlane, allocate 8 GB RAM and 4 CPUs for optimal performance.&lt;br&gt;
-5-10 minutes of setup time&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Step 1: Start OpenChoreo Quick Start&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; openchoreo-quick-start &lt;span class="sb"&gt;`&lt;/span&gt;
  &lt;span class="nt"&gt;--pull&lt;/span&gt; always &lt;span class="sb"&gt;`&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; //var/run/docker.sock:/var/run/docker.sock &lt;span class="sb"&gt;`&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 &lt;span class="nt"&gt;-p&lt;/span&gt; 9443:9443 &lt;span class="sb"&gt;`&lt;/span&gt;
  ghcr.io/openchoreo/quick-start:v1.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Step 2: Install OpenChoreo(two options):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./install.sh

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;With observability&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./install.sh &lt;span class="nt"&gt;--with-build&lt;/span&gt; &lt;span class="nt"&gt;--with-observability&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 3: Choose a Deployment Option&lt;br&gt;
There are two ways to deploy the GCP Microservices Demo:&lt;/p&gt;

&lt;p&gt;Option A: Use the built-in OpenChoreo deploy script for GCP Microservices Demo (11 services: frontend, cart, checkout, payment, and more)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./deploy-gcp-demo.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Option B: Clone and deploy manually&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--depth&lt;/span&gt; 1 &lt;span class="nt"&gt;--branch&lt;/span&gt; v0 https://github.com/GoogleCloudPlatform/microservices-demo.git
&lt;span class="nb"&gt;cd &lt;/span&gt;microservices-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; ./release/kubernetes-manifests.yaml
I used Option B &lt;span class="o"&gt;(&lt;/span&gt;clone and deploy&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 4: Verify in OpenChoreo UI&lt;br&gt;
Access the UI at: &lt;code&gt;http://openchoreo.localhost:8080/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Default login credentials:&lt;/p&gt;

&lt;p&gt;Username: &lt;code&gt;admin@openchoreo.dev&lt;/code&gt;&lt;br&gt;
Password: &lt;code&gt;Admin@123&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%2F1frup8664uxz6h9fmj7e.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%2F1frup8664uxz6h9fmj7e.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check:&lt;/p&gt;

&lt;p&gt;Project and component catalog&lt;br&gt;
Deployment pipeline view&lt;br&gt;
Environment progression&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%2Fkzq4d2vsaa9gtkfn6hug.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%2Fkzq4d2vsaa9gtkfn6hug.png" alt=" " width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 5: Validate End-to-End App Behavior&lt;br&gt;
I opened the storefront and validated core user flow (browse, cart, checkout).&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%2F6ec04p8gys9vauqgobu8.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%2F6ec04p8gys9vauqgobu8.png" alt=" " width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📚 &lt;strong&gt;References&lt;/strong&gt;&lt;br&gt;
Documentation: &lt;a href="https://openchoreo.dev/docs/" rel="noopener noreferrer"&gt;https://openchoreo.dev/docs/&lt;/a&gt;&lt;br&gt;
Documentation: &lt;a href="https://insights.linuxfoundation.org/project/openchore" rel="noopener noreferrer"&gt;https://insights.linuxfoundation.org/project/openchore&lt;/a&gt;&lt;br&gt;
OpenChoreo Quick Start Guide:&lt;br&gt;
&lt;a href="https://openchoreo.dev/docs/getting-started/quick-start-guide/" rel="noopener noreferrer"&gt;https://openchoreo.dev/docs/getting-started/quick-start-guide/&lt;/a&gt;&lt;br&gt;
GCP Microservices Demo Repository:&lt;br&gt;
&lt;a href="https://github.com/GoogleCloudPlatform/microservices-demo" rel="noopener noreferrer"&gt;https://github.com/GoogleCloudPlatform/microservices-demo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>openchoreo</category>
      <category>kubernetes</category>
      <category>microservices</category>
      <category>devops</category>
    </item>
    <item>
      <title>🚀 How I Built a Serverless Expense Tracker Using AWS Lambda and Amazon S3 - No Server Required</title>
      <dc:creator>Limani Ndou</dc:creator>
      <pubDate>Fri, 20 Mar 2026 19:50:36 +0000</pubDate>
      <link>https://dev.to/limani/how-i-built-a-serverless-expense-tracker-using-aws-lambda-and-amazon-s3-no-server-required-n24</link>
      <guid>https://dev.to/limani/how-i-built-a-serverless-expense-tracker-using-aws-lambda-and-amazon-s3-no-server-required-n24</guid>
      <description>&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%2Fdq2avg3odalndq7jn1iu.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%2Fdq2avg3odalndq7jn1iu.png" alt=" " width="800" height="446"&gt;&lt;/a&gt;&lt;br&gt;
🚀I have built a fully serverless expense tracking pipeline on AWS  no servers, no manual work, just pure cloud automation. &lt;/p&gt;

&lt;p&gt;The problem: combining monthly expense CSVs every year is tedious and error-prone. So I automated the entire process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🪣 Amazon S3 (Simple Storage Service)&lt;/strong&gt;&lt;br&gt;
Amazon S3 is a cloud-based object storage service that stores and retrieves any amount of data from anywhere in the world. It can also watch for new files and automatically notify other AWS services when something is uploaded.&lt;br&gt;
💡 Think of it as a smart cloud hard drive the moment a CSV lands in S3, it wakes up Lambda automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚡ AWS Lambda&lt;/strong&gt;&lt;br&gt;
AWS Lambda is a serverless compute service that runs your code in response to events, without provisioning or managing any servers. You only pay for the milliseconds your code actually runs.&lt;br&gt;
💡 Think of it as a worker who sleeps until you need them triggered, runs the task, goes back to sleep. No server running 24/7, no idle costs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔐 AWS IAM (Identity &amp;amp; Access Management)&lt;/strong&gt;&lt;br&gt;
AWS IAM is a service that controls access to AWS resources by defining who is authenticated and what actions they are authorised to perform.&lt;br&gt;
💡 Think of it as the security guard of AWS without IAM, Lambda would not be allowed to touch a single file in S3.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📊 Amazon CloudWatch&lt;/strong&gt;&lt;br&gt;
Amazon CloudWatch is a monitoring and observability service that collects logs, metrics, and events from AWS services in real time.&lt;br&gt;
💡 Think of it as the CCTV of your cloud application every log line, every error, every execution time recorded automatically.&lt;/p&gt;

&lt;p&gt;⚙️ How The Pipeline Works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upload monthly CSV to S3&lt;/li&gt;
&lt;li&gt;S3 fires an event → Lambda wakes up&lt;/li&gt;
&lt;li&gt;Lambda reads the new file + existing master&lt;/li&gt;
&lt;li&gt;Merges, sorts by date, removes duplicates&lt;/li&gt;
&lt;li&gt;Recalculates category totals in South African Rand&lt;/li&gt;
&lt;li&gt;Saves updated master file back to S3 instantly&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;📈 Real Results — 3 Months of SA Expense Data:&lt;br&gt;
• ✅ 50 transactions merged automatically&lt;br&gt;
• ✅ 0 manual steps required&lt;br&gt;
• ✅ Categories: Groceries, Fuel, Utilities, Health &amp;amp; more&lt;br&gt;
• 💰 Grand Total (YTD 2026): R41,859.97&lt;/p&gt;

&lt;p&gt;🔗 Full source code, architecture diagram &amp;amp; sample data if you want to try:&lt;br&gt;
👉 &lt;a href="https://lnkd.in/dQNytjKD" rel="noopener noreferrer"&gt;https://lnkd.in/dQNytjKD&lt;/a&gt;&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>aws</category>
      <category>s3</category>
      <category>lambda</category>
    </item>
  </channel>
</rss>
