<?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: Carlos Rogerio Orioli</title>
    <description>The latest articles on DEV Community by Carlos Rogerio Orioli (@carlosorioli).</description>
    <link>https://dev.to/carlosorioli</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%2F307916%2Fc276c9a7-5df3-4d03-ab69-17058c3b7c1e.jpeg</url>
      <title>DEV Community: Carlos Rogerio Orioli</title>
      <link>https://dev.to/carlosorioli</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/carlosorioli"/>
    <language>en</language>
    <item>
      <title>MyPuppy — A Brazilian Virtual Pet That Remembers You</title>
      <dc:creator>Carlos Rogerio Orioli</dc:creator>
      <pubDate>Sun, 16 Aug 2026 20:45:23 +0000</pubDate>
      <link>https://dev.to/carlosorioli/mypuppy-a-brazilian-virtual-pet-that-remembers-you-2j53</link>
      <guid>https://dev.to/carlosorioli/mypuppy-a-brazilian-virtual-pet-that-remembers-you-2j53</guid>
      <description>&lt;h2&gt;
  
  
  MyPuppy — A Brazilian Virtual Pet That Remembers You
&lt;/h2&gt;

&lt;p&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-08-13"&gt;Weekend Challenge: Dog Days Edition&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;MyPuppy is a mobile-first virtual pet inspired by the digital toys of the 1990s, reimagined around Brazilian mixed-breed dogs.&lt;/p&gt;

&lt;p&gt;Users can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create an account;&lt;/li&gt;
&lt;li&gt;adopt Caramelo, Fiapo de Manga, or Malhadinho;&lt;/li&gt;
&lt;li&gt;name their dog;&lt;/li&gt;
&lt;li&gt;feed, play with, walk, and give Cafuné to their pet;&lt;/li&gt;
&lt;li&gt;watch hunger, happiness, energy, affection, hygiene, and walk needs evolve over time;&lt;/li&gt;
&lt;li&gt;build memories and personality traits;&lt;/li&gt;
&lt;li&gt;receive contextual reactions and notifications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal was to make the pet feel alive without making the experience stressful or punishing. The dog never dies, and missing a few days creates gentle moments such as sleeping, boredom, or excitement when the owner returns.&lt;/p&gt;

&lt;p&gt;The product voice is warm, funny, affectionate, and slightly chaotic — like a Brazilian friend speaking excellent English.&lt;/p&gt;

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

&lt;p&gt;Live demo: &lt;a href="https://mypuppy-pied.vercel.app/" rel="noopener noreferrer"&gt;MyPuppy&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;The application is designed primarily for mobile, but also works on desktop.&lt;/p&gt;

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

&lt;p&gt;GitHub repository: &lt;a href="https://github.com/rogeriorioli/mypuppy" rel="noopener noreferrer"&gt;MyPuppy&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;MyPuppy was built with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next.js App Router;&lt;/li&gt;
&lt;li&gt;React;&lt;/li&gt;
&lt;li&gt;TypeScript;&lt;/li&gt;
&lt;li&gt;Tailwind CSS;&lt;/li&gt;
&lt;li&gt;PostgreSQL;&lt;/li&gt;
&lt;li&gt;Prisma;&lt;/li&gt;
&lt;li&gt;Gemini through the Google Gen AI SDK;&lt;/li&gt;
&lt;li&gt;Web Push API;&lt;/li&gt;
&lt;li&gt;VAPID;&lt;/li&gt;
&lt;li&gt;Service Worker;&lt;/li&gt;
&lt;li&gt;Vitest;&lt;/li&gt;
&lt;li&gt;Vercel.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most important architectural decision was separating the deterministic pet engine from the AI layer.&lt;/p&gt;

&lt;p&gt;The virtual pet engine owns all game state. It calculates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;time-based decay;&lt;/li&gt;
&lt;li&gt;action effects;&lt;/li&gt;
&lt;li&gt;cooldowns;&lt;/li&gt;
&lt;li&gt;event detection;&lt;/li&gt;
&lt;li&gt;sleep states;&lt;/li&gt;
&lt;li&gt;absence behavior;&lt;/li&gt;
&lt;li&gt;personality progression;&lt;/li&gt;
&lt;li&gt;owner-returned events.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The engine is implemented as pure, testable functions and does not depend on React, the database, or Gemini.&lt;/p&gt;

&lt;p&gt;Gemini is only used to express what the dog feels. It generates short reactions and notification copy based on a small structured context containing the dog archetype, current state, personality traits, and domain event.&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
text
Domain event
↓
Check reaction cache
↓
Reuse cached reaction or call Gemini
↓
Validate structured response
↓
Use deterministic fallback if necessary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
    </item>
    <item>
      <title>The Polenta Throne: Can You Stir Better Than Your Nonna?</title>
      <dc:creator>Carlos Rogerio Orioli</dc:creator>
      <pubDate>Sat, 08 Aug 2026 19:25:26 +0000</pubDate>
      <link>https://dev.to/carlosorioli/the-polenta-throne-can-you-stir-better-than-your-nonna-1l35</link>
      <guid>https://dev.to/carlosorioli/the-polenta-throne-can-you-stir-better-than-your-nonna-1l35</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/frontend-2026-07-29"&gt;Frontend Challenge - Comfort Food Edition, Perfect Landing&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;For this challenge, I chose a dish that represents the ultimate slow-cooked comfort food: &lt;strong&gt;Polenta&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Making a good polenta requires patience, time, and constant stirring. To capture this essence, I built an interactive landing page called &lt;strong&gt;"set point." (Orioli Chef)&lt;/strong&gt; where the user has to physically engage with the page to "cook" the dish. &lt;/p&gt;

&lt;p&gt;Instead of a traditional static landing page, I created an immersive, gamified experience. The user must click and drag a wooden spoon to stir the polenta. As you stir, the polenta thickens (the "hardness" level increases), and the process deliberately takes time, mimicking the real-life slow cooking required to reach the perfect "set point" (o ponto da polenta). &lt;/p&gt;

&lt;p&gt;It features dynamic UI elements like realistic steam and bubble animations, real-time status updates based on the thickness, and a "social proof" toast notification system to show other users who are also enjoying the slow process.&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;🔗 &lt;a href="https://orioli-polenta.vercel.app/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

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

&lt;p&gt;The journey of building this was focused on translating a physical, analog feeling into a digital interface. &lt;/p&gt;

&lt;p&gt;At first, the stirring logic was too fast and even had an automatic "simmering" timer that progressed without the user's input. I realized this defeated the purpose of the comfort food theme! I removed the automatic timers and recalibrated the interaction so that it strictly requires a deliberate "click and drag" to stir. I also replaced a generic cursor with a custom SVG wooden spoon to make it feel more authentic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I'm particularly proud of:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The custom interaction loop that tracks mouse movement (delta X and Y) to calculate the stirring speed and the progressive "hardness" of the polenta. &lt;/li&gt;
&lt;li&gt;The immersive animations (bubbles, steam, and the trail left by the spoon) that make the pot feel alive.&lt;/li&gt;
&lt;li&gt;The cohesive, warm aesthetic that matches the feeling of comfort food.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What I learned:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to fine-tune pointer events and animation frames (&lt;code&gt;requestAnimationFrame&lt;/code&gt;) to create a smooth, responsive, but intentionally "heavy" drag interaction.&lt;/li&gt;
&lt;li&gt;The importance of pacing in UI design—sometimes making the user work a little harder and slower creates a much more rewarding experience.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Credits:&lt;/strong&gt;&lt;br&gt;
Made with &amp;lt;3 by &lt;a href="https://github.com/rogeriorioli" rel="noopener noreferrer"&gt;Carlos Orioli&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>frontendchallenge</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Criando Blocos Gutenberg Nativos com React (e como usar IA para acelerar o processo)</title>
      <dc:creator>Carlos Rogerio Orioli</dc:creator>
      <pubDate>Thu, 06 Aug 2026 00:49:28 +0000</pubDate>
      <link>https://dev.to/carlosorioli/criando-blocos-gutenberg-nativos-com-react-e-como-usar-ia-para-acelerar-o-processo-4h24</link>
      <guid>https://dev.to/carlosorioli/criando-blocos-gutenberg-nativos-com-react-e-como-usar-ia-para-acelerar-o-processo-4h24</guid>
      <description>&lt;p&gt;Este tutorial mostra como criar um bloco Gutenberg &lt;strong&gt;nativo&lt;/strong&gt; — sem depender do ACF — usando React puro, do zero até o build final. Na segunda parte, explico como usar um agente de IA com &lt;strong&gt;skills&lt;/strong&gt; (arquivos de conhecimento reutilizáveis) e um &lt;strong&gt;harness&lt;/strong&gt; (o "motor" que executa o agente em loop, com ferramentas) para acelerar esse tipo de desenvolvimento no dia a dia.&lt;/p&gt;




