<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: John NG</title>
    <description>The latest articles on Forem by John NG (@john-nch-hk).</description>
    <link>https://forem.com/john-nch-hk</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%2F2312969%2Fdc40f540-336c-4c89-8115-7464907f2365.PNG</url>
      <title>Forem: John NG</title>
      <link>https://forem.com/john-nch-hk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/john-nch-hk"/>
    <language>en</language>
    <item>
      <title>Easy-CRM, a productivity tool created with Kiro</title>
      <dc:creator>John NG</dc:creator>
      <pubDate>Sun, 14 Sep 2025 17:39:02 +0000</pubDate>
      <link>https://forem.com/kirodotdev/easy-crm-a-productivity-tool-created-with-kiro-6cl</link>
      <guid>https://forem.com/kirodotdev/easy-crm-a-productivity-tool-created-with-kiro-6cl</guid>
      <description>&lt;h2&gt;
  
  
  Inspiration
&lt;/h2&gt;

&lt;p&gt;Our team spent a lot of time in identifying contacts for inviting to our events, as our leads often were scattered across excels/csvs from various past events/sources. As such, we need a tool to consolidate them all and allow easy query/exporting.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;A serverless web application that enables users to upload CSV/Excel files containing lead data in various formats. The system automatically standardizes the data using DeepSeek AI and provides a web interface for viewing, filtering, exporting, and querying lead.&lt;/p&gt;

&lt;p&gt;Demo available!!!&lt;br&gt;
&lt;a href="https://demo-crm.cmpapp.top/" rel="noopener noreferrer"&gt;https://demo-crm.cmpapp.top/&lt;/a&gt;&lt;br&gt;
demo-user&lt;br&gt;
DemoPass123!&lt;/p&gt;

&lt;p&gt;Main Menu&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%2Fkpim0lqzt5w0gtuvhr1c.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%2Fkpim0lqzt5w0gtuvhr1c.png" alt=" " width="800" height="559"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Uploading&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%2Fi7sf1f4s4y3v41eccb3g.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%2Fi7sf1f4s4y3v41eccb3g.png" alt=" " width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;File Upload &amp;amp; Processing&lt;/strong&gt;: Drag-and-drop CSV/Excel upload with automatic format standardization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Processing Status&lt;/strong&gt;: Live status indicator showing upload and processing progress with cancellation support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Worksheet Excel Support&lt;/strong&gt;: Automatically processes ALL worksheets in Excel files (not just the first one)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Duplicate Lead Handling&lt;/strong&gt;: Automatic detection and handling of duplicate leads based on email addresses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lead Management&lt;/strong&gt;: Sortable, filterable table view with pagination for lead data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phone Field Integration&lt;/strong&gt;: Complete phone number support with validation, formatting, and clickable tel: links&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Export&lt;/strong&gt;: CSV export functionality with filter-aware data selection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch Processing&lt;/strong&gt;: Scalable file processing architecture using SQS queues for large files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure Access&lt;/strong&gt;: AWS Cognito authentication with JWT token validation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How I built it
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: Python 3.13, AWS Lambda, DynamoDB, S3, SQS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: Vanilla HTML5, CSS, JavaScript with Tailwind CSS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure&lt;/strong&gt;: CloudFormation nested stacks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Integration&lt;/strong&gt;: DeepSeek AI API for data standardization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt;: AWS Cognito (User Pool + Identity Pool)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CDN&lt;/strong&gt;: CloudFront with SSL certificate&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Architecture Diagram
&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%2Fl3sd5kx1im2h7197h4so.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%2Fl3sd5kx1im2h7197h4so.png" alt="Diagram" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson learnt from using Kiro
&lt;/h2&gt;

&lt;p&gt;The most challenging part with vibe coding is debugging the issues with Kiro. Later on I adopted the below approaches which dramatically reduce number issues arising:&lt;/p&gt;

&lt;p&gt;During Project kickstart:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I provided the architecture in the "spec" session, such as how lambda should process the info, db schema, etc.&lt;/li&gt;
&lt;li&gt;I always try to explain the whole logic and required features in detail, so that Kiro wont have to guess or over-engineered my solution. &lt;/li&gt;
&lt;li&gt;Kiro generate the details on implementation and test cases, task by task.&lt;/li&gt;
&lt;li&gt;Go through the tasks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;During implementation:&lt;br&gt;
I always use steering to ensure that future vibe coding/spec will always follow certain amount of standard/convention. For example, I require Kiro to always use venv to prevent messing up my workspace and global env.&lt;/p&gt;

