<?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: Shams Ali Shaikh</title>
    <description>The latest articles on DEV Community by Shams Ali Shaikh (@shamsalishaikh).</description>
    <link>https://dev.to/shamsalishaikh</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%2F4104387%2F7af4f921-b588-4c0a-8e7b-b53fd043cccc.png</url>
      <title>DEV Community: Shams Ali Shaikh</title>
      <link>https://dev.to/shamsalishaikh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shamsalishaikh"/>
    <language>en</language>
    <item>
      <title>Rhea.js 1.0: a security-first backend framework for Node.js and Express 5</title>
      <dc:creator>Shams Ali Shaikh</dc:creator>
      <pubDate>Tue, 13 Oct 2026 11:21:22 +0000</pubDate>
      <link>https://dev.to/shamsalishaikh/rheajs-10-a-security-first-backend-framework-for-nodejs-and-express-5-59gl</link>
      <guid>https://dev.to/shamsalishaikh/rheajs-10-a-security-first-backend-framework-for-nodejs-and-express-5-59gl</guid>
      <description>&lt;p&gt;I just released &lt;strong&gt;Rhea.js 1.0&lt;/strong&gt;, an open-source backend framework for Node.js. It sits on top of Express 5 and adds the parts every API ends up needing: a project layout, security defaults, validation, logging, authentication and a CLI that generates code for you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-rhea my-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This post explains what it is, why I built it, what you get, and, just as important, what it does not do yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Every Express project I started began the same way. Install Express. Add Helmet. Add CORS. Remember the body size limit. Add a rate limiter. Add a logger and then notice it prints passwords. Write an error handler. Decide on a folder layout. Copy the auth code from the last project.&lt;/p&gt;

&lt;p&gt;Two things bothered me about that routine:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Security is opt-in.&lt;/strong&gt; If you forget a step, nothing warns you. A fresh &lt;code&gt;express()&lt;/code&gt; app has no security headers, no limits, and no opinion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every team invents its own structure.&lt;/strong&gt; Nobody can open a new project and know where the validation lives.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Rhea.js is my answer: keep Express as the HTTP engine, and put the architecture and the safe defaults around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Rhea.js is
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A runtime package, &lt;code&gt;@rheajs/core&lt;/code&gt;, with a &lt;code&gt;createApp()&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;An auth package, &lt;code&gt;@rheajs/auth&lt;/code&gt; (passwords, JWT, refresh tokens, guards).&lt;/li&gt;
&lt;li&gt;A CLI, &lt;code&gt;@rheajs/cli&lt;/code&gt;, and the scaffolder &lt;code&gt;create-rhea&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Express 5 underneath. Your routes are normal Express routes. If you know Express, you already know most of Rhea.js.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is MIT licensed, written in TypeScript, and works with TypeScript or JavaScript, ES Modules or CommonJS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started in one minute
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-rhea my-api
&lt;span class="nb"&gt;cd &lt;/span&gt;my-api
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The scaffolder asks four things: TypeScript or JavaScript, ES Modules or CommonJS, a database (MongoDB, MySQL or none) and, if you picked a database, whether to add authentication. Then it installs dependencies, runs &lt;code&gt;git init&lt;/code&gt;, makes the first commit, and, if you have the GitHub CLI, can create the GitHub repository for you.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;http://localhost:5000/api/rhea&lt;/code&gt; and you have a running API. Add a resource:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx rhea generate module &lt;span class="nb"&gt;users&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That creates the controller, service, repository, routes, Zod schema, types and an integration test, and registers the module.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get by default
&lt;/h2&gt;