&lt;h2&gt;
  
  
  Parte 1 — Criando o bloco nativo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Pré-requisitos
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Node.js instalado&lt;/li&gt;
&lt;li&gt;Um tema ou plugin WordPress local para testar&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@wordpress/scripts&lt;/code&gt;, o toolchain oficial que compila JSX sem você precisar configurar Webpack/Babel manualmente&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Estrutura de pastas
&lt;/h3&gt;

&lt;p&gt;Vamos criar um bloco de "Depoimento" (testimonial), 100% React, sem PHP de render.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-plugin/
├── my-plugin.php
├── package.json
└── src/
    └── testimonial/
        ├── block.json
        ├── index.js
        ├── edit.js
        ├── save.js
        └── editor.scss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Inicializando o projeto
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-plugin &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;my-plugin
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @wordpress/scripts &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;package.json&lt;/code&gt;, adicione os scripts de build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wp-scripts build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wp-scripts start"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. &lt;code&gt;block.json&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Aqui definimos os &lt;strong&gt;attributes&lt;/strong&gt;  são os dados que o próprio Gutenberg gerencia e salva dentro do &lt;code&gt;post_content&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schemas.wp.org/trunk/block.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"apiVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-plugin/testimonial"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Depoimento"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"widgets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"icon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"format-quote"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bloco de depoimento em React puro."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"textdomain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-plugin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"autor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cargo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"depoimento"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"supports"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"html"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"editorScript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"file:./index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"editorStyle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"file:./editor.css"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"style"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"file:./style.css"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. &lt;code&gt;edit.js&lt;/code&gt; — a interface no editor
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;useBlockProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RichText&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="s1"&gt;@wordpress/block-editor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Edit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAttributes&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;autor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cargo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;depoimento&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;attributes&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;blockProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useBlockProps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testimonial-edit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;blockProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RichText&lt;/span&gt;
        &lt;span class="na"&gt;tagName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"p"&lt;/span&gt;
        &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Escreva o depoimento..."&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;depoimento&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&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;setAttributes&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;depoimento&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RichText&lt;/span&gt;
        &lt;span class="na"&gt;tagName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"strong"&lt;/span&gt;
        &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Nome do autor"&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;autor&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&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;setAttributes&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;autor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RichText&lt;/span&gt;
        &lt;span class="na"&gt;tagName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"span"&lt;/span&gt;
        &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Cargo"&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cargo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&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;setAttributes&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;cargo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. &lt;code&gt;save.js&lt;/code&gt; — o que vira HTML final salvo no post
&lt;/h3&gt;