&lt;p&gt;After getting a MVP: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For bug fix, i use 'Vibe' session as it's more simple and direct, and less costly.&lt;/li&gt;
&lt;li&gt;For new feature/enhancement, I used "Spec" session, as new changes may affect whole architecture, and require through planning to reduce future bug fixes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The above approaches enables Kiro to find the root issues much quicker, thus saving time and credits.&lt;/p&gt;

&lt;p&gt;One notable mention on code generation is that Kiro helped me solved a race condition problem, which is due to concurrent lambda operations on a dynamoDB update. Kiro successfully investigated the root issue and able to implement atomic operations to ensure the program be race-free.&lt;/p&gt;

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

&lt;p&gt;While Kiro/vibe coding is powerful, it still require a user with substancial knowledge to guide it, or else the product wont be delivered once it got complex enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next for easy-crm
&lt;/h2&gt;

&lt;p&gt;Will be adding querying on the leads with NLP to gain insights easily soon!&lt;/p&gt;

&lt;p&gt;Feel free to leave your comments below!! Would love to discuss how we can gradually adopt vibe coding into production. Also feel free to connect me via:&lt;br&gt;
LinkedIn:&lt;a href="https://www.linkedin.com/in/john-nch-hk" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/john-nch-hk&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/john-ng-hk" rel="noopener noreferrer"&gt;https://github.com/john-ng-hk&lt;/a&gt; &lt;/p&gt;

</description>
      <category>kiro</category>
      <category>aws</category>
      <category>genai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Vibe coding a simple STEM Game with Amazon Q CLI</title>
      <dc:creator>John NG</dc:creator>
      <pubDate>Thu, 19 Jun 2025 04:48:00 +0000</pubDate>
      <link>https://forem.com/aws-builders/vibe-coding-a-simple-stem-game-with-amazon-q-cli-2m7j</link>
      <guid>https://forem.com/aws-builders/vibe-coding-a-simple-stem-game-with-amazon-q-cli-2m7j</guid>
      <description>&lt;p&gt;Just recently saw this &lt;a href="https://community.aws/content/2xIoduO0xhkhUApQpVUIqBFGmAc/build-games-with-amazon-q-cli-and-score-a-t-shirt?trk=b085178b-f0cb-447b-b32d-bd0641720467&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;post&lt;/a&gt; and decided that it would be interesting to test out Amazon Q CLI capability by building a game, so here we go!&lt;/p&gt;

&lt;p&gt;First, I started by finding a game idea. Well turns out my high school teacher friend has some students find understanding physic concepts difficult, like free body diagrams. So I created this game for her students to understand the concepts easier~&lt;/p&gt;

&lt;p&gt;With the game idea in place, I then proceed to setup the development environment and get my hands dirty. For anyone interested, you can refer this &lt;a href="https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-installing.html" rel="noopener noreferrer"&gt;guide&lt;/a&gt; to install Amazon Q CLI.&lt;/p&gt;

&lt;p&gt;Basically Amazon Q CLI is like ChatGPT/Grok/DeepSeek but in the form of CLI, so it's quite easy to use as long as you are comfortable with CLI environment.&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%2Fqtd93ektruotf0ayprpw.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%2Fqtd93ektruotf0ayprpw.png" alt="Image description" width="800" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So with Amazon Q CLI ready, now is time for prompting! It's working better than I expected as it appears Q is using a reasoning model by default, though the response time could be quite long as a trade-off.&lt;/p&gt;

&lt;p&gt;Therefore, after endless prompting and revising, i find the below tips that maybe usefull in facilitating effective prompting and reduce the back-and-forth between you and Q:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define a prompting framework such that the Q know the context, the task, and the expected results&lt;/li&gt;
&lt;li&gt;Ask Q to provide visual debugs can let the Q know how to fix issues more quickly&lt;/li&gt;
&lt;li&gt;Ask Q to give a plan before coding, that way you know Q is thinking as you expected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With about 3 hours prompting and waiting, here's the final product!&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%2Fzy15yvkp7j7elqtvs0h2.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%2Fzy15yvkp7j7elqtvs0h2.png" alt="Image description" width="800" height="627"&gt;&lt;/a&gt;&lt;br&gt;
game demo: &lt;a href="https://fbd.cmpapp.top" rel="noopener noreferrer"&gt;https://fbd.cmpapp.top&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/john-ng-hk/stem-fbd-game" rel="noopener noreferrer"&gt;https://github.com/john-ng-hk/stem-fbd-game&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's all and thanks for reading, feel free to connect me on &lt;a href="https://www.linkedin.com/in/john-nch-hk/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; too~&lt;/p&gt;