&lt;p&gt;Everything below is on from the first request, with no setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request IDs&lt;/strong&gt; on every request and every error response, so you can find a log line from a bug report.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Helmet&lt;/strong&gt; security headers, plus a &lt;code&gt;Permissions-Policy&lt;/code&gt; header.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CORS denied by default.&lt;/strong&gt; You list the origins you trust. A wildcard is refused in production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limiting&lt;/strong&gt;, with an option to share counters through Redis when you run more than one instance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Body size limit, request timeout and JSON-only bodies&lt;/strong&gt; (a form-encoded body gets a clean &lt;code&gt;415&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prototype-pollution guard&lt;/strong&gt;, and an optional guard against MongoDB operator keys such as &lt;code&gt;{"$ne": null}&lt;/code&gt; in a login body (on in generated MongoDB projects).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One error shape.&lt;/strong&gt; Throw &lt;code&gt;NotFoundError&lt;/code&gt; or &lt;code&gt;ConflictError&lt;/code&gt; from anywhere and the client always gets the same JSON. Stack traces never leave the server in production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured logs&lt;/strong&gt; with pino: JSON in production, readable in development, and passwords, tokens and cookies are redacted. In development you also get a short morgan line per request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation with Zod&lt;/strong&gt; for body, query and params, and &lt;strong&gt;environment validation&lt;/strong&gt; that stops startup when your config is wrong.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graceful shutdown&lt;/strong&gt; and process error handlers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A route looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sendSuccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@rheajs/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;sendSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Created&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Invalid input returns &lt;code&gt;422&lt;/code&gt; with a list of exactly which field failed, and the keys Zod strips never reach your handler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication that is not a tutorial snippet
&lt;/h2&gt;

&lt;p&gt;Pick a database and say yes to authentication, and the generated project gets a complete flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;POST /api/auth/register&lt;/code&gt;, &lt;code&gt;login&lt;/code&gt;, &lt;code&gt;refresh&lt;/code&gt;, &lt;code&gt;logout&lt;/code&gt;, &lt;code&gt;logout-all&lt;/code&gt; and &lt;code&gt;GET /api/auth/me&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Short-lived access token&lt;/strong&gt; (a JWT, 15 minutes) and a &lt;strong&gt;rotating refresh token&lt;/strong&gt;. The refresh token is random, stored only as a SHA-256 hash, and replaced every time you use it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reuse detection.&lt;/strong&gt; If an old refresh token is used again (a sign of theft), the whole session family is revoked. A short grace window handles honest double requests such as a flaky network.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookie mode for browser apps.&lt;/strong&gt; Set &lt;code&gt;AUTH_REFRESH_COOKIE=true&lt;/code&gt; and the refresh token lives in an &lt;code&gt;HttpOnly&lt;/code&gt;, &lt;code&gt;SameSite=Strict&lt;/code&gt; cookie, with an &lt;code&gt;Origin&lt;/code&gt; check against CSRF. No token in &lt;code&gt;localStorage&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Account lockout&lt;/strong&gt; after five wrong passwords, and a &lt;strong&gt;common-password blocklist&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;scrypt&lt;/strong&gt; password hashing with OWASP-level parameters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Protecting your own route is one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requireRole&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@rheajs/auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/:id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;requireRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I tested this flow against real MongoDB 7 and MySQL 8.4 over HTTP, including ten parallel refreshes with the same token (exactly one wins), and with a Next.js todo app in a real browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CLI
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rhea create&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;scaffold a project&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rhea dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;run with auto restart and graceful shutdown&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rhea generate module users&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;controller, service, repository, routes, schema, test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rhea doctor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;check your setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rhea security&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;static scan for common config mistakes (&lt;code&gt;--audit&lt;/code&gt; adds npm audit)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rhea docker&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;write a multi-stage, non-root Dockerfile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;rhea build&lt;/code&gt; / &lt;code&gt;rhea start&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;production build and run&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why not NestJS, Fastify or plain Express?
&lt;/h2&gt;

&lt;p&gt;Honest answer: they are all good, and the right choice depends on you.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Plain Express&lt;/strong&gt; is the fastest to start and the slowest to make safe. Rhea.js is Express plus the checklist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NestJS&lt;/strong&gt; is a large, decorator-based framework with dependency injection. Rhea.js is much smaller and has no decorators. It is plain functions and modules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fastify&lt;/strong&gt; is faster and has its own ecosystem. If raw throughput is your top need, use Fastify.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose Rhea.js if you want Express and a safe starting point, with a layout your whole team can predict.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest part
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance.&lt;/strong&gt; On a trivial route Rhea.js reaches about 60% of the throughput of bare Express on my machine, because it does real work on every request (IDs, logging, headers, limits, checks). The numbers and the method are in &lt;a href="https://github.com/dev-shamsali/Rhea.js-framework/blob/main/BENCHMARKS.md" rel="noopener noreferrer"&gt;BENCHMARKS.md&lt;/a&gt;. If you need raw speed and none of the checks, use bare Express.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security review.&lt;/strong&gt; Rhea.js is used in production by me. It has &lt;strong&gt;not&lt;/strong&gt; had an independent security review. I wrote a &lt;a href="https://github.com/dev-shamsali/Rhea.js-framework/blob/main/SECURITY_AUDIT.md" rel="noopener noreferrer"&gt;self-audit&lt;/a&gt; that lists what was tested, what was fixed, and what is still open. If you can review it, I would love that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not included yet:&lt;/strong&gt; server-side sessions, OAuth/OIDC, MFA, password reset, and an ORM. The rate limit is per process unless you pass a shared store.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stability.&lt;/strong&gt; From 1.0 it follows semantic versioning, and the docs say exactly what the public API is.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it and tell me what breaks
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-rhea my-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Docs: &lt;a href="https://rhea.devcodehub.cloud" rel="noopener noreferrer"&gt;https://rhea.devcodehub.cloud&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/dev-shamsali/Rhea.js-framework" rel="noopener noreferrer"&gt;https://github.com/dev-shamsali/Rhea.js-framework&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;npm: &lt;a href="https://www.npmjs.com/org/rheajs" rel="noopener noreferrer"&gt;https://www.npmjs.com/org/rheajs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try it, I would like to hear what was confusing or broken. Bug reports, questions and pull requests are all welcome. If you find a vulnerability, please follow &lt;code&gt;SECURITY.md&lt;/code&gt; and report it privately.&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Building Settla: An AI-Powered Payment &amp; Settlement Automation Platform</title>
      <dc:creator>Shams Ali Shaikh</dc:creator>
      <pubDate>Tue, 06 Oct 2026 09:03:22 +0000</pubDate>
      <link>https://dev.to/shamsalishaikh/building-settla-an-ai-powered-payment-settlement-automation-platform-dmn</link>
      <guid>https://dev.to/shamsalishaikh/building-settla-an-ai-powered-payment-settlement-automation-platform-dmn</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/mlh-hackathon"&gt;MLH x DEV Writing Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;For the &lt;strong&gt;Paytm AI Hackathon&lt;/strong&gt;, I built &lt;strong&gt;Settla&lt;/strong&gt;, an AI-powered payment and settlement automation platform designed to simplify payment operations, refunds, vendor management, and workflow automation.&lt;/p&gt;

&lt;p&gt;The idea came from a simple observation: payment operations can become complicated when you have to deal with multiple transactions, vendors, refunds, and settlement processes manually.&lt;/p&gt;

&lt;p&gt;I wanted to build something where AI wasn't just used as a chatbot, but could actually become part of the workflow.&lt;/p&gt;

&lt;p&gt;That's where &lt;strong&gt;Settla&lt;/strong&gt; came in.&lt;/p&gt;

&lt;p&gt;The goal was to create a platform where users could interact with payment operations through an intelligent interface while the underlying system handled the actual business logic, integrations, and automation.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Architecture
&lt;/h3&gt;

&lt;p&gt;I built Settla as a full-stack application with an architecture focused on automation and extensibility.&lt;/p&gt;

&lt;p&gt;The overall workflow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
  ↓
Settla Frontend
  ↓
Backend API
  ↓
AI / MCP Layer
  ↓
Payment Services
  ↓
n8n Automation
  ↓
Settlement / Refund Workflow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The backend handles the core application logic, while the automation layer is designed to connect different services and execute workflows.&lt;/p&gt;

&lt;p&gt;I also focused heavily on testing during development.&lt;/p&gt;

&lt;p&gt;The project currently includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;135 backend tests&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;9 frontend unit tests&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;13 browser E2E tests&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was important because payment-related workflows need predictable behavior. A small mistake in a payment or refund workflow can have much bigger consequences than a normal application bug.&lt;/p&gt;

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

&lt;p&gt;One of my biggest takeaways from building Settla was that &lt;strong&gt;AI is only one part of an AI-powered product&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The difficult part is building everything around it.&lt;/p&gt;

&lt;p&gt;You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reliable APIs&lt;/li&gt;
&lt;li&gt;Authentication and authorization&lt;/li&gt;
&lt;li&gt;Proper business logic&lt;/li&gt;
&lt;li&gt;Tool permissions&lt;/li&gt;
&lt;li&gt;Error handling&lt;/li&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;li&gt;Workflow automation&lt;/li&gt;
&lt;li&gt;External service integrations&lt;/li&gt;
&lt;li&gt;Observability and maintainability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI becomes much more useful when it can safely interact with these systems.&lt;/p&gt;

&lt;p&gt;That changed the way I think about AI applications.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Let's add an AI chatbot."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I started thinking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What can the AI actually do inside the system?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's a much more interesting engineering problem.&lt;/p&gt;

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

&lt;p&gt;I built Settla as a working full-stack application during the hackathon.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Links
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/dev-shamsali/settla-frontend" rel="noopener noreferrer"&gt;https://github.com/dev-shamsali/settla-frontend&lt;/a&gt; , &lt;a href="https://github.com/dev-shamsali/settla-backend" rel="noopener noreferrer"&gt;https://github.com/dev-shamsali/settla-backend&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="https://settla.devcodehub.cloud/" rel="noopener noreferrer"&gt;https://settla.devcodehub.cloud/&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;The intended Settla workflow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Request
     ↓
AI Agent
     ↓
Tool / MCP
     ↓
Payment Operation
     ↓
Automation Workflow
     ↓
Settla Backend
     ↓
Result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is to make complex payment operations easier to understand and automate instead of requiring users to manually perform every individual step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Partner Technologies
&lt;/h2&gt;

&lt;p&gt;One of the most interesting parts of building Settla was working with &lt;strong&gt;n8n&lt;/strong&gt; and exploring &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  n8n
&lt;/h3&gt;

&lt;p&gt;I used &lt;strong&gt;n8n&lt;/strong&gt; as the foundation for the automation layer.&lt;/p&gt;

&lt;p&gt;Instead of putting every automation directly into the backend, n8n allows workflows to be composed visually and connected to different services.&lt;/p&gt;

&lt;p&gt;For Settla, this opens up possibilities such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Payment Created
      ↓
Validate Transaction
      ↓
Process Workflow
      ↓
Update Settla
      ↓
Trigger Settlement
      ↓
Notify User
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the system easier to extend as more integrations are added.&lt;/p&gt;

&lt;h3&gt;
  
  
  MCP
&lt;/h3&gt;

&lt;p&gt;I also explored &lt;strong&gt;Model Context Protocol&lt;/strong&gt; to connect AI systems with external tools.&lt;/p&gt;

&lt;p&gt;This was one of the most interesting technical parts of the project.&lt;/p&gt;

&lt;p&gt;Instead of having an AI model simply generate text, MCP allows the AI layer to interact with tools that expose real application functionality.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
 ↓
AI
 ↓
MCP
 ↓
Tool
 ↓
External Service
 ↓
Result
 ↓
AI
 ↓
User
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach made me think about AI agents differently.&lt;/p&gt;

&lt;p&gt;The model doesn't need to know everything.&lt;/p&gt;

&lt;p&gt;It needs access to the &lt;strong&gt;right tools&lt;/strong&gt;, with the &lt;strong&gt;right permissions&lt;/strong&gt;, and the application needs to enforce the business rules.&lt;/p&gt;

&lt;p&gt;That separation between intelligence, tools, and business logic is something I found particularly valuable while building Settla.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hackathon Experience
&lt;/h2&gt;

&lt;p&gt;I participated in the &lt;strong&gt;Paytm AI Hackathon&lt;/strong&gt; with Settla.&lt;/p&gt;

&lt;p&gt;We didn't win this time.&lt;/p&gt;

&lt;p&gt;Honestly, we weren't as prepared as we should have been.&lt;/p&gt;

&lt;p&gt;But the experience was still extremely valuable.&lt;/p&gt;

&lt;p&gt;The hackathon brought together developers, AI enthusiasts, builders, and people experimenting with completely different ideas.&lt;/p&gt;

&lt;p&gt;I got the opportunity to discuss AI agents, payment systems, automation, MCP, architecture, and product ideas with other developers.&lt;/p&gt;

&lt;p&gt;What I enjoyed most was the environment.&lt;/p&gt;

&lt;p&gt;Everyone was trying to build something under a limited amount of time.&lt;/p&gt;

&lt;p&gt;That creates a completely different development experience.&lt;/p&gt;

&lt;p&gt;You have to constantly ask:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What should we build first?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can we realistically finish?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What needs to be tested?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What should we leave for later?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And most importantly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can we actually demonstrate what we built?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That last question is something I learned the hard way.&lt;/p&gt;

&lt;p&gt;Building the product is one thing.&lt;/p&gt;

&lt;p&gt;Building it, testing it, preparing the demo, and presenting it effectively are completely different challenges.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I'll Remember
&lt;/h3&gt;

&lt;p&gt;I didn't leave the hackathon with a trophy.&lt;/p&gt;

&lt;p&gt;I left with something else:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;experience.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I learned more about building AI-powered systems, explored MCP and workflow automation, met developers and AI enthusiasts, discussed ideas with other builders, and understood where we need to improve for the next hackathon.&lt;/p&gt;

&lt;p&gt;Most importantly, Settla gave me an opportunity to experiment with an idea that combines:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI + Payments + MCP + Automation + Full-Stack Engineering&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And that's something I'm proud of building.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Settla started as a hackathon project.&lt;/p&gt;

&lt;p&gt;But while building it, it became much more than just an idea.&lt;/p&gt;

&lt;p&gt;It became an experiment in how AI can interact with real systems instead of simply generating responses.&lt;/p&gt;

&lt;p&gt;I didn't win the hackathon.&lt;/p&gt;

&lt;p&gt;But I built something.&lt;/p&gt;

&lt;p&gt;I tested it.&lt;/p&gt;

&lt;p&gt;I learned from it.&lt;/p&gt;

&lt;p&gt;I met great developers.&lt;/p&gt;

&lt;p&gt;And I know exactly what I need to improve for the next one.&lt;/p&gt;

&lt;p&gt;Sometimes the most valuable outcome of a hackathon isn't the prize.&lt;/p&gt;

&lt;p&gt;It's knowing what you're capable of building next.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Built by Shams Ali Shaikh.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>mlhacks</category>
      <category>devchallenge</category>
      <category>hackathon</category>
    </item>
    <item>
      <title>Your Code Isn't Done When It Works</title>
      <dc:creator>Shams Ali Shaikh</dc:creator>
      <pubDate>Fri, 02 Oct 2026 06:13:21 +0000</pubDate>
      <link>https://dev.to/shamsalishaikh/your-code-isnt-done-when-it-works-40m9</link>
      <guid>https://dev.to/shamsalishaikh/your-code-isnt-done-when-it-works-40m9</guid>
      <description>&lt;h1&gt;
  
  
  Your Code Isn't Done When It Works
&lt;/h1&gt;

&lt;p&gt;One of the biggest lessons I've learned as a developer is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Getting an application to work is only the beginning.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;During development, we usually focus on one question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Does it work?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But production asks much harder questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can it handle traffic?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens when the server restarts?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens when the database goes down?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens when an API starts receiving unexpected requests?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can we deploy a new version without breaking the existing one?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can we find out what went wrong at 2 AM?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's where software engineering becomes more than just writing code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Localhost Is a Very Friendly Environment
&lt;/h2&gt;

&lt;p&gt;On localhost, everything feels perfect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application starts.&lt;/p&gt;

&lt;p&gt;The database is nearby.&lt;/p&gt;

&lt;p&gt;Environment variables are available.&lt;/p&gt;

&lt;p&gt;You have full access to the machine.&lt;/p&gt;

&lt;p&gt;And if something breaks, you simply restart it.&lt;/p&gt;

&lt;p&gt;Production doesn't care about any of that.&lt;/p&gt;

&lt;p&gt;Production has:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Users
Traffic
DNS
SSL
Nginx
Firewalls
Processes
Databases
Logs
Backups
Monitoring
CI/CD
Security
Failures
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And occasionally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Why is this server using 100% CPU?"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's when the fun begins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing Code vs Engineering Software
&lt;/h2&gt;

&lt;p&gt;Writing code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getUser&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Engineering the system around that code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How is the request authenticated?
        ↓
How is the API protected?
        ↓
What happens if the database fails?
        ↓
How is the error logged?
        ↓
How is the application monitored?
        ↓
How is the new version deployed?
        ↓
How do we roll it back?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code might be only a few lines.&lt;/p&gt;

&lt;p&gt;The engineering around it can involve an entire architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production Changes Your Definition of "Done"
&lt;/h2&gt;

&lt;p&gt;For me, a feature isn't really finished when:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Feature works
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A better definition is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Feature works
     +
Feature is tested
     +
Feature is secure
     +
Feature is observable
     +
Feature is deployable
     +
Feature is maintainable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a very different mindset.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Deployment Lesson
&lt;/h2&gt;

&lt;p&gt;I've spent a lot of time working with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next.js&lt;/li&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;MongoDB&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Nginx&lt;/li&gt;
&lt;li&gt;PM2&lt;/li&gt;
&lt;li&gt;GitHub Actions&lt;/li&gt;
&lt;li&gt;Linux servers&lt;/li&gt;
&lt;li&gt;CI/CD&lt;/li&gt;
&lt;li&gt;VPS infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And one thing becomes obvious very quickly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The application is only one part of the system.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A typical production flow might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Developer
    |
    v
GitHub
    |
    v
CI/CD
    |
    v
Production Server
    |
    +---- Nginx
    |
    +---- Application
    |
    +---- Database
    |
    +---- Monitoring
    |
    +---- Logs
    |
    v
Users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every layer can fail.&lt;/p&gt;

&lt;p&gt;And every layer needs to be understood.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mindset Shift
&lt;/h2&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Does my code work?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Start asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What happens when my code doesn't work?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's where better engineering decisions start.&lt;/p&gt;

&lt;p&gt;Build for failure.&lt;/p&gt;

&lt;p&gt;Log for debugging.&lt;/p&gt;

&lt;p&gt;Monitor for visibility.&lt;/p&gt;

&lt;p&gt;Automate deployments.&lt;/p&gt;

&lt;p&gt;Secure your infrastructure.&lt;/p&gt;

&lt;p&gt;Keep backups.&lt;/p&gt;

&lt;p&gt;Document your systems.&lt;/p&gt;

&lt;p&gt;And most importantly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't make production the place where you discover how your application works.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm Shams Ali Shaikh, and I'm documenting what I learn while building, deploying, and maintaining real-world applications.&lt;/p&gt;

&lt;p&gt;Because writing code is satisfying.&lt;/p&gt;

&lt;p&gt;But making that code survive production?&lt;/p&gt;

&lt;p&gt;That's where the real engineering begins.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>When Your Next.js App Works on Port 3000 but Production Says Nope</title>
      <dc:creator>Shams Ali Shaikh</dc:creator>
      <pubDate>Thu, 10 Sep 2026 17:57:01 +0000</pubDate>
      <link>https://dev.to/shamsalishaikh/when-your-nextjs-app-works-on-port-3000-but-production-says-nope-3f4h</link>
      <guid>https://dev.to/shamsalishaikh/when-your-nextjs-app-works-on-port-3000-but-production-says-nope-3f4h</guid>
      <description>&lt;p&gt;When Your Next.js App Works on Port 3000 but Production Says Nope &lt;/p&gt;

&lt;p&gt;If you've ever deployed a Next.js application, you've probably experienced this:&lt;/p&gt;

&lt;p&gt;Localhost: Works perfectly. Production: 502 Bad Gateway. &lt;/p&gt;

&lt;p&gt;Your application is running.&lt;/p&gt;

&lt;p&gt;Your process manager says it's online.&lt;/p&gt;

&lt;p&gt;The server looks healthy.&lt;/p&gt;

&lt;p&gt;And somehow, the browser still says:&lt;/p&gt;

&lt;p&gt;"Nope."&lt;/p&gt;

&lt;p&gt;This is where understanding Nginx reverse proxying becomes extremely useful.&lt;/p&gt;

&lt;p&gt;I'm Shams Ali Shaikh, and in this post, I'll walk through one of the most common patterns I use when deploying Next.js and Node.js applications to a production server.&lt;/p&gt;

&lt;p&gt;The Basic Problem &lt;/p&gt;

&lt;p&gt;When running a Next.js application locally, you might use:&lt;/p&gt;

&lt;p&gt;npm run dev &lt;/p&gt;

&lt;p&gt;and access it through:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In production, you might instead run:&lt;/p&gt;

&lt;p&gt;npm run build npm run start &lt;/p&gt;

&lt;p&gt;Your application is now listening on a port such as:&lt;/p&gt;

&lt;p&gt;127.0.0.1:3000 &lt;/p&gt;

&lt;p&gt;But your users aren't going to visit:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://your-server-ip:3000" rel="noopener noreferrer"&gt;http://your-server-ip:3000&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;They expect:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://example.com" rel="noopener noreferrer"&gt;https://example.com&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;That's where Nginx comes in.&lt;/p&gt;

&lt;p&gt;What Is Nginx Doing Here? &lt;/p&gt;

&lt;p&gt;Think of Nginx as the receptionist sitting in front of your application.&lt;/p&gt;

&lt;p&gt;The user talks to Nginx.&lt;/p&gt;

&lt;p&gt;Nginx talks to your application.&lt;/p&gt;

&lt;p&gt;The application doesn't need to be directly exposed to the internet.&lt;/p&gt;

&lt;p&gt;The architecture looks like this:&lt;/p&gt;

&lt;p&gt;Internet | v &lt;a href="https://example.com" rel="noopener noreferrer"&gt;https://example.com&lt;/a&gt; | v +---------+ | Nginx | +---------+ | Reverse Proxy | v 127.0.0.1:3000 | v Next.js &lt;/p&gt;

&lt;p&gt;This simple architecture solves a lot of deployment problems.&lt;/p&gt;

&lt;p&gt;Basic Nginx Configuration &lt;/p&gt;

&lt;p&gt;A basic configuration can look like this:&lt;/p&gt;

&lt;p&gt;server { listen 80; server_name example.com &lt;a href="http://www.example.com" rel="noopener noreferrer"&gt;www.example.com&lt;/a&gt;; location / { proxy_pass &lt;a href="http://127.0.0.1:3000" rel="noopener noreferrer"&gt;http://127.0.0.1:3000&lt;/a&gt;; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } &lt;/p&gt;

&lt;p&gt;The important part is:&lt;/p&gt;

&lt;p&gt;proxy_pass &lt;a href="http://127.0.0.1:3000" rel="noopener noreferrer"&gt;http://127.0.0.1:3000&lt;/a&gt;; &lt;/p&gt;

&lt;p&gt;This tells Nginx:&lt;/p&gt;

&lt;p&gt;"When someone requests this domain, forward the request to the application running on port 3000."&lt;/p&gt;

&lt;p&gt;Testing the Configuration &lt;/p&gt;

&lt;p&gt;After changing the Nginx configuration, don't immediately restart everything.&lt;/p&gt;

&lt;p&gt;First test the configuration:&lt;/p&gt;

&lt;p&gt;sudo nginx -t &lt;/p&gt;

&lt;p&gt;If the configuration is valid, reload Nginx:&lt;/p&gt;

&lt;p&gt;sudo systemctl reload nginx &lt;/p&gt;

&lt;p&gt;This is a small habit that can save you from turning a configuration change into a production incident.&lt;/p&gt;

&lt;p&gt;What If You Get a 502? &lt;/p&gt;

&lt;p&gt;This is where things become interesting.&lt;/p&gt;

&lt;p&gt;If Nginx returns:&lt;/p&gt;

&lt;p&gt;502 Bad Gateway &lt;/p&gt;

&lt;p&gt;don't immediately start changing random Nginx settings.&lt;/p&gt;

&lt;p&gt;First check whether your application is actually running.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;pm2 status &lt;/p&gt;

&lt;p&gt;Then test the application directly:&lt;/p&gt;

&lt;p&gt;curl &lt;a href="http://127.0.0.1:3000" rel="noopener noreferrer"&gt;http://127.0.0.1:3000&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;If this doesn't respond, the problem probably isn't Nginx.&lt;/p&gt;

&lt;p&gt;Your application might have:&lt;/p&gt;

&lt;p&gt;Crashed Failed to start Started on another port Failed because of environment variables Failed during the production build Been stopped by PM2 or another process manager &lt;/p&gt;

&lt;p&gt;If curl works but the domain doesn't, then investigate the Nginx configuration, DNS, SSL, firewall, or networking.&lt;/p&gt;

&lt;p&gt;Checking Nginx Logs &lt;/p&gt;

&lt;p&gt;When things still aren't clear, logs become your best friend.&lt;/p&gt;

&lt;p&gt;Check the Nginx error log:&lt;/p&gt;

&lt;p&gt;sudo tail -f /var/log/nginx/error.log &lt;/p&gt;

&lt;p&gt;You can also inspect the access log:&lt;/p&gt;

&lt;p&gt;sudo tail -f /var/log/nginx/access.log &lt;/p&gt;

&lt;p&gt;Logs usually give you a much better answer than repeatedly refreshing the browser and hoping for a miracle.&lt;/p&gt;

&lt;p&gt;One Server, Multiple Applications &lt;/p&gt;

&lt;p&gt;One of the reasons I like this architecture is that you can run multiple applications on the same server.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;app.example.com | v Nginx | v 127.0.0.1:3000 Next.js api.example.com | v Nginx | v 127.0.0.1:5000 Node.js admin.example.com | v Nginx | v 127.0.0.1:4000 Next.js &lt;/p&gt;

&lt;p&gt;Nginx becomes the traffic controller.&lt;/p&gt;

&lt;p&gt;Different domains can point to different applications and ports.&lt;/p&gt;

&lt;p&gt;Adding HTTPS &lt;/p&gt;

&lt;p&gt;In a real production environment, you generally don't want users accessing your application through plain HTTP.&lt;/p&gt;

&lt;p&gt;The production flow becomes:&lt;/p&gt;

&lt;p&gt;User | | HTTPS :443 v Nginx | | HTTP v 127.0.0.1:3000 | v Next.js &lt;/p&gt;

&lt;p&gt;Nginx can terminate the TLS connection while your application continues running internally.&lt;/p&gt;

&lt;p&gt;This also means your application doesn't necessarily need to manage the public SSL connection itself.&lt;/p&gt;

&lt;p&gt;My Production Debugging Checklist &lt;/p&gt;

&lt;p&gt;When a deployed Next.js application isn't working, I usually go layer by layer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is the application running? pm2 status 2. Is the application responding? curl &lt;a href="http://127.0.0.1:3000" rel="noopener noreferrer"&gt;http://127.0.0.1:3000&lt;/a&gt; 3. Is Nginx running? sudo systemctl status nginx 4. Is the configuration valid? sudo nginx -t 5. What does Nginx say? sudo tail -f /var/log/nginx/error.log 6. Is DNS pointing to the correct server? &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Check the domain's DNS records.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is HTTPS configured correctly? &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Check the certificate and TLS configuration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is the required port accessible? &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Check your firewall and server networking rules.&lt;/p&gt;

&lt;p&gt;The important part is not to troubleshoot everything at once.&lt;/p&gt;

&lt;p&gt;Start from the application and move outward.&lt;/p&gt;

&lt;p&gt;Application ↓ Port ↓ Process ↓ Nginx ↓ HTTPS ↓ DNS ↓ Internet The Bigger Lesson &lt;/p&gt;

&lt;p&gt;Deployment is not simply:&lt;/p&gt;

&lt;p&gt;git push → website &lt;/p&gt;

&lt;p&gt;A production application is a collection of interconnected layers.&lt;/p&gt;

&lt;p&gt;Developer ↓ GitHub ↓ CI/CD ↓ Production Server ↓ Docker / PM2 ↓ Next.js / Node.js ↓ Nginx ↓ HTTPS ↓ Domain ↓ Users &lt;/p&gt;

&lt;p&gt;When you understand each layer, debugging becomes much easier.&lt;/p&gt;

&lt;p&gt;You stop asking:&lt;/p&gt;

&lt;p&gt;"Why isn't my website working?"&lt;/p&gt;

&lt;p&gt;And start asking:&lt;/p&gt;

&lt;p&gt;"Which layer is failing?"&lt;/p&gt;

&lt;p&gt;That change in thinking is one of the most useful things I've learned while working with production deployments.&lt;/p&gt;

&lt;p&gt;Because "it works on my machine" might be a perfectly valid development statement.&lt;/p&gt;

&lt;p&gt;It just isn't a very convincing production strategy.&lt;/p&gt;

&lt;p&gt;I'm documenting what I learn while building and deploying real applications, from localhost to production.&lt;/p&gt;

&lt;p&gt;More deployment and DevOps guides coming soon.&lt;/p&gt;

&lt;p&gt;— Shams Ali Shaikh&lt;/p&gt;

&lt;p&gt;Software Engineer | MERN Stack | Next.js | Node.js | DevOps | Deployment&lt;/p&gt;

</description>
      <category>deployment</category>
      <category>devops</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>From “It Works on My Machine” to Production: My DevOps Journey</title>
      <dc:creator>Shams Ali Shaikh</dc:creator>
      <pubDate>Tue, 01 Sep 2026 13:13:00 +0000</pubDate>
      <link>https://dev.to/shamsalishaikh/from-it-works-on-my-machine-to-production-my-devops-journey-2kk1</link>
      <guid>https://dev.to/shamsalishaikh/from-it-works-on-my-machine-to-production-my-devops-journey-2kk1</guid>
      <description>&lt;h1&gt;
  
  
  From “It Works on My Machine” to “Why Is Production Down?”
&lt;/h1&gt;

&lt;p&gt;Hi, I’m Shams Ali Shaikh, a Software Engineer passionate about building applications and figuring out how to make them actually work in production.&lt;/p&gt;

&lt;p&gt;Writing code is one thing.&lt;/p&gt;

&lt;p&gt;Deploying it without breaking the server is a completely different adventure.&lt;/p&gt;

&lt;p&gt;Over the past few projects, I’ve been exploring application deployment, servers, DevOps, infrastructure automation, and production architecture.&lt;/p&gt;

&lt;p&gt;Here are some of the topics I’ll be sharing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How I Deploy Next.js Applications Using Nginx&lt;/li&gt;
&lt;li&gt;Complete Docker Deployment Guide for Node.js&lt;/li&gt;
&lt;li&gt;CI/CD Pipeline Using GitHub Actions&lt;/li&gt;
&lt;li&gt;Terraform for Beginners: Infrastructure Automation&lt;/li&gt;
&lt;li&gt;How I Configure Production Servers&lt;/li&gt;
&lt;li&gt;MERN Application Deployment Architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because building an application is only half the job.&lt;/p&gt;

&lt;p&gt;The real challenge starts when you hear:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"It works perfectly on my local machine."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then production introduces you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nginx configuration issues&lt;/li&gt;
&lt;li&gt;Docker containers that suddenly stop&lt;/li&gt;
&lt;li&gt;Missing environment variables&lt;/li&gt;
&lt;li&gt;SSL certificate problems&lt;/li&gt;
&lt;li&gt;Firewall rules&lt;/li&gt;
&lt;li&gt;Port conflicts&lt;/li&gt;
&lt;li&gt;PM2 processes&lt;/li&gt;
&lt;li&gt;CI/CD pipeline failures&lt;/li&gt;
&lt;li&gt;And, of course, the legendary 502 Bad Gateway&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My goal is to document everything I learn while building, deploying, breaking, fixing, and optimizing modern web applications.&lt;/p&gt;

&lt;p&gt;I’ll be sharing practical experiences around:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MERN Stack Development&lt;/li&gt;
&lt;li&gt;Next.js&lt;/li&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Nginx&lt;/li&gt;
&lt;li&gt;GitHub Actions&lt;/li&gt;
&lt;li&gt;CI/CD&lt;/li&gt;
&lt;li&gt;VPS Deployment&lt;/li&gt;
&lt;li&gt;Terraform&lt;/li&gt;
&lt;li&gt;DevOps&lt;/li&gt;
&lt;li&gt;Production Infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No unnecessary theory. No overcomplicated tutorials.&lt;/p&gt;

&lt;p&gt;Just practical development, real deployment problems, infrastructure challenges, and solutions discovered along the way.&lt;/p&gt;

&lt;p&gt;If you're interested in building applications and taking them from localhost to production, follow along.&lt;/p&gt;

&lt;p&gt;Because writing the code is easy.&lt;/p&gt;

&lt;p&gt;Finding out why it works locally but not in production is where the real character development begins.&lt;/p&gt;

&lt;p&gt;— Shams Ali Shaikh&lt;br&gt;
Software Engineer | MERN Stack | DevOps | Deployment&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>devops</category>
      <category>docker</category>
      <category>terraform</category>
    </item>
  </channel>
</rss>