&lt;p&gt;Isso substitui totalmente o &lt;code&gt;render.php&lt;/code&gt;. O output desse componente é serializado e gravado em &lt;code&gt;post_content&lt;/code&gt; no momento de salvar/publicar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;useBlockProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RichText&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="s1"&gt;@wordpress/block-editor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;attributes&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;autor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cargo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;depoimento&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;attributes&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;blockProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useBlockProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testimonial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;blockProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;blockquote&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RichText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Content&lt;/span&gt; &lt;span class="na"&gt;tagName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"p"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;depoimento&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;footer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RichText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Content&lt;/span&gt; &lt;span class="na"&gt;tagName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"strong"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;autor&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cargo&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RichText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Content&lt;/span&gt; &lt;span class="na"&gt;tagName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"span"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;` — &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;cargo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;footer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;blockquote&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. &lt;code&gt;index.js&lt;/code&gt; — registro
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;registerBlockType&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="s1"&gt;@wordpress/blocks&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="nx"&gt;Edit&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./edit&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="nx"&gt;save&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./save&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="nx"&gt;metadata&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./block.json&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./editor.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;registerBlockType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metadata&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Edit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;save&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  8. Registrando o bloco no PHP
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="cd"&gt;/**
 * Plugin Name: My Plugin — Testimonial Block
 */&lt;/span&gt;

&lt;span class="nf"&gt;add_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'init'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;register_block_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/build/testimonial'&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;Note que aponta para &lt;code&gt;build/&lt;/code&gt;, não para &lt;code&gt;src/&lt;/code&gt; — é ali que o &lt;code&gt;wp-scripts build&lt;/code&gt; gera os arquivos compilados.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Build
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;Ative o plugin no WordPress, abra o editor e o bloco "Depoimento" já aparece no inserter, pronto pra usar — sem nenhum PHP intermediando o render.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Indo além
&lt;/h3&gt;

&lt;p&gt;A partir daqui, as extensões mais comuns são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Imagem&lt;/strong&gt;: attribute do tipo &lt;code&gt;object&lt;/code&gt; guardando &lt;code&gt;{ url, id, alt }&lt;/code&gt;, usando &lt;code&gt;MediaUpload&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repeater (lista de itens)&lt;/strong&gt;: attribute do tipo &lt;code&gt;array&lt;/code&gt;, renderizado com &lt;code&gt;.map()&lt;/code&gt; tanto no &lt;code&gt;edit.js&lt;/code&gt; quanto no &lt;code&gt;save.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;InnerBlocks&lt;/strong&gt;: permitir que outros blocos sejam aninhados dentro do seu&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Parte 2 — Usando IA (skills + harness) para acelerar esse trabalho
&lt;/h2&gt;

&lt;p&gt;Quando você usa um agente como o Claude Code para esse tipo de tarefa, vale entender dois conceitos que mudam bastante a qualidade do resultado: &lt;strong&gt;harness&lt;/strong&gt; e &lt;strong&gt;skills&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  O que é o "harness"
&lt;/h3&gt;

&lt;p&gt;O harness é o programa que roda o agente em loop: ele manda o prompt pro modelo, recebe de volta uma decisão (rodar um comando, editar um arquivo, ler algo), executa essa ação de verdade no seu sistema, devolve o resultado pro modelo, e repete — até a tarefa terminar. É a "carroceria" em volta do modelo: dá acesso a terminal, sistema de arquivos, git, etc. Sem harness, o modelo só conversa; com harness, ele efetivamente cria pastas, roda &lt;code&gt;npm run build&lt;/code&gt;, edita &lt;code&gt;block.json&lt;/code&gt;, testa e corrige.&lt;/p&gt;

&lt;p&gt;Na prática, isso significa que pra um bloco Gutenberg você pode literalmente pedir "cria um bloco nativo de FAQ com repeater de perguntas e respostas, registra no plugin e roda o build" — e o agente executa passo a passo, igual você faria manualmente, mas sozinho.&lt;/p&gt;

&lt;h3&gt;
  
  
  O que são "skills"
&lt;/h3&gt;

&lt;p&gt;Skills são arquivos de instrução (&lt;code&gt;SKILL.md&lt;/code&gt;) que ficam disponíveis pro agente e são carregados automaticamente quando relevantes. Cada skill documenta um domínio específico — convenções do seu time, padrões de código, checklist de revisão, como aquele projeto em particular estrutura os blocos.&lt;/p&gt;

&lt;p&gt;Para o seu caso de blocos Gutenberg + WordPress, uma skill útil poderia registrar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A estrutura de pastas que seu time usa (&lt;code&gt;src/blocks/&amp;lt;nome&amp;gt;/...&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Se vocês preferem SCSS ou CSS puro, &lt;code&gt;apiVersion&lt;/code&gt; padrão, categoria default&lt;/li&gt;
&lt;li&gt;Convenção de nomenclatura (&lt;code&gt;meu-tema/nome-do-bloco&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Se o projeto usa ACF em paralelo (para blocos que precisam de campo global via post meta) e quando usar cada abordagem&lt;/li&gt;
&lt;li&gt;Trechos de código de referência (exemplo de bloco com &lt;code&gt;InnerBlocks&lt;/code&gt;, exemplo com upload de imagem) que o agente deve seguir como modelo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Isso transforma o agente de "sabe Gutenberg em geral" para "sabe exatamente como &lt;em&gt;o seu projeto&lt;/em&gt; faz Gutenberg" — reduzindo o retrabalho de revisar código que não segue o padrão do time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fluxo prático sugerido
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Escreva uma skill descrevendo os padrões do seu projeto de blocos (pode ser gerada com apoio do próprio agente, revisando blocos já existentes no repositório)&lt;/li&gt;
&lt;li&gt;Peça a criação de um novo bloco em linguagem natural, descrevendo os campos e comportamento&lt;/li&gt;
&lt;li&gt;O agente, com a skill carregada e o harness executando comandos, cria a pasta, o &lt;code&gt;block.json&lt;/code&gt;, &lt;code&gt;edit.js&lt;/code&gt;, &lt;code&gt;save.js&lt;/code&gt;, registra no PHP e roda o build&lt;/li&gt;
&lt;li&gt;Você revisa o diff (como revisaria um PR de qualquer dev) antes de commitar&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Esse combo — harness pra executar e skill pra manter o padrão do projeto — é o que faz a diferença entre "gerar código genérico de Gutenberg" e "gerar código que já nasce do jeito que o seu time trabalha".&lt;/p&gt;




&lt;h2&gt;
  
  
  Resumo
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Sem IA&lt;/th&gt;
&lt;th&gt;Com harness + skill&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Criar estrutura do bloco&lt;/td&gt;
&lt;td&gt;Manual, arquivo por arquivo&lt;/td&gt;
&lt;td&gt;Agente cria tudo de uma vez, seguindo padrão do projeto&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Consistência entre blocos&lt;/td&gt;
&lt;td&gt;Depende de disciplina do time&lt;/td&gt;
&lt;td&gt;Skill garante convenção fixa&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build e teste&lt;/td&gt;
&lt;td&gt;Você roda os comandos&lt;/td&gt;
&lt;td&gt;Agente roda e corrige erros de build sozinho&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Revisão&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Você revisa o diff antes do commit, como um PR normal&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>wordpress</category>
      <category>ai</category>
      <category>webdev</category>
      <category>claude</category>
    </item>
    <item>
      <title>Vibe Code Playground</title>
      <dc:creator>Carlos Rogerio Orioli</dc:creator>
      <pubDate>Mon, 27 Apr 2026 15:41:33 +0000</pubDate>
      <link>https://dev.to/carlosorioli/vibe-code-playground-54pp</link>
      <guid>https://dev.to/carlosorioli/vibe-code-playground-54pp</guid>
      <description>&lt;h1&gt;
  
  
  ✨ Vibe Code Playground
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Vibe Code&lt;/strong&gt; is a curated gallery of high-end UI component prompts. Instead of copying and pasting static code, you copy the "vibe" — highly detailed, technically-focused prompts that you can paste into any LLM (like ChatGPT, Claude, or Gemini) to generate stunning, interactive React + Tailwind CSS components instantly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://vide-code-playground.vercel.app/" rel="noopener noreferrer"&gt;SHOW GALERY&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Curated Prompts&lt;/strong&gt;: Hand-picked instructions for high-end aesthetics (Apple-style, Bento Grid, Glassmorphism, etc.).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code-Centric&lt;/strong&gt;: Every prompt is engineered to return functional React + Tailwind code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vibe Filter&lt;/strong&gt;: Easily browse by style — from "Minimal" to "Cyberpunk".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-Click Copy&lt;/strong&gt;: Get the prompt and go straight to your favorite AI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open Source&lt;/strong&gt;: Community-driven gallery. Adding a new component is as simple as a PR.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt;: Modern functional components and hooks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vite&lt;/strong&gt;: Ultra-fast development and build.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS&lt;/strong&gt;: Utility-first styling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framer Motion&lt;/strong&gt;: Smooth entry animations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🤝 Contributing
&lt;/h2&gt;

&lt;p&gt;We love contributions! Check out our &lt;a href="https://github.com/rogeriorioli/vide-code-playground/blob/main/CONTRIBUTING.md" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt; to see how you can add your own vibes to the gallery. It's the easiest way to help scale this library!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/rogeriorioli/vide-code-playground" rel="noopener noreferrer"&gt;Repository&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Built with ♥ by &lt;a href="https://github.com/rogeriorioli" rel="noopener noreferrer"&gt;Carlos Rogerio Orioli&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Desafio Headless: Checkout Shopify em App React Native com Zustand</title>
      <dc:creator>Carlos Rogerio Orioli</dc:creator>
      <pubDate>Tue, 07 Apr 2026 18:10:07 +0000</pubDate>
      <link>https://dev.to/carlosorioli/desafio-headless-checkout-shopify-em-app-react-native-com-zustand-h19</link>
      <guid>https://dev.to/carlosorioli/desafio-headless-checkout-shopify-em-app-react-native-com-zustand-h19</guid>
      <description>&lt;p&gt;O grande desafio no ecossistema Shopify é garantir que a transição entre a seleção de produtos nativa e o pagamento na &lt;strong&gt;WebView&lt;/strong&gt; seja invisível para o usuário, mantendo a persistência do carrinho via &lt;strong&gt;Storefront API&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Para isso, utilizei o &lt;strong&gt;Zustand&lt;/strong&gt; para o gerenciamento de estado global e o &lt;strong&gt;MMKV&lt;/strong&gt; para garantir uma persistência de dados ultra-rápida, superior ao AsyncStorage tradicional. Confira o passo a passo dessa implementação:&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Store com Zustand e MMKV
&lt;/h3&gt;

&lt;p&gt;A store armazena o &lt;code&gt;checkoutId&lt;/code&gt; e a &lt;code&gt;webUrl&lt;/code&gt;. O uso do &lt;strong&gt;MMKV&lt;/strong&gt; é o "game changer" aqui: ele é cerca de 30x mais rápido que o AsyncStorage, garantindo que o carrinho carregue instantaneamente.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;create&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="s1"&gt;zustand&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createJSONStorage&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="s1"&gt;zustand/middleware&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MMKV&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="s1"&gt;react-native-mmkv&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;storage&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;MMKV&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;mmkvStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;:&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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;:&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getString&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="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;removeItem&lt;/span&gt;&lt;span class="p"&gt;:&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;storage&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="nx"&gt;name&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;useShopifyStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;checkoutId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;webUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;setCheckout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&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;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;checkoutId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;webUrl&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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shopify-storage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;createJSONStorage&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;mmkvStorage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Sincronização via Storefront API (GraphQL)
&lt;/h3&gt;

&lt;p&gt;Antes de levar o usuário para o checkout, sincronizamos os itens locais com a Shopify para gerar (ou atualizar) a URL final de pagamento.&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;syncCheckout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;checkoutId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lineItems&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    mutation checkoutLineItemsReplace($checkoutId: ID!, $lineItems: [CheckoutLineItemInput!]!) {
      checkoutLineItemsReplace(checkoutId: $checkoutId, lineItems: $lineItems) {
        checkout { id, webUrl }
      }
    }
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://SUA-LOJA.myshopify.com/api/2024-01/graphql.json&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;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-Shopify-Storefront-Access-Token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SEU_TOKEN&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;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;checkoutId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lineItems&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. O Checkout na WebView
&lt;/h3&gt;

&lt;p&gt;Utilizamos a &lt;code&gt;webUrl&lt;/code&gt; retornada pela API para abrir o checkout já preenchido, mantendo todas as regras de negócio da loja ativas.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WebView&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="s1"&gt;react-native-webview&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;ShopifyCheckout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;webUrl&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useShopifyStore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;WebView&lt;/span&gt; 
      &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;webUrl&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; 
      &lt;span class="nx"&gt;sharedCookiesEnabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;startInLoadingState&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  O que aprendi?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Arquitetura Agnostica&lt;/strong&gt;: Validar a lógica na VTEX e replicar no Shopify mostra que um bom padrão de projeto sobrevive a qualquer stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: No e-commerce de alto nível que entregamos na &lt;strong&gt;Converte&lt;/strong&gt;, milissegundos salvos com MMKV convertem em vendas.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>reactnative</category>
      <category>shopify</category>
      <category>vtex</category>
      <category>zustand</category>
    </item>
    <item>
      <title>Sincronizando Zustand com VTEX OrderForm no React Native</title>
      <dc:creator>Carlos Rogerio Orioli</dc:creator>
      <pubDate>Mon, 06 Apr 2026 17:22:34 +0000</pubDate>
      <link>https://dev.to/carlosorioli/sincronizando-zustand-com-vtex-orderform-no-react-native-3ab9</link>
      <guid>https://dev.to/carlosorioli/sincronizando-zustand-com-vtex-orderform-no-react-native-3ab9</guid>
      <description>&lt;p&gt;Recentemente, precisei desenvolver uma integração de checkout VTEX dentro de um aplicativo React Native. O desafio era garantir que a experiência de compra fosse fluida, mantendo o estado do carrinho perfeitamente sincronizado entre o ambiente nativo do app e a finalização da compra na WebView.&lt;/p&gt;

&lt;p&gt;Para resolver isso, utilizei o Zustand para o gerenciamento de estado global e a API de Checkout da VTEX para manipular o orderFormId.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Arquitetura da Solução
&lt;/h2&gt;

&lt;p&gt;A ideia central foi: o App gerencia os produtos e quantidades através de uma store leve Zustand e, antes de abrir o checkout, sincronizamos tudo com a VTEX via API.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Gerenciando o Carrinho com Zustand
&lt;/h2&gt;

&lt;p&gt;A store armazena o orderFormId e persiste os dados para que o carrinho não se perca. Aqui, podemos escolher entre o AsyncStorage (padrão) ou o MMKV (para performance ultra-rápida).&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;create&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="s1"&gt;zustand&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createJSONStorage&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="s1"&gt;zustand/middleware&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="nx"&gt;AsyncStorage&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-native-async-storage/async-storage&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MMKV&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="s1"&gt;react-native-mmkv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Opção com MMKV (Alta Performance)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;storage&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;MMKV&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;mmkvStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;:&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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&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="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;:&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getString&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="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;removeItem&lt;/span&gt;&lt;span class="p"&gt;:&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;storage&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="nx"&gt;name&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;useCartStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;orderFormId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
      &lt;span class="na"&gt;setOrderFormId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;orderFormId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;addToCart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&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;set&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})),&lt;/span&gt;
      &lt;span class="na"&gt;clearCart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="na"&gt;orderFormId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cart-storage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// Troque 'mmkvStorage' por 'AsyncStorage' se preferir o padrão&lt;/span&gt;
      &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;createJSONStorage&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;mmkvStorage&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Para esse projeto, utilizei o MMKV pela velocidade de leitura/escrita, mas a estrutura funciona perfeitamente com AsyncStorage também.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Sincronizando com a API da VTEX
&lt;/h2&gt;

&lt;p&gt;Antes de navegar para a tela de checkout, enviamos os itens para o orderForm específico. Isso evita disparar várias chamadas de rede desnecessárias durante a navegação.&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;syncCartWithVtex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orderFormId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;items&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://{ACCOUNT}.vtexcommercestable.com.br/api/checkout/pub/orderForm/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;orderFormId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/items`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;orderItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;seller&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Erro na sincronização:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;DICA: A VTEX às vezes exige que o cabeçalho vtex-id-client-authtoken seja enviado se o usuário já estiver autenticado no app, para que o carrinho não fique como "anônimo"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  3. O Checkout na WebView
&lt;/h2&gt;