</description>
      <category>amazonqcli</category>
      <category>webdev</category>
      <category>programming</category>
      <category>aws</category>
    </item>
    <item>
      <title>[June 2025 UPDATED] Business Card Solution powered with AI</title>
      <dc:creator>John NG</dc:creator>
      <pubDate>Sun, 16 Mar 2025 16:23:39 +0000</pubDate>
      <link>https://forem.com/aws-builders/business-card-solution-powered-with-deepseek-29bj</link>
      <guid>https://forem.com/aws-builders/business-card-solution-powered-with-deepseek-29bj</guid>
      <description>&lt;h2&gt;
  
  
  Building a Modern Business Card Scanner with AI: A Deep Dive into AWS and DeepSeek Integration
&lt;/h2&gt;

&lt;p&gt;Hey there, fellow developers! 👋 Today, I'm excited to share my journey of building a modern business card scanner application that leverages AI to transform physical business cards into organized digital contacts. This project combines AWS services with the DeepSeek API to create a powerful networking tool.&lt;/p&gt;

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

&lt;p&gt;In today's digital age, we still exchange physical business cards, but managing them efficiently is a challenge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cards get lost or damaged&lt;/li&gt;
&lt;li&gt;Manual data entry is time-consuming and error-prone&lt;/li&gt;
&lt;li&gt;It's hard to analyze your professional network effectively&lt;/li&gt;
&lt;li&gt;Finding specific contacts or seeing connections between companies is difficult&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are existing digital business card scanning solution in the market, but they are often:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;expensive&lt;/li&gt;
&lt;li&gt;not user friendly&lt;/li&gt;
&lt;li&gt;only supports internal address book, no integration with device contacts&lt;/li&gt;
&lt;li&gt;data stored in the providers' database, you don't own the data&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  💡 The Solution
&lt;/h2&gt;

&lt;p&gt;I built an open-source web application that solves these problems by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using AI to extract information from business card images&lt;/li&gt;
&lt;li&gt;Organizing contacts with rich metadata&lt;/li&gt;
&lt;li&gt;Allows importing the contacts to your phone contacts in batch!&lt;/li&gt;
&lt;li&gt;self-deployable solution, meaning you own and control your data!&lt;/li&gt;
&lt;li&gt;Providing network analysis and visualization&lt;/li&gt;
&lt;li&gt;Offering an AI-powered chat interface for querying your contact database&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The application is built on a modern serverless stack:&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%2Fk4v12n11upqqmh48os6z.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%2Fk4v12n11upqqmh48os6z.png" alt="infra" width="800" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Frontend&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend hosted on S3 and enhanced with CloudFront CDN&lt;/li&gt;
&lt;li&gt;Interactive network visualization using D3.js&lt;/li&gt;
&lt;li&gt;Real-time chat interface&lt;/li&gt;
&lt;li&gt;Responsive design with Tailwind CSS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Backend&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS Lambda for serverless compute&lt;/li&gt;
&lt;li&gt;Amazon Textract for OCR&lt;/li&gt;
&lt;li&gt;DeepSeek API for intelligent data extraction&lt;/li&gt;
&lt;li&gt;DynamoDB for contact storage&lt;/li&gt;
&lt;li&gt;S3 for image storage&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Authentication&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS Cognito for user management&lt;/li&gt;
&lt;li&gt;Secure API access with IAM roles&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🔍 Key Features
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Intelligent Card Scanning&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%2F9kz2ldhxwwx3x9xy5mmz.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%2F9kz2ldhxwwx3x9xy5mmz.png" alt="Image description" width="800" height="452"&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%2Fzt3kjzhmc32k6o2yhcby.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%2Fzt3kjzhmc32k6o2yhcby.png" alt="Image description" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Network Analysis&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%2F9rearvdbjtdzalu73vq9.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%2F9rearvdbjtdzalu73vq9.png" alt="Image description" width="800" height="442"&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%2Fbxo6prtp9ccw6hadir5y.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%2Fbxo6prtp9ccw6hadir5y.png" alt="Image description" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;AI-Powered Chat Interface&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%2F188zcdasktgwgmxb5ma1.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%2F188zcdasktgwgmxb5ma1.png" alt="Image description" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Want to try it yourself?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click this demo &lt;a href="https://card.cmpapp.top" rel="noopener noreferrer"&gt;url&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Sign in using the test credentials:

&lt;ul&gt;
&lt;li&gt;Username: testUser&lt;/li&gt;
&lt;li&gt;Password: 12345678!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Navigate to the "Scan Cards" tab&lt;/li&gt;
&lt;li&gt;Upload one or more business card images&lt;/li&gt;
&lt;li&gt;View processed contacts in the "My Contacts" tab&lt;/li&gt;
&lt;li&gt;Explore network insights in the "Network Analysis" tab&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Want to deploy yourself? Check out the repo: &lt;a href="https://github.com/john-ng-hk/Biz-card-scanner" rel="noopener noreferrer"&gt;https://github.com/john-ng-hk/Biz-card-scanner&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🎨 User Experience
&lt;/h2&gt;

&lt;p&gt;The application provides a seamless experience:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upload business card images (single or batch)&lt;/li&gt;
&lt;li&gt;AI automatically extracts and categorizes information&lt;/li&gt;
&lt;li&gt;View your contacts in a modern, filterable interface&lt;/li&gt;
&lt;li&gt;Explore network connections through interactive visualizations&lt;/li&gt;
&lt;li&gt;Chat with AI to analyze your professional network&lt;/li&gt;
&lt;li&gt;Easily export contacts as vcard files for your phone contacts&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  💰 Cost Estimation
&lt;/h2&gt;

&lt;p&gt;AWS: Total 12 months cost = 15.00 USD &lt;a href="https://calculator.aws/#/estimate?id=8252b1a1003c7d6d4d558fe915ad161a370d83d8" rel="noopener noreferrer"&gt;AWS Pricing Calculator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DeepSeek API: minimum spend = 10RMB = 1.38 USD (1USD = 7.24 RMB)&lt;/p&gt;

&lt;p&gt;Total Annual Cost = AWS+DeepSeek key = 15+1.38=16.38= around 16.5 USD&lt;/p&gt;

&lt;p&gt;main assumptions:&lt;/p&gt;

&lt;p&gt;Number of API Requests 1000 API requests each day x 20 working days = 20000 API requests per month&lt;br&gt;
Number of scan card requests: 1 card each day x 30 days = 30 requests&lt;/p&gt;

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

&lt;p&gt;I'm planning to add:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Maybe with https so that the can directly scan with device mobile (DONE! You can now directly scan with camera)&lt;/li&gt;
&lt;li&gt;Better UI/UX and improve latency with AI chatbot.&lt;/li&gt;
&lt;li&gt;The current serverless architecture is a "Lambdalith", which is great for quick development for PoC but does not scale well with more features coming in. So may need decouple this part in the future.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🤔 Key Learnings
&lt;/h2&gt;

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

&lt;ol&gt;
&lt;li&gt;Serverless architectures need really thoughtful timeout configurations (I had to increaset the integration timeout to 60000ms via service quota request this time...)&lt;/li&gt;
&lt;li&gt;User experience is crucial for AI-powered application, I didnt expect most my dev time is on the frontend part.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🎁 Open Source
&lt;/h2&gt;

&lt;p&gt;This project is open source! Feel free to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Star the repository&lt;/li&gt;
&lt;li&gt;Submit issues or feature requests&lt;/li&gt;
&lt;li&gt;Contribute improvements&lt;/li&gt;
&lt;li&gt;Fork and adapt for your needs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔗 Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/john-ng-hk/Biz-card-scanner" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://sam-business-card-scanner-portal.s3-website-ap-southeast-1.amazonaws.com/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  👋 Connect
&lt;/h2&gt;

&lt;p&gt;I'd love to hear your thoughts and suggestions! Connect with me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: [&lt;a href="https://github.com/john-ng-hk" rel="noopener noreferrer"&gt;https://github.com/john-ng-hk&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;LinkedIn: [&lt;a href="https://www.linkedin.com/in/john-nch-hk/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/john-nch-hk/&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me know in the comments if you'd like to see more detailed posts about specific aspects of this project!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>aws</category>
      <category>serverless</category>
      <category>ai</category>
    </item>
    <item>
      <title>Business Card Solution powered with DeepSeek</title>
      <dc:creator>John NG</dc:creator>
      <pubDate>Sun, 16 Mar 2025 15:21:44 +0000</pubDate>
      <link>https://forem.com/john-nch-hk/business-card-solution-powered-with-deepseek-2319</link>
      <guid>https://forem.com/john-nch-hk/business-card-solution-powered-with-deepseek-2319</guid>
      <description>&lt;h2&gt;
  
  
  Building a Modern Business Card Scanner with AI: A Deep Dive into AWS and DeepSeek Integration
