<?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: Jim Zandueta</title>
    <description>The latest articles on DEV Community by Jim Zandueta (@jimzandueta).</description>
    <link>https://dev.to/jimzandueta</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%2F184387%2Fbff514f7-ba23-468a-9a24-6e44b5c53f33.jpg</url>
      <title>DEV Community: Jim Zandueta</title>
      <link>https://dev.to/jimzandueta</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jimzandueta"/>
    <language>en</language>
    <item>
      <title>I Built an AI App That Gives You Superpowers, But Makes Them Useless</title>
      <dc:creator>Jim Zandueta</dc:creator>
      <pubDate>Wed, 08 Apr 2026 03:51:52 +0000</pubDate>
      <link>https://dev.to/jimzandueta/i-built-an-ai-app-that-gives-you-superpowers-but-makes-them-useless-kfl</link>
      <guid>https://dev.to/jimzandueta/i-built-an-ai-app-that-gives-you-superpowers-but-makes-them-useless-kfl</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is a submission for the &lt;a href="https://dev.to/devteam/join-our-april-fools-challenge-for-a-chance-at-tea-rrific-prizes-1ofa"&gt;DEV April Fools Challenge&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

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

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

&lt;p&gt;I built a full-stack AI app that gives you the superpower you ask for, then ruins it with one tiny condition.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You open the site.
&lt;/li&gt;
&lt;li&gt;You rub a magical lamp.
&lt;/li&gt;
&lt;li&gt;A genie shows up.
&lt;/li&gt;
&lt;li&gt;You make a wish.
&lt;/li&gt;
&lt;li&gt;The app grants it in a way that makes the whole thing basically useless.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://cursed-powers--jimzandueta.replit.app/" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;cursed-powers--jimzandueta.replit.app&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;You can become invisible, but only your internal organs.&lt;/li&gt;
&lt;li&gt;You can shape-shift, but only into a slightly uglier version of yourself.&lt;/li&gt;
&lt;li&gt;You can hear other people's thoughts, but only in extinct languages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So yes, it works.&lt;/p&gt;

&lt;p&gt;It just works toward a completely worthless outcome.&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%2Fuga0rkcf37tfnytlxrq4.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%2Fuga0rkcf37tfnytlxrq4.png" alt="Genie" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The idea was simple. I wanted to interpret "useless" a little sideways.&lt;/p&gt;

&lt;p&gt;Instead of making something broken, I made something polished whose output is useless on purpose.&lt;/p&gt;

&lt;p&gt;The app does what it says. The infrastructure is real. The end result is still nonsense.&lt;/p&gt;

&lt;p&gt;So I did not build a useless app.&lt;br&gt;&lt;br&gt;
I built an app that mass-produces uselessness.&lt;/p&gt;

&lt;p&gt;And because I apparently cannot leave a joke alone once it starts working, I also over-engineered it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

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

&lt;p&gt;The repo includes the app code, infra setup, docs, ADRs, API design, tests, and enough delivery process to make the whole thing feel weirdly official.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/jimzandueta" rel="noopener noreferrer"&gt;
        jimzandueta
      &lt;/a&gt; / &lt;a href="https://github.com/jimzandueta/cursed-powers" rel="noopener noreferrer"&gt;
        cursed-powers
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Cursed Powers&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/jimzandueta/cursed-powers/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667" alt="MIT License"&gt;&lt;/a&gt;
&lt;a href="https://github.com/jimzandueta/cursed-powers/CONTRIBUTING.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/dd0b24c1e6776719edb2c273548a510d6490d8d25269a043dfabbd38419905da/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5052732d77656c636f6d652d627269676874677265656e2e737667" alt="PRs Welcome"&gt;&lt;/a&gt;
&lt;a href="https://datatracker.ietf.org/doc/html/rfc2324" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e15a37604340a26c9d8538c9b32ad5cc656b5255a039afb416996db13ccc2d2c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4854435043502d52464325323032333234253230436f6d706c69616e742d626c756576696f6c6574" alt="HTCPCP Compliant"&gt;&lt;/a&gt;
&lt;a href="https://github.com/jimzandueta/cursed-powers/infra/terraform/" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/04a8a0a9eb02eb35d30ca2eee66d5edec8626589b06907953413f07a6fee21ae/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4961432d5465727261666f726d2d374234324243" alt="Terraform"&gt;&lt;/a&gt;
&lt;a href="https://github.com/jimzandueta/cursed-powers/docs/adr/" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/966f38896b0c4c8f11f3a3ebbd6d2d0e83dcf02545f64ab9dea49dc0b0ebb5a1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646f63732d39253230414452732d696e666f726d6174696f6e616c" alt="ADRs"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Every superpower has a catch™&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Cursed Powers is a full-stack web application that combines AI with interactive storytelling. Users rub a magic lamp to summon a genie, make a superpower wish, and receive a hilariously cursed interpretation of their wish powered by AI.&lt;/p&gt;
&lt;p&gt;The engineering is production-grade. The usefulness is thoroughly cursed.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interactive Lamp Experience&lt;/strong&gt;: Animated lamp-rubbing interface that triggers genie summoning&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dual AI Providers&lt;/strong&gt;: Fallback-capable integration with Google Gemini 2.5 Flash and OpenAI GPT-4o-mini&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security-First Backend&lt;/strong&gt;: Rate limiting, abuse detection, request signing, CAPTCHA verification, and content moderation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Results&lt;/strong&gt;: WebSocket-ready architecture with progressive result streaming&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise Deployment&lt;/strong&gt;: Production-ready infrastructure with AWS ECS Fargate, CloudFront CDN, WAF, and automated scaling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comprehensive Testing&lt;/strong&gt;: 192 unit tests (100% API coverage) + 14 E2E browser tests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type-Safe&lt;/strong&gt;: 100% TypeScript with strict mode across frontend and backend&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Architecture&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;                         ┌──────────────────────────────┐
                         │        CloudFront CDN        │
                         │&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/jimzandueta/cursed-powers" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





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