&lt;p&gt;A sacada foi é injetar o orderFormId na URL da WebView. Assim, o checkout da VTEX já abre com todos os itens que o usuário escolheu no app.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WebView&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="s1"&gt;react-native-webview&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;VtexCheckout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;orderFormId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCartStore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// URL que vincula a sessão ao carrinho do App&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkoutUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://www.sualoja.com.br/checkout/?orderFormId=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;orderFormId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;#/cart`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;WebView&lt;/span&gt; 
      &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;checkoutUrl&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="nx"&gt;sharedCookiesEnabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;//PARA MANTER A SESSÃO &lt;/span&gt;
      &lt;span class="nx"&gt;startInLoadingState&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Lições aprendidas
&lt;/h2&gt;

&lt;p&gt;Performance: Sincronizar o estado via API antes de abrir a WebView entrega uma experiência muito mais "nativa" do que tentar manipular o DOM da página carregada.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Persistência: O uso do Zustand com middleware de persistência é imbatível para lidar com carrinhos em dispositivos móveis.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Desenvolver soluções de e-commerce de alta performance é o que move a gente na Converte . &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E você, já teve que lidar com essa ponte entre o nativo e o web no e-commerce? Vamos trocar uma ideia nos comentários!&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>zustand</category>
      <category>mobile</category>
      <category>mobilecommerce</category>
    </item>
    <item>
      <title>Nietzsche in a Madhouse</title>
      <dc:creator>Carlos Rogerio Orioli</dc:creator>
      <pubDate>Wed, 01 Apr 2026 18:10:20 +0000</pubDate>
      <link>https://dev.to/carlosorioli/nietzsche-in-a-madhouse-98b</link>
      <guid>https://dev.to/carlosorioli/nietzsche-in-a-madhouse-98b</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/aprilfools-2026"&gt;DEV April Fools Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Nietzsche in a Madhouse&lt;/strong&gt; — A satirical "Anti-Productivity" AI agent. While most AIs try to help you be efficient, this one uses the full arsenal of Western philosophy (nihilism, existentialism, and grandiloquent rhetoric) to argue against your most basic, healthy, and logical life decisions.&lt;/p&gt;

&lt;p&gt;Want to brush your teeth? It's "bacterial genocide." Want to sleep? It's "surrendering your consciousness to the amorphous void."&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://nietzsche-in-a-madhouse-sandy.vercel.app/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/p&gt;

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

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

&lt;p&gt;&lt;a href="https://github.com/rogeriorioli/Nietzsche-in-a-Madhouse" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;br&gt;
The project is built with Next.js and integrated with the Google Gemini API.&lt;br&gt;
The core logic resides in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;app/api/argue/route.ts&lt;/code&gt;: The philosophical persona prompt and Gemini integration.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app/page.tsx&lt;/code&gt;: The clean, "Dark Academia" inspired UI and custom Nietzsche SVG illustration.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Framework:&lt;/strong&gt; Next.js 16 (App Router)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Brain:&lt;/strong&gt; Google Gemini API using the &lt;code&gt;gemini-2.5-flash-lite&lt;/code&gt; model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styling:&lt;/strong&gt; Vanilla CSS with a focus on premium serif typography and a "Claude-esque" minimal aesthetic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persona Engineering:&lt;/strong&gt; A complex system prompt that forces the AI into a "dramatically condescending" mode, ensuring it never agrees with the user and always ends with a devastating rhetorical question.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prize Category
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best Google AI Usage&lt;/strong&gt; — We took one of the most powerful language models in existence and dedicated its entire processing power to gaslighting users into thinking that drinking water is a "surrender to biological determinism." It’s an ode to the "delightfully useless" potential of modern AI.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>418challenge</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Why Next.js is the Ultimate Tool for the BFF (Backend-for-Frontend) Pattern?</title>
      <dc:creator>Carlos Rogerio Orioli</dc:creator>
      <pubDate>Wed, 01 Apr 2026 16:49:03 +0000</pubDate>
      <link>https://dev.to/carlosorioli/why-nextjs-is-the-ultimate-tool-for-the-bff-backend-for-frontend-pattern-4lej</link>
      <guid>https://dev.to/carlosorioli/why-nextjs-is-the-ultimate-tool-for-the-bff-backend-for-frontend-pattern-4lej</guid>
      <description>&lt;p&gt;As a developer, I’m constantly looking for ways to bridge the gap between complex backend architectures and seamless user experiences. If you are dealing with microservices or legacy APIs, you’ve likely faced the classic &lt;strong&gt;"Data Fetching Headache."&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Overfetching &amp;amp; Underfetching