&lt;/h2&gt;

&lt;p&gt;Hey there, fellow developers! 👋 Today, I'm excited to share my journey of building a modern business card scanner application that leverages AI to transform physical business cards into organized digital contacts. This project combines AWS services with the DeepSeek API to create a powerful networking tool.&lt;/p&gt;

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

&lt;p&gt;In today's digital age, we still exchange physical business cards, but managing them efficiently is a challenge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cards get lost or damaged&lt;/li&gt;
&lt;li&gt;Manual data entry is time-consuming and error-prone&lt;/li&gt;
&lt;li&gt;It's hard to analyze your professional network effectively&lt;/li&gt;
&lt;li&gt;Finding specific contacts or seeing connections between companies is difficult&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are existing digital business card scanning solution in the market, but they are often:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;expensive&lt;/li&gt;
&lt;li&gt;not user friendly&lt;/li&gt;
&lt;li&gt;only supports internal address book, no integration with device contacts&lt;/li&gt;
&lt;li&gt;data stored in the providers' database, you don't own the data&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  💡 The Solution
&lt;/h2&gt;

&lt;p&gt;I built a web application that solves these problems by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using AI to extract information from business card images&lt;/li&gt;
&lt;li&gt;Organizing contacts with rich metadata&lt;/li&gt;
&lt;li&gt;Allows importing the contacts to your phone contacts in batch!&lt;/li&gt;
&lt;li&gt;self-deployable solution, meaning you own and control your data!&lt;/li&gt;
&lt;li&gt;Providing network analysis and visualization&lt;/li&gt;
&lt;li&gt;Offering an AI-powered chat interface for querying your contact database&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The application is built on a modern serverless stack:&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%2Fwn7ow12ak5r706trwmsd.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%2Fwn7ow12ak5r706trwmsd.png" alt="Image description" width="761" height="631"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Frontend&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single-page application hosted on S3&lt;/li&gt;
&lt;li&gt;Interactive network visualization using D3.js&lt;/li&gt;
&lt;li&gt;Real-time chat interface&lt;/li&gt;
&lt;li&gt;Responsive design with Tailwind CSS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Backend&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS Lambda for serverless compute&lt;/li&gt;
&lt;li&gt;Amazon Textract for OCR&lt;/li&gt;
&lt;li&gt;DeepSeek API for intelligent data extraction&lt;/li&gt;
&lt;li&gt;DynamoDB for contact storage&lt;/li&gt;
&lt;li&gt;S3 for image storage&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Authentication&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS Cognito for user management&lt;/li&gt;
&lt;li&gt;Secure API access with IAM roles&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🔍 Key Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Intelligent Card Scanning
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_with_deepseek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Extract the following information from the provided business card text: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name, company, department, title, email, phone, address, website. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Additionally, categorize the company&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s industry...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# DeepSeek API integration for smart data extraction
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Network Analysis
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateNetworkVisualization&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// D3.js force-directed graph&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;simulation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forceSimulation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;force&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;link&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forceLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;links&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;force&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;charge&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forceManyBody&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;force&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forceCenter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. AI-Powered Chat Interface
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_chat_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cors_headers&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Handle chat messages using DeepSeek.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Process natural language queries about your contacts
&lt;/span&gt;    &lt;span class="c1"&gt;# Generate insights and recommendations
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Want to try it yourself? Here's how:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repository:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &amp;lt;repository-url&amp;gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;business-card-scanner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Install dependencies:
&lt;/li&gt;
&lt;/ol&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;application
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Configure AWS and DeepSeek:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DEEPSEEK_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;YOUR_API_KEY'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Deploy:
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  🎨 User Experience
&lt;/h2&gt;