&lt;p&gt;Because the infrastructure is part of the punchline, I wanted to show not just the app, but the machinery behind it.&lt;/p&gt;

&lt;p&gt;This project only works as a joke if the output is ridiculous and the implementation is treated with an unreasonable amount of seriousness.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture, unfortunately
&lt;/h3&gt;

&lt;p&gt;Under the magical lamp and cursed wishes, this project runs on a stack that is much more serious than the idea deserves.&lt;/p&gt;

&lt;p&gt;That is part of the joke too. This entire system exists to reliably produce unusable superpowers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                         ┌──────────────────────────────┐
                         │        CloudFront CDN        │
                         │     + WAF (4 rule groups)    │
                         └──────────────┬───────────────┘
                                        │
                         ┌──────────────▼─────────────────┐
                         │     Application Load Balancer  │
                         │   (TLS 1.3, path-based routing)│
                         └───────┬──────────────┬─────────┘
                                 │              │
                    /api/*       │              │    /*
                   ┌─────────────▼──┐   ┌──────▼────────────┐
                   │   ECS Fargate  │   │   ECS Fargate     │
                   │   Fastify API  │   │   Next.js Web     │
                   │                │   │                   │
                   │  ┌──────────┐  │   │  Security Headers │
                   │  │ Helmet   │  │   │  HSTS, CSP, etc.  │
                   │  │ Rate Lim │  │   └───────────────────┘
                   │  │ Circuit  │  │
                   │  │ Breakers │  │
                   │  └──────────┘  │
                   └───────┬────────┘
                           │
              ┌────────────▼────────────┐
              │    EFS (Encrypted)      │
              │    SQLite + WAL mode    │
              │    Daily backups        │
              └─────────────────────────┘
                           │
            ┌──────────────┼──────────────┐
            │              │              │
      ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼──────┐
      │  Gemini   │ │  OpenAI   │ │  OpenAI    │
      │  2.5 Flash│ │  GPT-4o   │ │  Moderation│
      │ (primary) │ │  (backup) │ │  API       │
      └───────────┘ └───────────┘ └────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If someone only looked at the infrastructure, they might assume it powers something financially important.&lt;/p&gt;

&lt;p&gt;It does not.&lt;/p&gt;

&lt;p&gt;It powers a genie that grants wishes badly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend
&lt;/h3&gt;

&lt;p&gt;On the surface, the app needed to feel magical before it felt stupid.&lt;/p&gt;

&lt;p&gt;The frontend uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Next.js 15&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tailwind CSS v4&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Framer Motion&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I did not want this to feel like a generic AI textbox with a lamp pasted on top. I wanted it to feel a little ceremonial: arrive, rub the lamp, summon the genie, make a wish, then wait for the system to ruin it with confidence.&lt;/p&gt;

&lt;p&gt;So the frontend is responsible for the parts that make the joke land:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lamp animation&lt;/li&gt;
&lt;li&gt;genie reveal&lt;/li&gt;
&lt;li&gt;wish input flow&lt;/li&gt;
&lt;li&gt;result rendering&lt;/li&gt;
&lt;li&gt;validation&lt;/li&gt;
&lt;li&gt;API integration&lt;/li&gt;
&lt;li&gt;request handling&lt;/li&gt;
&lt;li&gt;enough theatricality to make the whole thing feel intentional&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Backend
&lt;/h3&gt;

&lt;p&gt;Once the frontend sets the mood, the backend does the deeply unserious serious work.&lt;/p&gt;

&lt;p&gt;The backend uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fastify 5&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Drizzle ORM&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQLite&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zod&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pino&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Helmet&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@fastify/rate-limit&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloudflare Turnstile verification&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;wish submission and validation&lt;/li&gt;
&lt;li&gt;AI orchestration&lt;/li&gt;
&lt;li&gt;cursed power generation&lt;/li&gt;
&lt;li&gt;result retrieval&lt;/li&gt;
&lt;li&gt;gallery and random wish endpoints&lt;/li&gt;
&lt;li&gt;health checks&lt;/li&gt;
&lt;li&gt;moderation&lt;/li&gt;
&lt;li&gt;rate limiting&lt;/li&gt;
&lt;li&gt;request validation&lt;/li&gt;
&lt;li&gt;diagnostics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Honestly, the backend is more serious than the premise deserves.&lt;/p&gt;

&lt;p&gt;That was deliberate.&lt;/p&gt;

&lt;p&gt;If the output is nonsense, the system producing that nonsense should still be solid.&lt;/p&gt;

&lt;h3&gt;
  
  
  Google AI / Gemini usage
&lt;/h3&gt;

&lt;p&gt;At the center of all this is the actual wish-ruining engine.&lt;/p&gt;

&lt;p&gt;Gemini is the main model behind the app.&lt;/p&gt;

&lt;p&gt;I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Gemini 2.5 Flash&lt;/strong&gt; as the primary model&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI GPT-4o-mini&lt;/strong&gt; as the fallback provider&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI Moderation&lt;/strong&gt; in the safety pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI flow is not just "say something random and funny." It follows a simple structure:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;wish → interpret → curse → return a technically valid but practically useless power&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That constraint helped a lot. The outputs became more consistent, easier to read, and usually much funnier.&lt;/p&gt;

&lt;p&gt;The genie is not denying your wish.&lt;br&gt;&lt;br&gt;
The genie is honoring it as maliciously as possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ridiculous over-engineering, on purpose
&lt;/h3&gt;

&lt;p&gt;At this point, the second joke becomes obvious:&lt;/p&gt;

&lt;p&gt;the implementation is wildly disproportionate to the value of the product.&lt;/p&gt;

&lt;p&gt;So naturally, this cursed superpower generator includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;npm workspaces + Turborepo&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;shared type-safe schema package&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenAPI 3.1&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;9 architecture decision records&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Terraform-managed AWS infrastructure&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CloudFront CDN&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AWS WAF&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;an &lt;strong&gt;Application Load Balancer with TLS 1.3&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ECS Fargate&lt;/strong&gt; for both web and API&lt;/li&gt;
&lt;li&gt;encrypted &lt;strong&gt;EFS-backed SQLite in WAL mode&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;multi-stage Dockerfiles&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;docker-compose&lt;/strong&gt; for local development&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI&lt;/strong&gt; with typecheck, lint, unit tests, E2E tests, and commitlint&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;tag-triggered release pipeline&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Husky&lt;/strong&gt; pre-commit, commit-msg, and pre-push hooks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conventional Commits&lt;/strong&gt; enforcement&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;deep health check endpoint&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;runbook&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;an &lt;strong&gt;incident response guide&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;service level agreement&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTCPCP compliance&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A lot of joke projects stop at the concept.&lt;/p&gt;

&lt;p&gt;I wanted this one to keep going until the engineering itself became part of the punchline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Did I mention it also has 100% unit test coverage?&lt;/strong&gt;&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Security, because apparently even cursed wishes need governance
&lt;/h3&gt;

&lt;p&gt;And since I was already making terrible but committed decisions, I also spent real time on security.&lt;/p&gt;

&lt;p&gt;That includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CloudFront + AWS WAF&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Helmet&lt;/strong&gt; security headers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;rate limiting&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloudflare Turnstile&lt;/strong&gt; CAPTCHA support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zod&lt;/strong&gt; schema validation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI provider circuit breakers&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;content moderation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CORS&lt;/strong&gt; configuration&lt;/li&gt;
&lt;li&gt;proxy awareness for real client IP handling&lt;/li&gt;
&lt;li&gt;vulnerability reporting documentation&lt;/li&gt;
&lt;li&gt;dependency monitoring through CI and GitHub alerts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Is this more security planning than most genie interactions require?&lt;br&gt;&lt;br&gt;
Yes.&lt;/p&gt;

&lt;p&gt;Was I going to stop because of that?&lt;br&gt;&lt;br&gt;
Obviously not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Teapot compliance
&lt;/h3&gt;

&lt;p&gt;Is &lt;code&gt;418&lt;/code&gt; and &lt;code&gt;teapot&lt;/code&gt; a super power?&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize category
&lt;/h2&gt;

&lt;p&gt;I would like to be considered for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Best Google AI Usage&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Best Ode to Larry Masinter&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;the main &lt;strong&gt;DEV April Fools Challenge&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This app is not useless because it is broken.&lt;/p&gt;

&lt;p&gt;It is useless because it is &lt;strong&gt;very good at producing unusable results.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is the whole bit.&lt;/p&gt;

&lt;p&gt;Some people use software to solve meaningful problems.&lt;/p&gt;

&lt;p&gt;I used software to build a scalable platform for granting wishes badly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The system is stable.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;The infrastructure is serious.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;The output is useless.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is exactly what I set out to build.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>418challenge</category>
      <category>ai</category>
      <category>showdev</category>
    </item>
    <item>
      <title>The Codex Setup That Worked for Us: Memory, Manifests, and Structured Context</title>
      <dc:creator>Jim Zandueta</dc:creator>
      <pubDate>Wed, 01 Apr 2026 07:14:45 +0000</pubDate>
      <link>https://dev.to/jimzandueta/from-ai-chaos-to-team-flow-codex-boilerplate-that-actually-worked-5fa1</link>
      <guid>https://dev.to/jimzandueta/from-ai-chaos-to-team-flow-codex-boilerplate-that-actually-worked-5fa1</guid>
      <description>&lt;p&gt;&lt;strong&gt;The past few weeks have been wild.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our team recently adopted &lt;strong&gt;AI-assisted programming&lt;/strong&gt; (not vibe-coding). We wanted speed, consistency, and fewer repetitive tasks.&lt;br&gt;&lt;br&gt;
What we got in week one was... chaos.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR&lt;br&gt;
We had &lt;strong&gt;inconsistent AI output&lt;/strong&gt; across teammates, treated it as a &lt;strong&gt;systems problem&lt;/strong&gt;, applied Agentic SDLC principles, and built a &lt;code&gt;.codex&lt;/code&gt; structure that made Codex outputs &lt;strong&gt;far more consistent&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Quick Jump
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What worked (and what didn’t)&lt;/li&gt;
&lt;li&gt;The shift: Agentic Software Development Lifecycle&lt;/li&gt;
&lt;li&gt;What’s inside &lt;code&gt;.codex&lt;/code&gt; (and why it matters)&lt;/li&gt;
&lt;li&gt;How we used it in this repo&lt;/li&gt;
&lt;li&gt;What’s next&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even with detailed technical tickets, our AI agents kept producing outputs that didn’t line up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;different &lt;strong&gt;naming conventions&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;different &lt;strong&gt;folder structures&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;different &lt;strong&gt;approaches to the same problem&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;different &lt;strong&gt;error-handling and testing styles&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every merge felt like stitching code from three different universes.&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%2Fx9qa4grriown1y2r5vf8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9qa4grriown1y2r5vf8.jpg" alt="Distracted Boyfriend Meme" width="750" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Week one energy:&lt;/strong&gt; &lt;em&gt;us trying to keep standards while random AI output keeps walking by.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  What worked (and what didn’t)
&lt;/h2&gt;

&lt;p&gt;We tested different setups.&lt;/p&gt;

&lt;p&gt;A strong &lt;code&gt;CLAUDE.md&lt;/code&gt; helped a lot early. Claude Opus was excellent at reasoning and breaking work down step by step.&lt;br&gt;&lt;br&gt;
The issue for us was practical: &lt;strong&gt;limits and timeouts&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Since our company sponsors Codex, we moved to Codex as our main tool. First impression? &lt;strong&gt;A bit lackluster&lt;/strong&gt; compared to Claude out of the box.&lt;/p&gt;

&lt;p&gt;That pushed us to a better question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maybe this isn’t just a model problem. Maybe it’s a &lt;u&gt;system problem&lt;/u&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="//i.imgflip.com/ao4a58.jpg" class="article-body-image-wrapper"&gt;&lt;img src="//i.imgflip.com/ao4a58.jpg" alt="Drake Meme"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The shift: Agentic Software Development Lifecycle
&lt;/h2&gt;

&lt;p&gt;Quick diff:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traditional SDLC: &lt;strong&gt;mostly human implementation through linear phases&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A-SDLC: &lt;strong&gt;human + AI-agent collaboration in tight feedback loops&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In A-SDLC, developers don’t just write code. We &lt;strong&gt;orchestrate&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;guardrails&lt;/li&gt;
&lt;li&gt;context&lt;/li&gt;
&lt;li&gt;fast reviews&lt;/li&gt;
&lt;li&gt;memory updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And yes, we’re &lt;strong&gt;actively applying&lt;/strong&gt; these principles in real day-to-day work, not just talking about them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;better prompts&lt;/li&gt;
&lt;li&gt;tighter feedback loops&lt;/li&gt;
&lt;li&gt;stronger project memory&lt;/li&gt;
&lt;li&gt;clear constraints, patterns, and checklists&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once we treated this as a systems problem, &lt;strong&gt;output quality improved fast&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That’s why I built this boilerplate: to showcase the &lt;code&gt;.codex&lt;/code&gt; setup that worked best for us.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/jimzandueta/nestjs-http-server-boilerplate-codex-ai-assisted" rel="noopener noreferrer"&gt;github.com/jimzandueta/codex-nestjs&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  What’s inside &lt;code&gt;.codex&lt;/code&gt; (and why it matters)
&lt;/h2&gt;

&lt;p&gt;This isn’t just a random folder. It’s the &lt;strong&gt;operating system&lt;/strong&gt; for consistent AI-assisted engineering.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.codex/
  START_HERE.md
  RULES.md
  MANIFEST.yaml
  instructions/
  patterns/
  anti-patterns/
  checklists/
  skills/
  prompts/
  templates/
  overrides/
  memory/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2F%2F%2Fi.imgflip.com%2Fao4aax.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2F%2F%2Fi.imgflip.com%2Fao4aax.jpg" alt="Expanding Brain Meme" width="500" height="701"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1) &lt;code&gt;START_HERE.md&lt;/code&gt; + &lt;code&gt;RULES.md&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;These are your baseline guardrails.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Output Rules&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; Reuse existing patterns before inventing new ones.
&lt;span class="p"&gt;2.&lt;/span&gt; Keep diffs minimal.
&lt;span class="p"&gt;3.&lt;/span&gt; Never commit secrets.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This alone prevents a lot of “same task, five coding styles” situations.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) &lt;code&gt;MANIFEST.yaml&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is context routing. It tells the agent what to load for each task type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;task_routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;new-feature&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.codex/instructions/global.md&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.codex/patterns/repo-structure.md&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.codex/patterns/error-handling.md&lt;/span&gt;
    &lt;span class="na"&gt;skills&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.codex/skills/new-feature/SKILL.md&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So agents don’t start cold. They start with the right playbook.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) &lt;code&gt;instructions/&lt;/code&gt;, &lt;code&gt;patterns/&lt;/code&gt;, &lt;code&gt;anti-patterns/&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;instructions/&lt;/code&gt;: how to work&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;patterns/&lt;/code&gt;: preferred way to build&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;anti-patterns/&lt;/code&gt;: what to avoid&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of this as turning tribal team knowledge into repeatable, machine-readable engineering practice.&lt;/p&gt;

&lt;h3&gt;
  
  
  4) &lt;code&gt;checklists/&lt;/code&gt;, &lt;code&gt;skills/&lt;/code&gt;, &lt;code&gt;prompts/&lt;/code&gt;, &lt;code&gt;templates/&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is the day-to-day execution layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;checklists/&lt;/code&gt;: quality gates&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;skills/&lt;/code&gt;: repeatable workflows&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;prompts/&lt;/code&gt;: reusable prompt scaffolds&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;templates/&lt;/code&gt;: starter artifacts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example checklist snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Tests&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] New logic has happy path + failure test
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Coverage stays at 100% threshold
&lt;span class="p"&gt;-&lt;/span&gt; [ ] No flaky tests introduced
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5) &lt;code&gt;overrides/&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This lets you keep generic Codex assets while declaring project reality.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generic pattern: “recommended structure”&lt;/li&gt;
&lt;li&gt;project override: “this NestJS repo uses &lt;code&gt;src/common&lt;/code&gt;, &lt;code&gt;src/clients&lt;/code&gt;, &lt;code&gt;src/modules&lt;/code&gt;, etc.”&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6) &lt;code&gt;memory/&lt;/code&gt; (the secret sauce)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;This is where consistency compounds:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;memory/project-facts.md&lt;/code&gt; → stable project truths&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;memory/decisions.md&lt;/code&gt; → ADR-style decisions/tradeoffs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;memory/learned-patterns.md&lt;/code&gt; → recurring conventions discovered during work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As new decisions are made between the developer and AI agent, memory gets updated so future tasks inherit the &lt;strong&gt;same context and tradeoffs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A realistic flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developer: “We need &lt;code&gt;requestId&lt;/code&gt; in logs for traceability.”&lt;/li&gt;
&lt;li&gt;Agent: “Two options: &lt;code&gt;AsyncLocalStorage&lt;/code&gt; or explicit propagation.”&lt;/li&gt;
&lt;li&gt;Team decision: explicit propagation first (simpler + easier to test).&lt;/li&gt;
&lt;li&gt;Memory updates: ADR + project convention + learned pattern.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sample ADR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;### ADR-002: Standardize request correlation IDs in HTTP logs&lt;/span&gt;

&lt;span class="gs"&gt;**Date**&lt;/span&gt;: 2026-04-02
&lt;span class="gs"&gt;**Status**&lt;/span&gt;: Accepted

&lt;span class="gs"&gt;**Context**&lt;/span&gt;: Debugging incidents was slow because logs across layers were hard to correlate.
&lt;span class="gs"&gt;**Decision**&lt;/span&gt;: Add &lt;span class="sb"&gt;`requestId`&lt;/span&gt; at the HTTP boundary and propagate it through services/clients.
&lt;span class="gs"&gt;**Consequences**&lt;/span&gt;: Better traceability, with slight method-signature overhead.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sample project facts update:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Conventions&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Logging: include &lt;span class="sb"&gt;`requestId`&lt;/span&gt; in structured logs for HTTP flows.
&lt;span class="p"&gt;-&lt;/span&gt; Request context: generate/forward &lt;span class="sb"&gt;`x-request-id`&lt;/span&gt; at ingress and propagate downstream.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sample learned pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;### LP-001: Propagate requestId from boundary to integrations&lt;/span&gt;

&lt;span class="gs"&gt;**Observed**&lt;/span&gt;: Missing correlation fields made multi-step failures harder to debug.
&lt;span class="gs"&gt;**Rule**&lt;/span&gt;: Controllers create context; services/clients forward &lt;span class="sb"&gt;`requestId`&lt;/span&gt;; logs include it at each layer.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This memory layer is the difference between &lt;strong&gt;“new agent, same mistakes”&lt;/strong&gt; and &lt;strong&gt;“new agent, same team brain.”&lt;/strong&gt;&lt;/p&gt;

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




&lt;h2&gt;
  
  
  How we used it in this repo (&lt;a href="https://github.com/jimzandueta/nestjs-http-server-boilerplate-codex-ai-assisted" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)
&lt;/h2&gt;

&lt;p&gt;Using this &lt;code&gt;.codex&lt;/code&gt; setup, we built a NestJS sample HTTP server with consistent architecture and quality gates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clear boundaries (&lt;code&gt;common&lt;/code&gt;, &lt;code&gt;clients&lt;/code&gt;, &lt;code&gt;integrations&lt;/code&gt;, &lt;code&gt;modules&lt;/code&gt;, &lt;code&gt;http&lt;/code&gt;, &lt;code&gt;errors&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;validated runtime config (&lt;code&gt;HOST&lt;/code&gt;, &lt;code&gt;PORT&lt;/code&gt;, &lt;code&gt;NODE_ENV&lt;/code&gt;, &lt;code&gt;LOG_LEVEL&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;structured logging&lt;/li&gt;
&lt;li&gt;reusable HTTP client with timeout/retry&lt;/li&gt;
&lt;li&gt;typed external API errors + global exception filter&lt;/li&gt;
&lt;li&gt;sample feature module (&lt;code&gt;posts&lt;/code&gt;) using JSONPlaceholder&lt;/li&gt;
&lt;li&gt;strict tests with &lt;strong&gt;100% coverage thresholds&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;open-source docs (&lt;code&gt;LICENSE&lt;/code&gt;, &lt;code&gt;CONTRIBUTING&lt;/code&gt;, &lt;code&gt;CODE_OF_CONDUCT&lt;/code&gt;, &lt;code&gt;SECURITY&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So this repo isn’t just “another Nest starter.”&lt;br&gt;&lt;br&gt;
It’s a &lt;strong&gt;working example of structured AI-assisted delivery&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  One important note
&lt;/h2&gt;

&lt;p&gt;Codex setups are usually &lt;strong&gt;stack-specific&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This &lt;code&gt;.codex&lt;/code&gt; is tuned for a NestJS HTTP app. I maintain a different Codex baseline for Terraform/infrastructure because workflows, anti-patterns, and quality gates are different.&lt;/p&gt;

&lt;p&gt;Same core idea, different playbook.&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s next
&lt;/h2&gt;

&lt;p&gt;I’ll keep evolving this repo with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;richer feature module examples&lt;/li&gt;
&lt;li&gt;better integration patterns&lt;/li&gt;
&lt;li&gt;stricter review automations&lt;/li&gt;
&lt;li&gt;stack-specific Codex variants&lt;/li&gt;
&lt;li&gt;deeper AI-agent orchestration experiments using open-source tools like LangChain, Langfuse, and local models&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your team is in that “week one AI chaos” phase, start with structure first.&lt;br&gt;&lt;br&gt;
Model quality matters, but &lt;strong&gt;system quality matters more&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6uwzflh2jp2aw0om185.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6uwzflh2jp2aw0om185.jpg" alt="One Does Not Simply Meme" width="651" height="384"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  IMPORTANT: Here's a picture of my cat!
&lt;/h2&gt;

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

</description>
      <category>softwareengineering</category>
      <category>ai</category>
      <category>nestjs</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to Allow Users to Upload and Download Data from AWS S3 Without Direct Access Using Pre-Signed URLs?</title>
      <dc:creator>Jim Zandueta</dc:creator>
      <pubDate>Sat, 24 Dec 2022 05:49:34 +0000</pubDate>
      <link>https://dev.to/jimzandueta/how-to-allow-users-to-upload-and-download-data-from-aws-s3-without-direct-access-using-pre-signed-urls-h33</link>
      <guid>https://dev.to/jimzandueta/how-to-allow-users-to-upload-and-download-data-from-aws-s3-without-direct-access-using-pre-signed-urls-h33</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Amazon Simple Storage Service (AWS S3) is a popular cloud storage service that allows users to store and retrieve data from a variety of sources. While S3 buckets are set to public by default, there are times when it is necessary to restrict access to specific users or groups. Direct access to the bucket in these scenarios may pose security risks and limit flexibility.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Direct access to an AWS S3 bucket necessitates exposing the AWS access keys and secret keys to users, which can result in unauthorized access to the bucket and its contents. Furthermore, using this method, it may be impossible to control specific actions or limit access time.&lt;/p&gt;




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

&lt;p&gt;Pre-signed URLs provide a secure solution by allowing users to access specific objects in the bucket without exposing the AWS access keys and secret keys. Pre-signed URLs can also be used to restrict specific actions that users can take and to limit the amount of time that a user has access to the data.&lt;/p&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;p&gt;To generate pre-signed URLs in TypeScript, you can use the &lt;code&gt;aws-sdk&lt;/code&gt; package, which provides a &lt;code&gt;getSignedUrl&lt;/code&gt; method that can be used to generate a pre-signed URL for a specific S3 object. Here's an example of how to use &lt;code&gt;getSignedUrl&lt;/code&gt; to generate a pre-signed URL for downloading an S3 object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Generate a pre-signed URL for an S3 object&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generatePresignedUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;expiration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;S3&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;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Expires&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;expiration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSignedUrlPromise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getObject&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Example usage&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-s3-bucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path/to/my/object.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expiration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="c1"&gt;// URL will expire in 60 seconds&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&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;generatePresignedUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expiration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Outputs a pre-signed URL that can be used to access the object&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To generate a pre-signed URL for uploading an S3 object, you can use the putObject method in a similar way:&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;AWS&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;aws-sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;express&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;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Configure the AWS SDK with your S3 bucket's credentials&lt;/span&gt;
&lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;accessKeyId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ACCESS_KEY_ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;secretAccessKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;S3&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Create an Express.js router&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Route for generating a pre-signed URL for uploading a file to S3&lt;/span&gt;
&lt;span class="nx"&gt;router&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;/upload&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;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="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Check if the file was included in the request&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;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;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No file provided&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Get the file and other parameters from the request body&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Generate a pre-signed URL for uploading the file to S3&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;ContentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;ACL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;private&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Set the ACL to "private"&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSignedUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;putObject&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Send the pre-signed URL back to the client&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Send an error response if something went wrong&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Export the router&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="o"&gt;---&lt;/span&gt;

&lt;span class="c1"&gt;// Example Usage&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;axios&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;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Function to upload a file to S3 using a pre-signed URL&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;uploadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Set the headers for the request&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="c1"&gt;// Make the PUT request to the pre-signed URL&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Check the status of the response&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Outputs 201 if upload was successful&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Example usage&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, world!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello.txt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/plain&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;server_url&amp;gt;/upload&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;uploadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;






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

&lt;p&gt;Pre-signed URLs are a convenient and secure way for users to access data in an AWS S3 bucket without granting direct access. To use pre-signed URLs, use the AWS SDK to generate a URL for a specific object in the bucket. The generated URL can then be provided to the user, who can use it to access the object within the time period specified in the URL.&lt;/p&gt;




&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/PresignedUrlUploadObject.html" rel="noopener noreferrer"&gt;AWS documentation on pre-signed URLs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getSignedUrl-property" rel="noopener noreferrer"&gt;AWS SDK for JavaScript documentation on getSignedUrl method&lt;/a&gt;: &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>How to connect to the same host with different SSH keys?</title>
      <dc:creator>Jim Zandueta</dc:creator>
      <pubDate>Tue, 16 Aug 2022 14:12:00 +0000</pubDate>
      <link>https://dev.to/jimzandueta/setup-your-ssh-configuration-file-1m9e</link>
      <guid>https://dev.to/jimzandueta/setup-your-ssh-configuration-file-1m9e</guid>
      <description>&lt;p&gt;&lt;strong&gt;Required Reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/jimzandueta/generate-an-ssh-key-pair-2fcc"&gt;Generate an SSH key pair&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Optional Reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;None&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup your SSH configuration file
&lt;/h2&gt;

&lt;p&gt;When connecting to a remote server via SSH, we would use the command line to specify the remote user name, hostname, and port, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ssh tony@avengers.com &lt;span class="nt"&gt;-p&lt;/span&gt; 4321
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can connect to the server using the same options as in the previous command by typing &lt;code&gt;ssh avengers&lt;/code&gt; after adding the following lines to your &lt;code&gt;~/.ssh/config&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Host avengers
    HostName avengers.com
    User tony
    Port 4321
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also specify which SSH key to use when connecting to a specific server in the configuration file by setting &lt;code&gt;IdentityFile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Host avengers
    HostName avengers.com
    User tony
    Port 4321
    IdentityFile ~/.ssh/id_rsa_avengers

Host marvel
    HostName marvel.com
    User tony
    Port 8080
    IdentityFile ~/.ssh/id_rsa_marvel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The use of &lt;code&gt;IdentityFile&lt;/code&gt; is especially useful when connecting to the same hostname with different SSH keys. A real-world example would be having multiple Github accounts, such as personal and work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Host github_personal
    HostName github.com
    IdentityFile ~/.ssh/github_personal

Host github_work
    HostName github.com
    IdentityFile ~/.ssh/github_work

IdentityFile ~/.ssh/id_rsa 
&lt;span class="c"&gt;#default ssh key to use for all other hosts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the configuration file above, we can clone repositories from your personal Github account with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git clone git@github_personal:tonystark/ultron.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that instead of &lt;code&gt;@github.com&lt;/code&gt; as the host name, we use &lt;code&gt;@github_personal&lt;/code&gt; as defined in the configuration file.&lt;/p&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Updating the configuration file:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open your favorite terminal&lt;/li&gt;
&lt;li&gt;Create/Open the SSH configuration file
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nano ~/.ssh/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;-&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.ssh.com/academy/ssh/config"&gt;git config file syntax&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>tutorial</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>How to generate a secure SSH key pair?</title>
      <dc:creator>Jim Zandueta</dc:creator>
      <pubDate>Tue, 16 Aug 2022 13:39:00 +0000</pubDate>
      <link>https://dev.to/jimzandueta/generate-an-ssh-key-pair-2fcc</link>
      <guid>https://dev.to/jimzandueta/generate-an-ssh-key-pair-2fcc</guid>
      <description>&lt;p&gt;&lt;strong&gt;Required Reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;None&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Optional Reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;None&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate an SSH key pair
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Open your favorite terminal&lt;/li&gt;
&lt;li&gt;Run the ssh-keygen command
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; rsa &lt;span class="nt"&gt;-b&lt;/span&gt; 4096 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"tonystark@avengers.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;INFO: For increased security, the type flag &lt;code&gt;-t rsa&lt;/code&gt; and the bits &lt;code&gt;flag -b 4096&lt;/code&gt; are required. The comment flag &lt;code&gt;-C "tonystark@avengers.com"&lt;/code&gt; allows us to easily identify who owns the SSH key.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Specify the key file name. Default is &lt;code&gt;id_rsa&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Enter a passphrase *&lt;em&gt;optional&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kBWO3CPz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n8qdopzivgs2inx9xt69.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kBWO3CPz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n8qdopzivgs2inx9xt69.png" alt="ssh-keygen-sample" width="880" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;WARNING: If you already have a default SSH key ~/.ssh/id_rsa, &lt;strong&gt;DO NOT OVERWRITE IT&lt;/strong&gt;. If you are not careful, you will lose SSH access to your cloud servers and git platforms. Instead, give your new SSH key a new name, such as id_rsa_avengers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.ssh.com/academy/ssh/keygen"&gt;ssh-keygen | SSH Tutorial &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>tutorial</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>How to setup your global (and local) git profile?</title>
      <dc:creator>Jim Zandueta</dc:creator>
      <pubDate>Tue, 16 Aug 2022 13:29:00 +0000</pubDate>
      <link>https://dev.to/jimzandueta/setup-your-git-profile-3i06</link>
      <guid>https://dev.to/jimzandueta/setup-your-git-profile-3i06</guid>
      <description>&lt;p&gt;&lt;strong&gt;Required Reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;None&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Optional Reading:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;None&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup your git profile
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Open your favorite terminal&lt;/li&gt;
&lt;li&gt;Set your git username
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.name &lt;span class="s2"&gt;"Tony Stark"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Set your git email
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.email tonystark@avengers.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Set your git editor *&lt;em&gt;optional&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; core.editor nano 
&lt;span class="c"&gt;# you can also use emacs (nostalgic) or vim (adventurous). &lt;/span&gt;
&lt;span class="c"&gt;# Vim is the default editor.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Review your settings
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--list&lt;/span&gt; &lt;span class="nt"&gt;--show-origin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The global flag --global will apply the configuration to the current operating system profile/user. If you want to apply your configuration at the local level, navigate to the project's root directory (where the.git folder is located) and run the git config commands without the global flag, or use the local flag --local to be more verbose.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.atlassian.com/git/tutorials/setting-up-a-repository/git-config"&gt;git config | Atlassian Git Tutorial &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup"&gt;Git - First-Time Git Setup &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>tutorial</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>macOS: Moving Your Notification to a Different Display</title>
      <dc:creator>Jim Zandueta</dc:creator>
      <pubDate>Fri, 08 May 2020 09:26:07 +0000</pubDate>
      <link>https://dev.to/jimzandueta/macos-moving-your-notification-to-a-different-display-17bi</link>
      <guid>https://dev.to/jimzandueta/macos-moving-your-notification-to-a-different-display-17bi</guid>
      <description>&lt;p&gt;My current display configuration includes my Macbook to the right and a 27" BenQ Monitor in front of me. The larger screen houses all of my work-related applications, while the smaller one houses my calendar, calculator, and Spotify.&lt;/p&gt;

&lt;p&gt;For as long as I can remember, all of my notifications would appear on the screen of my Macbook. I never thought about it before, but after getting in trouble for missing several critical Slack messages, I realized I needed to do something about it.&lt;/p&gt;

&lt;p&gt;I did some research and here's what I discovered:&lt;/p&gt;

&lt;p&gt;Setting up multiple displays on macOS is a simple process. Simply navigate to System Preferences &amp;gt; Displays &amp;gt; Arrangement and drag the screens to the desired location.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ip3QzgpX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sopy9q2td40hfmviem9z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ip3QzgpX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sopy9q2td40hfmviem9z.png" alt="Display Arrangement" width="780" height="623"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take note of the white bar on top of the small screen icon. That, believe it or not, is the &lt;strong&gt;Menu Bar&lt;/strong&gt;. It handles a lot of things, including notifications! &lt;/p&gt;

&lt;p&gt;I simply dragged it to the screen icon on the left, and after a few flashes, my 27" display became my main monitor (displaying notifications), and my Macbook became the extension monitor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---_Wocll2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ljonxhabfks995jzll4x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---_Wocll2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ljonxhabfks995jzll4x.png" alt="Alt Text" width="780" height="619"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, moving the menu bar icon will &lt;strong&gt;rearrange&lt;/strong&gt; your desktop. So, if you have your applications organized across multiple desktops, consider cleaning them up first.&lt;/p&gt;

&lt;p&gt;I hope this was helpful. Happy coding!&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>macos</category>
      <category>productivity</category>
      <category>tips</category>
    </item>
  </channel>
</rss>