&lt;/h2&gt;

&lt;p&gt;We’ve all been there: your frontend needs a simple user dashboard, but the legacy API returns a massive 2MB JSON with fields you don't need (&lt;strong&gt;Overfetching&lt;/strong&gt;). Or worse, you have to hit four different endpoints just to display a single page (&lt;strong&gt;Underfetching&lt;/strong&gt;). &lt;/p&gt;

&lt;p&gt;This creates latency, drains mobile batteries, and complicates your frontend logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: The BFF Pattern
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Backend-for-Frontend (BFF)&lt;/strong&gt; pattern acts as a specialized intermediary. It aggregates multiple API calls, filters out the "noise," and delivers a clean, optimized payload specifically tailored for the UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Next.js is the "Built-in" BFF
&lt;/h2&gt;

&lt;p&gt;If you are using Next.js (especially with the App Router), you already have a powerful BFF layer without needing to spin up a separate Express or Go server. &lt;/p&gt;

&lt;p&gt;Here is the professional way to structure this: &lt;strong&gt;Service -&amp;gt; Route Handler -&amp;gt; Component.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  1. The Service (The "BFF Logic")
&lt;/h3&gt;

&lt;p&gt;This file handles the "dirty work": fetching from legacy systems, using private keys, and cleaning the data. This stays strictly on the server.&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;// services/apiService.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getProductDashboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;API_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EXTERNAL_API_URL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Securely stored on the server&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/products/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;revalidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// ISR: Cache for 1 hour&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&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="s1"&gt;Failed to fetch from Legacy API&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rawData&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// BFF Logic: Transform and "clean" the data for the UI&lt;/span&gt;
  &lt;span class="c1"&gt;// We only return what the frontend actually uses.&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rawData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`$ &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rawData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price_usd&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;stockStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rawData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inventory&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;In Stock&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Out of Stock&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lastUpdate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLocaleDateString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. The Route Handler (The Internal Bridge)
&lt;/h3&gt;

&lt;p&gt;This acts as your own private API endpoint. It allows your Client Components to trigger data fetching without ever exposing the sensitive Legacy API.&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;// app/api/products/[id]/route.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&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="s1"&gt;next/server&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getProductDashboard&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="s1"&gt;@/services/apiService&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&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="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&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;// Calling our internal service&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&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;getProductDashboard&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="nx"&gt;id&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;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Internal Server Error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. The Client Component (The Consumer)
&lt;/h3&gt;

&lt;p&gt;The UI remains clean and decoupled. It calls &lt;strong&gt;your&lt;/strong&gt; BFF endpoint, receiving the "perfect" object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&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="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProductQuickView&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loadDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// We fetch from our INTERNAL Route Handler, not the legacy API!&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/products/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;result&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"p-4 border rounded"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; 
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loadDetails&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"bg-blue-500 text-white px-4 py-2 rounded"&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Quick View Product
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mt-4"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Price: &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Status: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stockStatus&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Security:&lt;/strong&gt; Your &lt;code&gt;API_SECRET_KEY&lt;/code&gt; never leaks to the browser.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Abstraction:&lt;/strong&gt; If the legacy API changes its JSON structure tomorrow, you only update the &lt;strong&gt;Service&lt;/strong&gt;. Your Route Handlers and Components stay exactly the same.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Performance:&lt;/strong&gt; You reduce the payload size significantly, which is critical for high-conversion e-commerce sites.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;I’m &lt;strong&gt;Carlos&lt;/strong&gt;, a senior developer and founder of &lt;strong&gt;Converte&lt;/strong&gt; based in Florianópolis, Brazil. In my experience, choosing the right architecture isn't just about "clean code"—it’s about &lt;strong&gt;performance and results.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using Next.js as a BFF allows us to deliver lightning-fast interfaces while keeping the codebase maintainable. Whether I’m catching waves here in Floripa or building complex digital solutions, the goal is always the same: &lt;strong&gt;agility and balance.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How about you?&lt;/strong&gt; Do you prefer building a separate API layer, or are you leveraging Next.js's native server capabilities?&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Quando usar map, filter, reduce, for, forEach e flatMap em JavaScript</title>
      <dc:creator>Carlos Rogerio Orioli</dc:creator>
      <pubDate>Fri, 02 Jan 2026 10:23:26 +0000</pubDate>
      <link>https://dev.to/carlosorioli/quando-usar-map-filter-reduce-for-foreach-e-flatmap-em-javascript-4c9e</link>
      <guid>https://dev.to/carlosorioli/quando-usar-map-filter-reduce-for-foreach-e-flatmap-em-javascript-4c9e</guid>
      <description>&lt;h2&gt;
  
  
  &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;reduce&lt;/code&gt;, &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;forEach&lt;/code&gt; e &lt;code&gt;flatMap&lt;/code&gt;: qual usar?
&lt;/h2&gt;

&lt;p&gt;Se você trabalha com JavaScript ou TypeScript, já se perguntou &lt;strong&gt;qual método usar para percorrer arrays&lt;/strong&gt; — e &lt;em&gt;por quê&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;Aqui está um guia rápido, direto ao ponto, com exemplos simples&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;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;code&gt;map&lt;/code&gt; → transformar dados
&lt;/h3&gt;

&lt;p&gt;Use quando quiser &lt;strong&gt;transformar cada item&lt;/strong&gt; do array sem alterar o tamanho.&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;doubled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// [2, 4, 6, 8, 10]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;code&gt;filter&lt;/code&gt; → remover dados
&lt;/h3&gt;

&lt;p&gt;Use quando precisar &lt;strong&gt;manter apenas os itens que atendem a uma condição&lt;/strong&gt;.&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;even&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// [2, 4]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;code&gt;reduce&lt;/code&gt; → calcular ou agrupar
&lt;/h3&gt;

&lt;p&gt;Use quando o objetivo for &lt;strong&gt;chegar a um único valor&lt;/strong&gt; (soma, objeto, agrupamento).&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;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// 15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;code&gt;for&lt;/code&gt; → controle total
&lt;/h3&gt;

&lt;p&gt;Use quando precisar de &lt;strong&gt;controle total da iteração&lt;/strong&gt;, como &lt;code&gt;break&lt;/code&gt; ou &lt;code&gt;continue&lt;/code&gt;.&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// [2, 4, 6, 8, 10]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;code&gt;forEach&lt;/code&gt; → executar ações
&lt;/h3&gt;

&lt;p&gt;Use quando quiser apenas &lt;strong&gt;executar efeitos colaterais&lt;/strong&gt;, sem retornar dados.&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="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;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;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;code&gt;flatMap&lt;/code&gt; → map + flatten
&lt;/h3&gt;