&lt;p&gt;The application provides a seamless experience:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upload business card images (single or batch)&lt;/li&gt;
&lt;li&gt;AI automatically extracts and categorizes information&lt;/li&gt;
&lt;li&gt;View your contacts in a modern, filterable interface&lt;/li&gt;
&lt;li&gt;Explore network connections through interactive visualizations&lt;/li&gt;
&lt;li&gt;Chat with AI to analyze your professional network&lt;/li&gt;
&lt;li&gt;Easily export contacts as vcard files for your phone contacts&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  💰 Cost Estimation
&lt;/h2&gt;

&lt;p&gt;AWS: Total 12 months cost = 15.00 USD &lt;a href="https://calculator.aws/#/estimate?id=8252b1a1003c7d6d4d558fe915ad161a370d83d8" rel="noopener noreferrer"&gt;AWS Pricing Calculator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DeepSeek API: minimum spend = 10RMB = 1.38 USD (1USD = 7.24 RMB)&lt;/p&gt;

&lt;p&gt;Total Annual Cost = AWS+DeepSeek key = 15+1.38=16.38= around 16.5 USD&lt;/p&gt;

&lt;p&gt;main assumptions:&lt;/p&gt;

&lt;p&gt;Number of API Requests 1000 API requests each day x 20 working days = 20000 API requests per month&lt;br&gt;
Number of scan card requests: 1 card each day x 30 days = 30 requests&lt;/p&gt;

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

&lt;p&gt;I'm planning to add:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Maybe with https so that the can directly scan with device mobile&lt;/li&gt;
&lt;li&gt;Better UI/UX and improve latency with AI chatbot.&lt;/li&gt;
&lt;li&gt;The current serverless architecture is a "Lambdalith", which is great for quick development for PoC but does not scale well with more features coming in. So may need decouple this part in the future.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🤔 Key Learnings
&lt;/h2&gt;

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

&lt;ol&gt;
&lt;li&gt;Serverless architectures need thoughtful timeout configurations&lt;/li&gt;
&lt;li&gt;User experience is crucial for AI-powered application&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🎁 Open Source
&lt;/h2&gt;

&lt;p&gt;This project is open source! Feel free to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Star the repository&lt;/li&gt;
&lt;li&gt;Submit issues or feature requests&lt;/li&gt;
&lt;li&gt;Contribute improvements&lt;/li&gt;
&lt;li&gt;Fork and adapt for your needs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔗 Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/john-ng-hk/Biz-card-scanner" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://sam-business-card-scanner-portal.s3-website-ap-southeast-1.amazonaws.com/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  👋 Connect
&lt;/h2&gt;

&lt;p&gt;I'd love to hear your thoughts and suggestions! Connect with me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: [&lt;a href="https://github.com/john-ng-hk" rel="noopener noreferrer"&gt;https://github.com/john-ng-hk&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;LinkedIn: [&lt;a href="https://www.linkedin.com/in/john-nch-hk/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/john-nch-hk/&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me know in the comments if you'd like to see more detailed posts about specific aspects of this project!&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>aws</category>
      <category>deepseek</category>
      <category>ai</category>
    </item>
    <item>
      <title>Cloud Billing Portal: Automated Billing Statement Generation for Cloud Services</title>
      <dc:creator>John NG</dc:creator>
      <pubDate>Thu, 30 Jan 2025 10:22:05 +0000</pubDate>
      <link>https://forem.com/john-nch-hk/cloud-billing-portal-automated-billing-statement-generation-for-cloud-services-55d5</link>
      <guid>https://forem.com/john-nch-hk/cloud-billing-portal-automated-billing-statement-generation-for-cloud-services-55d5</guid>
      <description>&lt;h2&gt;
  
  
  Use case
&lt;/h2&gt;

&lt;p&gt;Currently our team need to spend large amount of time in manually consolidating multiple cloud accounts' bills into one single statement for our clients. As such, I have developed an in-house statement generation tool on AWS to automate consolidation of cloud vendor bills into customizable billing statements, saving hours of effort to and reducing human errors.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://cloudbilling.ddns.net" rel="noopener noreferrer"&gt;Link to demo&lt;/a&gt;&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;Provides a simple login system for authenticaiton and authorization&lt;/li&gt;
&lt;li&gt;Consolidate cloud vendor's raw bills into a single PDF statement&lt;/li&gt;
&lt;li&gt;Customizable PDF statement that allows input for address, ATTN, exchange rate, business logic, etc.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Solution Overview
&lt;/h2&gt;