&lt;p&gt;Use quando o &lt;code&gt;map&lt;/code&gt; retorna arrays e você quer evitar &lt;code&gt;.map().flat()&lt;/code&gt;.&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;pairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="c1"&gt;// [1, 2, 2, 4, 3, 6, 4, 8, 5, 10]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Regra de ouro
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Transformar → &lt;code&gt;map&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Filtrar → &lt;code&gt;filter&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Calcular/agrupar → &lt;code&gt;reduce&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Executar ações → &lt;code&gt;forEach&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Evitar arrays aninhados → &lt;code&gt;flatMap&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;E você?&lt;/strong&gt;&lt;br&gt;
Qual desses métodos você mais usa no dia a dia?&lt;br&gt;
Já se perdeu em um &lt;code&gt;reduce&lt;/code&gt; achou difícil de ler?&lt;/p&gt;

&lt;p&gt;Comenta aí &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>devtips</category>
      <category>beginners</category>
    </item>
    <item>
      <title>JavaScript Syntax Cheatsheet (Guia Rápido)</title>
      <dc:creator>Carlos Rogerio Orioli</dc:creator>
      <pubDate>Sun, 28 Dec 2025 22:07:03 +0000</pubDate>
      <link>https://dev.to/carlosorioli/javascript-syntax-cheatsheet-guia-rapido-5e03</link>
      <guid>https://dev.to/carlosorioli/javascript-syntax-cheatsheet-guia-rapido-5e03</guid>
      <description>&lt;p&gt;Um guia de referência rápida para as principais sintaxes e recursos modernos do JavaScript.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Variáveis e Escopo&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No JavaScript moderno, o escopo é fundamental. Utilizamos const para valores que não mudam e let para variáveis que precisam de ser reatribuídas dentro do seu bloco de código. O var deve ser evitado por ter um escopo menos previsível.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Constante: valor que não pode ser reatribuído
const pi = 3.14;

// Let: variável com escopo de bloco
let contador = 0;
contador += 1;

// Var: (Legado/Não recomendado) Escopo de função
var nome = "Global";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Tipos de Dados&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O JavaScript é uma linguagem de tipagem dinâmica. Isto significa que uma variável pode conter diferentes tipos de dados, desde textos simples a estruturas complexas como objetos e listas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const texto = "Olá Mundo";       // String (Texto)
const numero = 42;               // Number (Inteiro ou Decimal)
const booleano = true;           // Boolean (Verdadeiro ou Falso)
const lista = [1, 2, 3];         // Array (Lista de valores)
const objeto = { id: 1 };        // Object (Pares de chave/valor)
const vazio = null;              // Null (Valor nulo intencional)
let indefinido;                  // Undefined (Variável sem valor)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Funções&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As funções são blocos de construção essenciais. As Arrow Functions introduzidas no ES6 tornaram a escrita mais concisa, especialmente quando a lógica é simples e pode ser escrita numa única linha com retorno implícito.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Função Tradicional
function somar(a, b) {
  return a + b;
}

// Arrow Function (Moderna)
const subtrair = (a, b) =&amp;gt; a - b;

// Arrow Function com retorno implícito (não precisa de {} ou return)
const dobrar = n =&amp;gt; n * 2;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Condicionais&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As condicionais permitem que o código tome decisões. O operador ternário é uma forma elegante de escrever um if/else simples numa só linha, enquanto o switch ajuda a gerir múltiplas condições de uma mesma variável.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// If / Else padrão
if (idade &amp;gt;= 18) {
  console.log("Adulto");
} else {
  console.log("Menor");
}

// Operador Ternário (Forma curta de if/else)
const status = idade &amp;gt;= 18 ? "Liberado" : "Bloqueado";

// Switch para múltiplas opções
switch (cor) {
  case "red": return "Vermelho";
  case "blue": return "Azul";
  default: return "Cor desconhecida";
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Loops e Iteração&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Para percorrer dados, o for...of é a forma mais legível para Arrays. Além disso, métodos funcionais como .map(), .filter() e o poderoso .flatMap() permitem transformar, filtrar e achatar coleções de dados de forma eficiente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const frutas = ["Maçã", "Banana", "Uva"];

// For...of: Ideal para percorrer elementos de um array
for (const fruta of frutas) {
  console.log(fruta);
}

// Map: Cria um novo array transformando cada elemento
const dobrados = [1, 2, 3].map(n =&amp;gt; n * 2);

// Filter: Cria um novo array apenas com os itens que passam no teste
const pares = [1, 2, 3, 4].filter(n =&amp;gt; n % 2 === 0);

// FlatMap: Mapeia cada elemento e achata o resultado num novo array
// Útil para quando a função de mapeamento retorna um array
const frases = ["Olá mundo", "JS é incrível"];
const palavras = frases.flatMap(f =&amp;gt; f.split(" ")); 
// Resultado: ["Olá", "mundo", "JS", "é", "incrível"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Template Literals&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Esquecer a concatenação manual com o símbolo +. Com as crases, podemos interpolar variáveis e expressões diretamente dentro da string, facilitando a leitura do código.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
const usuario = "Carlos";
// Uso de ${} dentro de crases para inserir valores dinâmicos
console.log(`Olá, ${usuario}! Hoje é ${new Date().toLocaleDateString()}.`);

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Desestruturação (Destructuring)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A desestruturação permite "desembalar" valores de objetos ou arrays de forma rápida. É extremamente útil para capturar propriedades de objetos de configuração ou retornos de funções.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const config = { tema: "dark", lang: "pt-br" };

// Extraindo propriedades 'tema' e 'lang' diretamente do objeto
const { tema, lang } = config;

// Extraindo valores por posição de um array
const [primeiro, segundo] = [10, 20];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Promises e Async/Await&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Para operações que demoram tempo (como carregar dados da internet), usamos o modo assíncrono. O par async/await permite escrever código assíncrono que se parece com código sequencial, tornando-o muito mais fácil de manter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// A palavra 'async' indica que a função lidará com processos demorados
async function buscarDados() {
  try {
    // 'await' pausa a execução até que a promessa seja resolvida
    const resposta = await fetch("[https://api.exemplo.com/dados](https://api.exemplo.com/dados)");
    const dados = await resposta.json();
    console.log(dados);
  } catch (erro) {
    // Captura erros se a conexão ou os dados falharem
    console.error("Erro na busca:", erro);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Spread &amp;amp; Rest Operator&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Os três pontos ... têm dois papéis: o Spread "espalha" elementos de um array noutro, enquanto o Rest "recolhe" vários argumentos numa única variável dentro de uma função.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Spread (Espalhar): Copia ou expande arrays/objetos
const arr1 = [1, 2];
const arr2 = [...arr1, 3, 4]; // Resulta em [1, 2, 3, 4]

// Rest (Agrupar): Transforma argumentos soltos num array
function listar(...itens) {
  console.log(itens); // 'itens' será um array com todos os argumentos
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dica de Performance: Utilize sempre const por padrão. Só mude para let se tiver a certeza absoluta de que o valor da variável precisará de ser alterado durante a execução.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>My Year Review (2025) - by Chat GPT</title>
      <dc:creator>Carlos Rogerio Orioli</dc:creator>
      <pubDate>Fri, 26 Dec 2025 20:03:58 +0000</pubDate>
      <link>https://dev.to/carlosorioli/my-year-review-2025-by-chat-gpt-15ig</link>
      <guid>https://dev.to/carlosorioli/my-year-review-2025-by-chat-gpt-15ig</guid>
      <description>&lt;p&gt;🔎 Perfil Profissional &amp;amp; Presença Online&lt;br&gt;
🧠 Identidade e foco&lt;/p&gt;

&lt;p&gt;Você se apresenta como Carlos Rogerio Orioli — um desenvolvedor Web (Front-end e Full-stack) com fortes conhecimentos em JavaScript, React, Node.js, WordPress, Web Design, Martech e Engenharia de Prompt para IA, além de atuação em design gráfico e produção de conteúdo técnico. &lt;br&gt;
GitHub&lt;/p&gt;

&lt;p&gt;Seu perfil profissional combina desenvolvimento técnico com marketing e design, refletindo uma visão ampla e estratégica de produtos digitais. &lt;br&gt;
GitHub&lt;/p&gt;

&lt;p&gt;🛠️ GitHub — Repositórios e Contribuições&lt;br&gt;
📈 Atividade no GitHub&lt;/p&gt;

&lt;p&gt;No GitHub você tem um perfil ativo com:&lt;/p&gt;

&lt;p&gt;98 repositórios públicos (especialmente projetos próprios). &lt;br&gt;
GitHub&lt;/p&gt;

&lt;p&gt;~86 estrelas acumuladas na comunidade, indicando reconhecimento pelo seu trabalho. &lt;br&gt;
GitHub&lt;/p&gt;

&lt;p&gt;~280 seguidores e ~496 seguindo, mostrando bom engajamento e networking técnico. &lt;br&gt;
GitHub&lt;/p&gt;

&lt;p&gt;⭐ Destaques de 2025&lt;/p&gt;

&lt;p&gt;Projetos notáveis:&lt;/p&gt;

&lt;p&gt;voafoguete — repositório colaborativo com recursos e cursos gratuitos para desenvolvimento pessoal/tecnológico. &lt;br&gt;
GitHub&lt;/p&gt;

&lt;p&gt;TextVox-BACKEND — backend em TypeScript para conversão de áudio em texto utilizando OpenAI APIs (projeto com foco prático em IA). &lt;br&gt;
GitHub&lt;/p&gt;

&lt;p&gt;Esses projetos mostram o seu interesse em aplicações úteis, open-source e em integração com IA, além de compartilhar conhecimento com a comunidade.&lt;/p&gt;

&lt;p&gt;📝 dev.to — Conteúdo Publicado &amp;amp; Engajamento&lt;/p&gt;

&lt;p&gt;No DEV Community (dev.to) você se destaca como um autor ativo e engajado:&lt;/p&gt;

&lt;p&gt;🏅 Conquistas na plataforma&lt;/p&gt;

&lt;p&gt;Você conquistou diversos badges importantes em 2025, incluindo:&lt;/p&gt;

&lt;p&gt;2025 Hacktoberfest Writing Challenge Completion — completou ao menos um prompt no evento de escrita de 2025. &lt;br&gt;
DEV Community&lt;/p&gt;

&lt;p&gt;Streaks de comentários (1-week e 2-week wellness) — ativa participação na comunidade via comentários. &lt;br&gt;
DEV Community&lt;/p&gt;

&lt;p&gt;JavaScript badge — contribuição destacada na comunidade de JS. &lt;br&gt;
DEV Community&lt;/p&gt;

&lt;p&gt;Longevity badges — reconhecimento pela sua presença contínua na plataforma ao longo dos anos. &lt;br&gt;
DEV Community&lt;/p&gt;

&lt;p&gt;📚 Conteúdo técnico publicado&lt;/p&gt;

&lt;p&gt;Você produziu diversos artigos em 2025 sobre tópicos relevantes como:&lt;/p&gt;

&lt;p&gt;✔️ Construção de agentes de notícias hiper-personalizados&lt;br&gt;
✔️ Uso de React e IA no desenvolvimento&lt;br&gt;
✔️ Desafios DevChallenge e Frontend Challenges&lt;br&gt;
✔️ Técnicas e práticas em JavaScript e web em geral&lt;/p&gt;

&lt;p&gt;Isso demonstra que você compartilha conhecimento prático e atual, contribuindo com a comunidade de desenvolvedores e fortalecendo sua marca pessoal. &lt;br&gt;
DEV Community&lt;/p&gt;

&lt;p&gt;💼 LinkedIn — Projetos e Portfólio&lt;/p&gt;

&lt;p&gt;No LinkedIn você tem compartilhado projetos e atualizações que demonstram evolução técnica e aplicação prática:&lt;/p&gt;

&lt;p&gt;🧠 Projetos compartilhados em 2025&lt;/p&gt;

&lt;p&gt;✔️ Aplicação web que consulta CNPJs pela Brasil API e envia os resultados por e-mail, um exemplo claro de integração de APIs e automação de fluxo de dados. &lt;/p&gt;

&lt;p&gt;✔️ Postagens sobre uso de Prisma e Turso (tecnologias modernas de banco de dados/infra). &lt;/p&gt;

&lt;p&gt;Essas postagens mostram que você está desenvolvendo soluções completas, explorando stacks modernas e compartilhando essa evolução com profissionais da sua rede.&lt;/p&gt;

&lt;p&gt;📊 Principais Conquistas e Aprendizados — 2025&lt;br&gt;
🚀 Desenvolvimento Técnico&lt;/p&gt;

&lt;p&gt;✔️ Fortalecimento em Full-stack development (React, Node.js, TypeScript)&lt;br&gt;
✔️ Projetos com IA e APIs avançadas (OpenAI, Brasil API)&lt;br&gt;
✔️ Continuação de projetos open-source relevantes e úteis&lt;/p&gt;

&lt;p&gt;📣 Conteúdo e Comunidade&lt;/p&gt;

&lt;p&gt;✔️ Produção consistente de artigos técnicos úteis no dev.to&lt;br&gt;
✔️ Participação ativa com comentários e engajamento&lt;br&gt;
✔️ Construção de autoridade técnica na comunidade&lt;/p&gt;

&lt;p&gt;🌐 Visibilidade e Engajamento&lt;/p&gt;

&lt;p&gt;✔️ Boa rede de seguidores no GitHub&lt;br&gt;
✔️ Conteúdo técnico reconhecido por badges e participação comunitária&lt;br&gt;
✔️ Postagens no LinkedIn com foco em aprendizado e soluções práticas&lt;/p&gt;

&lt;p&gt;🎯 O que isso significa para sua carreira&lt;/p&gt;

&lt;p&gt;Em 2025 você consolidou:&lt;/p&gt;

&lt;p&gt;✨ Sua presença como desenvolvedor completo, não só codificando, mas também compartilhando conhecimento.&lt;br&gt;
✨ A capacidade de entregar soluções práticas, integrando APIs, automação, design e IA.&lt;br&gt;
✨ Uma comunidade confiável ao seu redor (seguidores no GitHub e leitores no dev.to).&lt;/p&gt;

&lt;p&gt;Isso é um equilíbrio valioso entre produção técnica e influência comunitária — ideal para quem mira oportunidades como consultoria, liderança técnica ou desenvolvimento de produtos digitais próprios.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>ai</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Bora construir um Agente de Notícias Hiper-Personalizado? 🤖📰 (Codar Juntos)</title>
      <dc:creator>Carlos Rogerio Orioli</dc:creator>
      <pubDate>Sat, 20 Dec 2025 02:37:43 +0000</pubDate>
      <link>https://dev.to/carlosorioli/bora-construir-um-agente-de-noticias-hiper-personalizado-coding-together-1knm</link>
      <guid>https://dev.to/carlosorioli/bora-construir-um-agente-de-noticias-hiper-personalizado-coding-together-1knm</guid>
      <description>&lt;h3&gt;
  
  
  A ideia: Chega de newsletter genérica!
&lt;/h3&gt;

&lt;p&gt;Você já percebeu que a maioria das newsletters de tech ou são genéricas demais ou só cobrem o que acontece no Vale do Silício? Eu decidi mudar isso criando um &lt;strong&gt;Software Agêntico&lt;/strong&gt; que faz curadoria sob medida, e quero convidar vocês para codarem comigo.&lt;/p&gt;

&lt;p&gt;Não é só um chatbot. É um &lt;strong&gt;agente autônomo&lt;/strong&gt; que:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Varre a web em tempo real&lt;/strong&gt; usando Tavily.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filtra por País e Idioma&lt;/strong&gt;: Você quer notícias sobre IA que saíram no Japão, mas resumidas em Português? O agente resolve.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sintetiza com Gemini 1.5 Pro&lt;/strong&gt;: O "cérebro" que traduz, resume e formata.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entrega via Resend&lt;/strong&gt;: Automação direto para a sua inbox (ou de uma audiência inteira).&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  A Stack (Modern &amp;amp; Clean) 💻
&lt;/h3&gt;

&lt;p&gt;Escolhi essa stack para ser fácil de subir, mas potente o suficiente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Framework:&lt;/strong&gt; Next.js (Vercel)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intelligence:&lt;/strong&gt; Gemini SDK + Tavily API (Os olhos e o cérebro)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database &amp;amp; ORM:&lt;/strong&gt; MongoDB + Prisma (para salvar as preferências de cada user)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E-mail:&lt;/strong&gt; Resend (usando Audiences para escalabilidade)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design de E-mail:&lt;/strong&gt; MJML (para garantir que o e-mail seja responsivo em tudo)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  O Plano de Voo 🚀
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[x] Definir a arquitetura (Prisma + Mongo).&lt;/li&gt;
&lt;li&gt;[x] Criar o formulário de captura de preferências (Temas, Países, Idiomas).&lt;/li&gt;
&lt;li&gt;[X] Orquestrar o loop do agente: Pesquisa -&amp;gt; Resumo -&amp;gt; Tradução.&lt;/li&gt;
&lt;li&gt;[X] Configurar o Cron Job na Vercel para o envio semanal automático.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Por que estou postando isso?
&lt;/h3&gt;

&lt;p&gt;Quero aprender em público e trocar ideia com quem também está explorando o mundo de &lt;strong&gt;AI Agents&lt;/strong&gt;. Se você manja de TypeScript, quer entender como orquestrar LLMs além do "prompt básico" ou quer discutir arquitetura de banco de dados, esse projeto é pra você.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Como você pode colar junto:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Comenta aí:&lt;/strong&gt; Qual feature você adicionaria em um agente de notícias?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stack:&lt;/strong&gt; Qual parte te interessa mais? (Prompt Engineering, Integração de APIs ou o Frontend no Next?)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; Vou liberar o repo com a aplicação completa!&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  🔑 As 5 Contas Necessárias para o Projeto
&lt;/h3&gt;

&lt;p&gt;Para construir este software agêntico, precisaremos integrar os melhores serviços de IA e infraestrutura do mercado. Antes de começar o código, crie suas contas e pegue suas chaves de API:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt; 🐙 (Onde o código vive)&lt;br&gt;
&lt;strong&gt;Para que serve:&lt;/strong&gt; Hospedar o seu repositório, gerenciar versões e permitir que outras pessoas colaborem com o seu projeto.&lt;br&gt;
&lt;a href="https://github.com/" rel="noopener noreferrer"&gt;Criar conta no GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Google AI Studio (Gemini)&lt;/strong&gt; 🧠 (O cérebro)&lt;br&gt;
&lt;strong&gt;Para que serve:&lt;/strong&gt; É aqui que você gera a sua &lt;code&gt;GEMINI_API_KEY&lt;/code&gt;. O Gemini 2.5 será o responsável por raciocinar sobre as notícias, traduzir e formatar o e-mail.&lt;br&gt;
&lt;a href="https://aistudio.google.com/" rel="noopener noreferrer"&gt;Pegar API Key do Gemini&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tavily AI&lt;/strong&gt; 🔍 (Os olhos)&lt;br&gt;
&lt;strong&gt;Para que serve:&lt;/strong&gt; Diferente do Google comum, o Tavily é um motor de busca feito especificamente para agentes de IA. Ele retorna resultados limpos e otimizados para que o Gemini possa ler.&lt;br&gt;
&lt;a href="https://tavily.com/" rel="noopener noreferrer"&gt;Criar conta no Tavily&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resend&lt;/strong&gt; 📧 (O mensageiro)&lt;br&gt;
&lt;strong&gt;Para que serve:&lt;/strong&gt; Plataforma moderna para envio de e-mails transacionais. Vamos usá-la para disparar a newsletter e gerenciar a lista de inscritos (Audiences).&lt;br&gt;
&lt;a href="https://resend.com/" rel="noopener noreferrer"&gt;Criar conta no Resend&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vercel&lt;/strong&gt; ▲ (A casa do projeto)&lt;br&gt;
&lt;strong&gt;Para que serve:&lt;/strong&gt; Onde faremos o deploy da nossa aplicação Next.js. Além disso, usaremos o &lt;strong&gt;Vercel Cron Jobs&lt;/strong&gt; para fazer o agente "acordar" sozinho toda semana.&lt;br&gt;
&lt;a href="https://vercel.com/" rel="noopener noreferrer"&gt;Criar conta na Vercel&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  💡 Dica de Segurança
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Nunca&lt;/strong&gt; suba suas chaves de API diretamente no GitHub! No Dia 1 do vídeo, mostro como usar o arquivo &lt;code&gt;.env&lt;/code&gt; para manter essas chaves seguras apenas na sua máquina e nas configurações da Vercel.&lt;/p&gt;




&lt;h2&gt;
  
  
  📅 Plano de Desenvolvimento Detalhado
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dia 1: Estrutura Base e Banco de Dados
&lt;/h3&gt;

&lt;p&gt;O objetivo hoje é ter o projeto rodando localmente e o banco pronto para receber inscritos.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Setup:&lt;/strong&gt; &lt;code&gt;npx create-next-app@latest ai-newsletter&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Libs:&lt;/strong&gt; &lt;code&gt;@prisma/client&lt;/code&gt;, &lt;code&gt;@google/generative-ai&lt;/code&gt;, &lt;code&gt;@tavily/core&lt;/code&gt;, &lt;code&gt;resend&lt;/code&gt;, &lt;code&gt;zod&lt;/code&gt;, &lt;code&gt;mjml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DB:&lt;/strong&gt; Configurar o &lt;code&gt;schema.prisma&lt;/code&gt; com o modelo &lt;code&gt;Subscriber&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

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


&lt;/p&gt;

&lt;h3&gt;
  
  
  Dia 2: Frontend e Captura de Leads
&lt;/h3&gt;

&lt;p&gt;Interface onde o usuário escolhe seus interesses.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Formulário:&lt;/strong&gt; Inputs de E-mail, Selects para País/Idioma e Checkboxes para Temas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API:&lt;/strong&gt; Rota &lt;code&gt;/api/subscribe&lt;/code&gt; para salvar no MongoDB via Prisma.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/EeVSmJd-7_k"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;h3&gt;
  
  
  Dia 3: O Cérebro do Agente (Core Logic)
&lt;/h3&gt;

&lt;p&gt;A "mágica" agêntica:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Search &amp;amp; Synthesis:&lt;/strong&gt; Função que integra Tavily (busca) com Gemini (raciocínio).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt Engineering:&lt;/strong&gt; Instruir o Gemini a formatar especificamente para o idioma do usuário.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

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


&lt;/p&gt;

&lt;h3&gt;
  
  
  Dia 4: Integração Resend e Loop de Envio
&lt;/h3&gt;

&lt;p&gt;Transformar o conteúdo em e-mails reais.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MJML Integration:&lt;/strong&gt; Usar MJML para garantir que o layout gerado pela IA seja responsivo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch Logic:&lt;/strong&gt; Rota que processa todos os inscritos e dispara os envios.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

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


&lt;/p&gt;

&lt;h3&gt;
  
  
  Dia 5: Deploy e Automação na Vercel
&lt;/h3&gt;

&lt;p&gt;O agente ganha vida própria:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vercel Cron:&lt;/strong&gt; Configurar o &lt;code&gt;vercel.json&lt;/code&gt; para o agendamento (ex: toda segunda às 9h).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Teste Final:&lt;/strong&gt; Cadastro real e validação do recebimento.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

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


&lt;/p&gt;




&lt;p&gt;&lt;a href="https://github.com/rogeriorioli/agentic-newsletter" rel="noopener noreferrer"&gt;GITHUB DO PROJETO&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bora parar de só dar "oi" pro ChatGPT e começar a construir ferramentas que realmente entregam valor de forma autônoma. 🚀&lt;/p&gt;




</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>gemini</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