&lt;p&gt;The Cloud Billing Portal is a comprehensive AWS-based solution designed to simplify and automate the process of generating and managing cloud billing statements. This application provides a user-friendly interface for uploading billing data, processing it, and generating customized PDF billing statements.&lt;/p&gt;

&lt;p&gt;The portal leverages various AWS services, including Lambda, API Gateway, S3, and Cognito, to create a secure and scalable billing management system. It offers features such as user authentication, file upload capabilities, and automated PDF generation based on uploaded billing data.&lt;/p&gt;

&lt;p&gt;The following diagram depicts the architecture of this solution.&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%2F5pu7bua92aqfkko61odi.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%2F5pu7bua92aqfkko61odi.png" alt="Image description" width="791" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation and Deployment
&lt;/h2&gt;

&lt;p&gt;Please refer to the &lt;a href="https://github.com/john-ng-hk/cloud-billing-portal/tree/main" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; for installation and deployment guide&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost
&lt;/h2&gt;

&lt;p&gt;Assumptions: 100 request per month to S3 and Lambda. 1 active user for signing into the portal&lt;/p&gt;

&lt;p&gt;Monthly cost: 0.07 USD Yearly cost: 0.84 USD&lt;br&gt;
No upfront cost.&lt;/p&gt;

&lt;p&gt;Detailed estimation link: &lt;a href="https://calculator.aws/#/estimate?id=73dac7b97d53a08857592a60c20f21541269b683" rel="noopener noreferrer"&gt;https://calculator.aws/#/estimate?id=73dac7b97d53a08857592a60c20f21541269b683&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Maximum payload
&lt;/h3&gt;

&lt;p&gt;Maximum payload for Lambda is 6MB, so any amount of .csv which may lead produce a statement greater than 6MB will probably return 500 error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scaling strategies
&lt;/h3&gt;

&lt;p&gt;The system scales well with the proposed fully serverless architecutre. However, to support more than 1,000 concurrent users, the default quota of Lambda it must be increased by Requesting a quota increase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloud Vendor
&lt;/h3&gt;

&lt;p&gt;Currently the portal only allows processing raw bills from Huawei Cloud. To allow input from other cloud vendors .csv, you will need to specify their respective csv format such as column names in &lt;code&gt;/sam-CloudBillingPortal/myBillAcc.py&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Potential Improvements
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Allow Sign-up Page redirect to cloud billing portal&lt;/li&gt;
&lt;li&gt;Setup custom DNS domain name
&lt;/li&gt;
&lt;li&gt;Include WAF for better security&lt;/li&gt;
&lt;li&gt;Implement loggings such as CloudWatch to track usage and errors.&lt;/li&gt;
&lt;li&gt;Setup unit tests in the CI/CD pipeline.&lt;/li&gt;
&lt;li&gt;Use HTTPS for better security&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>A simple short-lived URL shortener solution with AWS and GitHub actions</title>
      <dc:creator>John NG</dc:creator>
      <pubDate>Sun, 15 Dec 2024 14:54:26 +0000</pubDate>
      <link>https://forem.com/john-nch-hk/a-simple-short-lived-url-shortener-solution-with-aws-and-github-actions-58e2</link>
      <guid>https://forem.com/john-nch-hk/a-simple-short-lived-url-shortener-solution-with-aws-and-github-actions-58e2</guid>
      <description>&lt;h2&gt;
  
  
  Use case
&lt;/h2&gt;

&lt;p&gt;In cases where some large documents need be shared to client with URLs, these URLs are often lengthy, and use of free online URL shortener services like Bitly.com are prohibited due to confidentiality of documents. As such, I have designed a URL shortener with AWS to solve this problem for myself and team.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://d1y7ljm6v4i0aq.cloudfront.net/admin" rel="noopener noreferrer"&gt;Link to demo URL Shortener&lt;/a&gt;&lt;br&gt;
The following image shows the webpage of the URL shortener.&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%2Ff2u3crm1ziy1mtu5esjl.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%2Ff2u3crm1ziy1mtu5esjl.png" alt="Image description" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;Provides a simple web interface for users to submit long URLs and receive shortened versions of it&lt;/li&gt;
&lt;li&gt;Generate customizable short URLs in the format: &lt;a href="http://xxxxx.xxx/h2so4" rel="noopener noreferrer"&gt;http://xxxxx.xxx/h2so4&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Each short URL expires after 10 minutes after creation/accessed&lt;/li&gt;
&lt;li&gt;Displays a custom error page for non-existing short URLs&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Solution Component
&lt;/h2&gt;

&lt;h3&gt;
  
  
  AWS services
&lt;/h3&gt;

&lt;p&gt;Amazon API Gateway&lt;br&gt;
Amazon CloudFront&lt;br&gt;
Amazon DynamoDB&lt;br&gt;
Amazon EventBridge&lt;br&gt;
Amazon S3&lt;br&gt;
AWS CloudFormation&lt;br&gt;
AWS Lambda&lt;br&gt;
AWS WAF (Optional)&lt;/p&gt;

&lt;h3&gt;
  
  
  Others
&lt;/h3&gt;

&lt;p&gt;Git&lt;br&gt;
GitHub Actions&lt;br&gt;
Python&lt;br&gt;
HTML&lt;br&gt;
CSS&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution Overview
&lt;/h2&gt;

&lt;p&gt;The core idea of this solution is using S3 as a redirection engine to redirect URLs based on the attached metadata. When the user enters a short URL, S3 automatically responds with a HTTP redirect to the long URL, see &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/how-to-page-redirect.html" rel="noopener noreferrer"&gt;here &lt;/a&gt;)for more details.&lt;/p&gt;

&lt;p&gt;However, the user need a way to interact with the S3 redirection engine. As such, a website that provide interactions based on client is needed. This is where our API gateway comes into the picture, which will be acting as a simple page for our users and allow them to submit request that will invoke our backend (Lambda functions) to store our shortened URLs into our S3 bucket.&lt;/p&gt;

&lt;p&gt;Lastly, we will use Amazon CloudFront to wrap everything together with a simple domain name.&lt;/p&gt;

&lt;p&gt;The following diagram depicts the architecture of this solution.&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%2F8wp9q88gjpem8xgyi63c.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%2F8wp9q88gjpem8xgyi63c.png" alt="Image description" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;For easiest deployment, you can just use the CloudFormation stack provided &lt;a href="https://github.com/john-ng-hk/url-shortener/blob/main/stack.yaml" rel="noopener noreferrer"&gt;here&lt;/a&gt; to quickly launch all resources in your AWS account.&lt;/p&gt;

&lt;p&gt;If you wish to set this up together with a CI/CD pipeline using GitHub actions, please refer to the &lt;a href="https://github.com/john-ng-hk/url-shortener?tab=readme-ov-file" rel="noopener noreferrer"&gt;README in my repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost
&lt;/h2&gt;

&lt;p&gt;Assumptions: 100 short urls created per month, each viewed by 100 users. So 100x100 = 10,000 requests/month.&lt;/p&gt;

&lt;p&gt;Monthly cost: 0.95 USD (without WAF) Yearly cost: 11.4 USD&lt;br&gt;
No upfront cost.&lt;/p&gt;

&lt;p&gt;Detailed estimation link: &lt;a href="https://calculator.aws/#/estimate?id=0c0cd81bd97e9e112e7ddee985b873c0c34e0ef5" rel="noopener noreferrer"&gt;https://calculator.aws/#/estimate?id=0c0cd81bd97e9e112e7ddee985b873c0c34e0ef5&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Limitations on concurrent users
&lt;/h3&gt;

&lt;p&gt;The limitation is 1,000 concurrent users with the current proposed setup. The bottleneck is Lambda, which is supporting only 1,000 concurrent concurrent executions with the defualt quota.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scaling strategies
&lt;/h3&gt;

&lt;p&gt;The URL Shortener scales well with the proposed fully serverless architecutre. However, to support more than 1,000 concurrent users, the default quota of Lambda it must be increased by Requesting a quota increase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Potential Improvements
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Redirect uesr back to homepage if a the link is invalid.&lt;/li&gt;
&lt;li&gt;Setup custom DNS domain name to create a really short URL instead of using cloudfront domain.&lt;/li&gt;
&lt;li&gt;Setup mechanisms like Captcha to deter bot attacks and spam on the service.&lt;/li&gt;
&lt;li&gt;Setup access control such as Cognito to the portal for secure authentication.&lt;/li&gt;
&lt;li&gt;Implement loggings such as CloudWatch to track usage and errors.&lt;/li&gt;
&lt;li&gt;Setup unit tests in the CI/CD pipeline.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/blogs/compute/build-a-serverless-private-url-shortener/" rel="noopener noreferrer"&gt;https://aws.amazon.com/blogs/compute/build-a-serverless-private-url-shortener/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
