<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Juan Jose Miranda</title>
    <description>The latest articles on Forem by Juan Jose Miranda (@juan_jose_miranda).</description>
    <link>https://forem.com/juan_jose_miranda</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2293041%2F5ddf8232-4320-4e22-824f-a7bf15779c9f.jpg</url>
      <title>Forem: Juan Jose Miranda</title>
      <link>https://forem.com/juan_jose_miranda</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/juan_jose_miranda"/>
    <language>en</language>
    <item>
      <title>Pequeñas ideas, grandes comunidades: así nació Kinua</title>
      <dc:creator>Juan Jose Miranda</dc:creator>
      <pubDate>Fri, 26 Sep 2025 11:18:13 +0000</pubDate>
      <link>https://forem.com/juan_jose_miranda/pequenas-ideas-grandes-comunidades-asi-nacio-kinua-5f78</link>
      <guid>https://forem.com/juan_jose_miranda/pequenas-ideas-grandes-comunidades-asi-nacio-kinua-5f78</guid>
      <description>&lt;p&gt;No sabía el poder de la comunidad hasta que llegué al AWS User Group. Con el tiempo entendí que estos espacios no solo son para aprender, sino también el origen de nuevas ideas. Así nació Kinua, a partir del feedback del AWS Community Day Bolivia 2024 y de la convicción de que siempre se puede mejorar. En ese proceso descubrimos algo muy claro: como ingenieros podemos crear cosas increíbles, pero cuando se trata de organizar eventos, manejar la logística o incluso coordinar el swag, siempre hay retos. Tres amigos, una noche con cervezas y un propósito claro: ayudar a la comunidad con lo que mejor sabemos hacer, programar. De esa chispa nació una app pensada para que los asistentes vivan una experiencia más conectada, dinámica y memorable en cada AWS Community Day.&lt;/p&gt;

&lt;h2&gt;
  
  
  El reto: del pasaporte físico a la experiencia digital
&lt;/h2&gt;

&lt;p&gt;El AWS Community Day Bolivia 2024 marcó un hito: fue la primera edición en nuestro país. Nos costó bastante sacarlo adelante, pero el resultado superó las expectativas: más de 27 charlas, más de 400 asistentes y lazos valiosos con sponsors que sentaron las bases para futuras ediciones. También logramos conseguir bastante swag para la comunidad. Como organizador, fue increíblemente gratificante ver tantas personas reunidas alrededor de la nube.&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%2Fbfcgi0al9q9lxa72eluz.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%2Fbfcgi0al9q9lxa72eluz.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sin embargo, como desarrollador, no pude dejar de notar ciertas limitaciones en la experiencia. En particular, el uso del “pasaporte físico”: una cartilla de papel que los asistentes llevaban consigo para sumar puntos visitando stands de sponsors o completar misiones y luego reclamar premios. Funcionaba, sí, pero era lento, manual, generaba filas y dependía de manejar papel en un evento que debería inspirar innovación. Algo no encajaba.&lt;/p&gt;

&lt;p&gt;Para la edición 2025, llevé la idea a la organización: digitalizar el pasaporte y convertirlo en una experiencia gamificada moderna. La propuesta fue recibida con entusiasmo, y con el apoyo de todos, me uní a Abel y Jhonathan para ponernos manos a la obra y hacer lo que mejor sabemos hacer: codear.&lt;/p&gt;

&lt;p&gt;Revisamos los problemas, analizamos alternativas, hicimos sesiones de fobbing y llegamos a una conclusión clara: no queríamos seguir generando procesos manuales y papeleo. Queríamos una app que reemplazara el pasaporte físico, potenciara la experiencia gamificada y mostrara lo que de verdad podemos lograr cuando mezclamos comunidad y tecnología.&lt;/p&gt;

&lt;p&gt;Así comenzó el camino de Kinua.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retos convertidos en oportunidades
&lt;/h2&gt;

&lt;p&gt;La experiencia del primer AWS Community Day Bolivia nos dejó tres retos principales claramente identificados:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;La agenda. Con más de 27 charlas en paralelo, tener una agenda estática en papel se volvió poco práctico. Queríamos que cada asistente pudiera ver todas las sesiones en un solo lugar, marcar sus favoritas, recibir notificaciones de cambios y, lo más importante, dejar su puntuación y feedback para los speakers. Una agenda viva y digital que acompañe al usuario durante todo el evento.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Las fotos del evento. En cada Community Day se generan cientos de fotos: las de la organización, las de los sponsors y las de la comunidad misma. El problema es que muchas veces los asistentes no saben en cuáles aparecen. Aquí vimos una oportunidad única: usar Amazon Rekognition para identificar a los participantes y mostrarles directamente en qué fotos salieron, creando así una experiencia personalizada y memorable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;El sistema de puntos. El famoso pasaporte físico funcionaba, pero tenía un límite. Queríamos llevarlo a otro nivel: no solo retos con sponsors, sino también con speakers en cada charla y con comunidades aliadas. Imaginamos una dinámica donde participar, aprender y conectar se tradujera en puntos y recompensas, gamificando toda la experiencia del evento y no solo las visitas a stands.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Estos tres puntos fueron nuestra brújula para diseñar lo que se convertiría en Kinua, una plataforma pensada no solo para resolver problemas logísticos, sino para crear una experiencia más rica, divertida y alineada con el espíritu de innovación que representa AWS.&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%2Fh21n68qu5w7vha5xtm7g.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%2Fh21n68qu5w7vha5xtm7g.png" alt=" " width="800" height="999"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Arquitectura Serverless y Decisiones Técnicas
&lt;/h2&gt;

&lt;p&gt;Desde el inicio sabíamos que dos factores serían decisivos en este proyecto: el costo y el tiempo. Por un lado, queríamos minimizar los gastos operativos evitando la gestión de servidores y escalado manual; por otro, necesitábamos entregar una solución completa en pocas semanas.&lt;br&gt;
La respuesta natural fue apostar por una arquitectura 100% serverless en el backend, acompañada de un frontend PWA en Angular, que nos permitió ofrecer una experiencia similar a una app nativa sin pasar por el proceso de publicación en tiendas ni requerir instalación.&lt;/p&gt;

&lt;p&gt;Además, gracias a que una PWA (Progressive Web App) puede ejecutarse desde el navegador, incluso en condiciones de conectividad limitada, logramos un balance ideal entre velocidad de desarrollo, experiencia de usuario y facilidad de despliegue.&lt;/p&gt;

&lt;p&gt;A continuación, comparto el diagrama general de servicios y cómo cada componente se integra dentro de nuestra solución.&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%2Fxmi5gycc5aveggwe8lqk.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%2Fxmi5gycc5aveggwe8lqk.png" alt="Diagrama" width="800" height="786"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esta arquitectura no solo redujo el costo operativo en más de un 70% frente a un enfoque tradicional, sino que también nos permitió escalar automáticamente durante el evento sin ninguna intervención manual.&lt;/p&gt;

&lt;h2&gt;
  
  
  Impacto en la comunidad
&lt;/h2&gt;

&lt;p&gt;El lanzamiento de Kinua durante el AWS Community Day Bolivia 2025 fue más que un experimento técnico: fue una experiencia real de transformación. En apenas unas semanas, pasamos de tener la idea en papel a verla funcionando en manos de cientos de asistentes.&lt;/p&gt;

&lt;p&gt;Los resultados hablaron por sí solos:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speakers&lt;/strong&gt;: destacaron lo simple que fue interactuar con los asistentes y cómo las dinámicas de puntos aumentaron la participación en cada charla.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sponsors&lt;/strong&gt;: encontraron nuevas formas de conectar con el público, midiendo de forma clara el impacto de sus activaciones y obteniendo métricas tangibles de engagement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;La comunidad&lt;/strong&gt;: vivió el evento de una manera más interactiva, con notificaciones en tiempo real, acceso rápido a la agenda y un sistema de puntos que convirtió cada charla en una dinámica gamificada.&lt;/p&gt;

&lt;p&gt;Más allá de la tecnología, el verdadero impacto estuvo en cómo Kinua mejoró la experiencia del evento: los asistentes estuvieron más informados, más motivados y más conectados.&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%2F1pn68zoww1jcykaevlj1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1pn68zoww1jcykaevlj1.jpg" alt=" " width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Kinua es Open Source
&lt;/h2&gt;

&lt;p&gt;Kinua nació como un proyecto para el AWS Community Day Bolivia 2025, pero nuestra meta va más allá: queremos seguir mejorándolo y ponerlo a disposición de cualquier comunidad o evento que lo necesite.&lt;/p&gt;

&lt;p&gt;El código está disponible como open source, listo para que lo uses, lo refines y lo hagas crecer. Porque las comunidades no solo se construyen con eventos, también con colaboración y tecnología compartida. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/JuanJoseMirandaM/kinua" rel="noopener noreferrer"&gt;https://github.com/JuanJoseMirandaM/kinua&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%2Fp7cg1a3pxr6li76qi9qa.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7cg1a3pxr6li76qi9qa.jpg" alt="Equipo Kinua" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hagamos que cada evento sea una experiencia única, cada conexión tenga un impacto real y que las comunidades puedan crecer. Kinua es solo el comienzo: un proyecto pensado para mejorar, crecer y estar disponible para cualquier comunidad que quiera usarlo. En AWS siempre nos dicen “Build on AWS”, y esto nos recuerda que todos somos builders; ahora la invitación está abierta para usarla, refinarla y llevarla aún más lejos.&lt;/p&gt;

</description>
      <category>awscommunityday</category>
      <category>aws</category>
      <category>bolivia</category>
      <category>kinua</category>
    </item>
    <item>
      <title>Event-Driven Architecture con Lambda y S3</title>
      <dc:creator>Juan Jose Miranda</dc:creator>
      <pubDate>Mon, 04 Aug 2025 04:14:13 +0000</pubDate>
      <link>https://forem.com/juan_jose_miranda/event-driven-architecture-con-lambda-y-s3-4bcb</link>
      <guid>https://forem.com/juan_jose_miranda/event-driven-architecture-con-lambda-y-s3-4bcb</guid>
      <description>&lt;p&gt;&lt;strong&gt;Event‑Driven Architecture (EDA)&lt;/strong&gt; es un patrón de diseño en el cual los componentes del sistema se comunican a través de &lt;strong&gt;eventos&lt;/strong&gt;. Este enfoque permite construir sistemas desacoplados, escalables y reactivos, donde cada parte del sistema responde a eventos en lugar de seguir un flujo de control predefinido.&lt;/p&gt;

&lt;p&gt;Amazon S3 puede generar eventos cuando se sube un objeto &lt;code&gt;s3:ObjectCreated:*&lt;/code&gt; y estos eventos pueden invocar funciones &lt;strong&gt;AWS Lambda&lt;/strong&gt; automáticamente. Con este patrón puedes automatizar tareas como redimensionado, análisis, notificaciones, o incluso sobreponer una marca de agua a imágenes subidas.&lt;/p&gt;

&lt;p&gt;En este artículo construiremos un pipeline para:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Procesar imágenes subidas a S3.&lt;/li&gt;
&lt;li&gt;Aplicar una marca de agua.&lt;/li&gt;
&lt;li&gt;Almacenarlas en otro bucket o prefijo.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conceptos Fundamentales
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Event Source y Event Target
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Event Source&lt;/strong&gt;: Amazon S3 que emite notificaciones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event Target&lt;/strong&gt;: AWS Lambda que consume el evento.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Comunicación Asíncrona
&lt;/h3&gt;

&lt;p&gt;Cada imagen es procesada como un evento independiente, lo que permite procesamiento paralelo, alta tolerancia y escalabilidad.&lt;/p&gt;

&lt;h3&gt;
  
  
  S3 Events &amp;amp; Lambda Triggers
&lt;/h3&gt;

&lt;p&gt;S3 permite configurar notificaciones como:&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="nl"&gt;"Events"&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="s2"&gt;"s3:ObjectCreated:*"&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;p&gt;Estas notificaciones invocan funciones Lambda cuando se produce un evento compatible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementación Práctica: Aplicar Marca de Agua
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Flujo
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Usuario sube una imagen a bucket S3.&lt;/li&gt;
&lt;li&gt;Lambda aplica marca de agua con el logo.&lt;/li&gt;
&lt;li&gt;Imagen procesada se guarda en un prefijo o bucket definido.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Arquitectura
&lt;/h3&gt;

&lt;p&gt;El flujo arquitectónico básico se ve así:&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%2F7zss59fj18j5u5miifty.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%2F7zss59fj18j5u5miifty.png" alt="Flow" width="800" height="497"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuración S3
&lt;/h3&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;"NotificationConfiguration"&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;"LambdaFunctionConfigurations"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"LambdaFunctionArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:region:account:function:processImage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Events"&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="s2"&gt;"s3:ObjectCreated:*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Filter"&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;"Key"&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;"FilterRules"&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="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;"suffix"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".jpg"&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="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="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="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;
  
  
  Lambda Function
&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;S3Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;GetObjectCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PutObjectCommand&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;@aws-sdk/client-s3&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;sharp&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;sharp&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;s3&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;S3Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;us-east-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;streamToBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stream&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;chunks&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="k"&gt;await &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;chunk&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;chunks&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chunk&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;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunks&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;handler&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;event&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;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Records&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="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&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;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Records&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="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Obtener logo&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;watermarkObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&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;GetObjectCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;assets-bucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;community-day-logo.png&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;watermarkBuffer&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;streamToBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;watermarkObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Redimensionar logo&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resizedWatermark&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;sharp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;watermarkBuffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;png&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBuffer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Obtener imagen original&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imageObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&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;GetObjectCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalBuffer&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;streamToBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Obtener metadatos de la imagen original para calcular padding&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&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;sharp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalBuffer&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;metadata&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;paddingX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 20px desde el borde derecho&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;paddingY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 20px desde el borde inferior&lt;/span&gt;

  &lt;span class="c1"&gt;// Obtener dimensiones del logo redimensionado&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logoMetadata&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;sharp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resizedWatermark&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;metadata&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;top&lt;/span&gt; &lt;span class="o"&gt;=&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;height&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="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logoMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;paddingY&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;left&lt;/span&gt; &lt;span class="o"&gt;=&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;width&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="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logoMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;paddingX&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Componer con marca de agua redimensionada y padding&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;watermarked&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;sharp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalBuffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;composite&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resizedWatermark&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;left&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="nf"&gt;jpeg&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBuffer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Subir imagen final con marca de agua&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&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;PutObjectCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`processed/mark-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;watermarked&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ContentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image/jpeg&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuración Trigger
&lt;/h3&gt;

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

&lt;ol&gt;
&lt;li&gt;Seleccione "Add trigger". &lt;/li&gt;
&lt;li&gt;En "Bucket", seleccione su bucket de origen.&lt;/li&gt;
&lt;li&gt;En "Event types", seleccione "All object create events".&lt;/li&gt;
&lt;li&gt;En "Recursive invocation", marque la casilla para confirmar que no se recomienda usar el mismo depósito de Amazon S3 para entrada y salida.&lt;/li&gt;
&lt;li&gt;Seleccione "Add".&lt;/li&gt;
&lt;/ol&gt;

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

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

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

&lt;h2&gt;
  
  
  Consideraciones
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Idempotencia&lt;/strong&gt;: identifica la imagen procesada para no hacerlo dos veces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observabilidad&lt;/strong&gt;: CloudWatch Logs y métricas para seguimiento.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimización de costos&lt;/strong&gt;: memoria adecuada, timeouts y tamaño del paquete bien definidos.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>lambda</category>
      <category>serverless</category>
      <category>eventdriven</category>
    </item>
    <item>
      <title>🚨 Adiós a los 12 meses gratis en AWS: esto es lo que debes saber desde hoy</title>
      <dc:creator>Juan Jose Miranda</dc:creator>
      <pubDate>Wed, 16 Jul 2025 21:05:33 +0000</pubDate>
      <link>https://forem.com/juan_jose_miranda/adios-a-los-12-meses-gratis-en-aws-esto-es-lo-que-debes-saber-desde-hoy-3a2i</link>
      <guid>https://forem.com/juan_jose_miranda/adios-a-los-12-meses-gratis-en-aws-esto-es-lo-que-debes-saber-desde-hoy-3a2i</guid>
      <description>&lt;p&gt;Desde el &lt;strong&gt;15 de julio de 2025&lt;/strong&gt;, Amazon Web Services (AWS) le dice oficialmente &lt;strong&gt;adiós al mítico Free Tier de 12 meses&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Si alguna vez te registraste en AWS y disfrutaste de un año completo de EC2, S3 o RDS gratis, esta noticia te va a interesar (y quizás doler un poco).&lt;/p&gt;

&lt;p&gt;Pero ¡tranquilo! AWS no ha eliminado su capa gratuita por completo. Lo que ha hecho es &lt;strong&gt;reinventarla&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
En este artículo te explico &lt;strong&gt;qué ha cambiado&lt;/strong&gt;, &lt;strong&gt;cómo aprovechar los nuevos beneficios&lt;/strong&gt;, y &lt;strong&gt;qué debes tener en cuenta si planeas crear una cuenta hoy o en el futuro&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏁 ¿Qué cambió desde el 15 de julio?
&lt;/h2&gt;

&lt;p&gt;Hasta el 14 de julio, cualquier persona que se creaba una cuenta en AWS obtenía:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ 12 meses gratuitos de servicios como EC2 (750 horas/mes), S3 (5 GB), RDS, Lambda, CloudWatch, etc.&lt;/li&gt;
&lt;li&gt;⏱️ Una capa gratuita con límites por servicio y duración fija.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Desde el &lt;strong&gt;15 de julio de 2025&lt;/strong&gt;, este modelo desaparece &lt;strong&gt;para nuevas cuentas&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Ahora el sistema se basa en &lt;strong&gt;créditos y actividades&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 Comparativa: Free Tier antiguo vs nuevo
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Característica&lt;/th&gt;
&lt;th&gt;Antes (hasta 14 de julio 2025)&lt;/th&gt;
&lt;th&gt;Ahora (desde 15 de julio 2025)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Duración&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;12 meses&lt;/td&gt;
&lt;td&gt;6 meses o hasta agotar los créditos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Modelo&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Límite por servicio y tiempo&lt;/td&gt;
&lt;td&gt;Créditos flexibles + retos para ganar más&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Créditos iniciales&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;$100 USD al crear la cuenta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Créditos adicionales&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Hasta $100 USD extras completando tareas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Servicios Always Free&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sí&lt;/td&gt;
&lt;td&gt;Sí (más de 30 servicios disponibles)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Posibilidad de cierre de cuenta&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Sí, si no migras al plan de pago tras usar créditos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Acceso a servicios&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Amplio, sin limitaciones&lt;/td&gt;
&lt;td&gt;Algunas restricciones (ej. sin Marketplace)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;Con esta nueva estructura de créditos, &lt;strong&gt;AWS ya no solo nos regala tiempo: nos reta a decidir con intención.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Administrar cada dólar nos acerca a la realidad de construir sistemas sostenibles, donde cada recurso cuenta y cada decisión tiene impacto.&lt;br&gt;&lt;br&gt;
🧠 &lt;strong&gt;Una práctica perfecta para quienes quieren ir más allá del "jugar en la nube".&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  💳 ¿Cómo se consiguen los $100 USD adicionales?
&lt;/h2&gt;

&lt;p&gt;AWS ahora incentiva a los nuevos usuarios a explorar la plataforma mediante &lt;strong&gt;actividades simples&lt;/strong&gt; que desbloquean créditos extra.&lt;br&gt;&lt;br&gt;
Algunas de estas tareas incluyen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lanzar una instancia EC2.&lt;/li&gt;
&lt;li&gt;Usar un modelo en Amazon Bedrock.&lt;/li&gt;
&lt;li&gt;Configurar una alerta de presupuesto.&lt;/li&gt;
&lt;li&gt;Crear una aplicación web usando AWS Lambda.&lt;/li&gt;
&lt;li&gt;Crear una base de datos Amazon RDS.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 Recomendaciones para aprovechar al máximo el nuevo Free Tier
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Activa presupuestos y alertas de costos&lt;/strong&gt; desde el día uno.&lt;/li&gt;
&lt;li&gt;Usa servicios como &lt;strong&gt;Lambda, DynamoDB, S3 y API Gateway&lt;/strong&gt;, que tienen niveles gratuitos generosos.&lt;/li&gt;
&lt;li&gt;Aprovecha los &lt;strong&gt;retos sugeridos por AWS&lt;/strong&gt; para obtener más créditos.&lt;/li&gt;
&lt;li&gt;Prueba &lt;strong&gt;AWS Cloud9&lt;/strong&gt; para desarrollar directamente en la nube.&lt;/li&gt;
&lt;li&gt;Supervisa el uso desde el &lt;strong&gt;Billing Dashboard&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🔎 ¿Quién se ve afectado?
&lt;/h2&gt;

&lt;p&gt;Este nuevo modelo &lt;strong&gt;solo aplica a cuentas creadas desde el 15 de julio de 2025&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Si ya tenías una cuenta antes de esa fecha, &lt;strong&gt;sigues con tu Free Tier de 12 meses&lt;/strong&gt; y no debes preocuparte (por ahora).&lt;/p&gt;




&lt;h2&gt;
  
  
  🤔 ¿Mejor o peor?
&lt;/h2&gt;

&lt;p&gt;Depende del caso de uso.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Si sabes administrar tus recursos, puede ser &lt;strong&gt;más flexible&lt;/strong&gt; y educativo.&lt;/li&gt;
&lt;li&gt;❌ Si esperabas un año completo sin preocuparte por los costos, este cambio puede parecer un retroceso.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lo importante es que el nuevo enfoque &lt;strong&gt;te entrena a pensar como si tuvieras un sistema real en producción&lt;/strong&gt;, desde el primer día.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✍️ ¿Y tú qué opinas?
&lt;/h2&gt;

&lt;p&gt;¿Crees que este nuevo enfoque es mejor o peor?&lt;br&gt;&lt;br&gt;
¿Ya usaste tus créditos o hiciste alguna prueba interesante con esta nueva capa gratuita?&lt;/p&gt;

&lt;p&gt;💬 Cuéntame en los comentarios. ¡Me encantaría ver qué opinan otros desarrolladores de esta nueva era en AWS!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>freetier</category>
      <category>devops</category>
      <category>news</category>
    </item>
    <item>
      <title>🛠️Simula S3 Localmente con LocalStack y Docker Compose</title>
      <dc:creator>Juan Jose Miranda</dc:creator>
      <pubDate>Wed, 28 May 2025 16:00:00 +0000</pubDate>
      <link>https://forem.com/juan_jose_miranda/simula-s3-localmente-con-localstack-y-docker-compose-536c</link>
      <guid>https://forem.com/juan_jose_miranda/simula-s3-localmente-con-localstack-y-docker-compose-536c</guid>
      <description>&lt;p&gt;¿Alguna vez quisiste trabajar con S3 sin necesidad de una cuenta AWS o cargos por uso? &lt;strong&gt;LocalStack&lt;/strong&gt; es la solución. En este artículo te muestro cómo levantar LocalStack con Docker Compose, crear un bucket S3, subir un archivo y listar su contenido usando AWS CLI.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ Prerrequisitos
&lt;/h2&gt;

&lt;p&gt;Antes de comenzar, asegúrate de tener instalado lo siguiente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html" rel="noopener noreferrer"&gt;AWS CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/get-docker/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🐳 Paso 1: Docker Compose para LocalStack
&lt;/h2&gt;

&lt;p&gt;Primero, crea un archivo llamado &lt;code&gt;docker-compose.yml&lt;/code&gt; con el siguiente contenido:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.8'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;localstack&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localstack/localstack:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localstack&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4566:4566"&lt;/span&gt;   &lt;span class="c1"&gt;# Puerto principal de LocalStack&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SERVICES=s3&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DEBUG=1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DATA_DIR=/tmp/localstack/data&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_ACCESS_KEY_ID=test&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_SECRET_ACCESS_KEY=test&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DEFAULT_REGION=us-east-1&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./localstack:/tmp/localstack"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/var/run/docker.sock:/var/run/docker.sock"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este archivo levanta un contenedor de LocalStack con soporte &lt;strong&gt;solo para S3&lt;/strong&gt; y con credenciales fijas (&lt;code&gt;test/test&lt;/code&gt;), ideales para desarrollo local.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚀 Levanta el contenedor
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🔧 Paso 2: Configura AWS CLI
&lt;/h2&gt;

&lt;p&gt;Configura tus credenciales con los mismos valores definidos en el &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- AWS Access Key ID: &lt;span class="nb"&gt;test&lt;/span&gt;
- AWS Secret Access Key: &lt;span class="nb"&gt;test&lt;/span&gt;
- Region: us-east-1
- Output Format: json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🛠️ Paso 3: Crea un bucket S3 local
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3 mb s3://mi-bucket-local
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--endpoint-url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:4566
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verifica que el bucket fue creado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3 &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;--endpoint-url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:4566
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📁 Paso 4: Sube un archivo de prueba
&lt;/h2&gt;

&lt;p&gt;Primero, crea un archivo simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Hola desde LocalStack"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ejemplo.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luego, súbelo al bucket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;ejemplo.txt s3://mi-bucket-local/ &lt;span class="nt"&gt;--endpoint-url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:4566
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📄 Paso 5: Lista los objetos en el bucket
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3 &lt;span class="nb"&gt;ls &lt;/span&gt;s3://mi-bucket-local/ &lt;span class="nt"&gt;--endpoint-url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:4566
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Salida esperada:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2025-05-28 12:45:00         23 ejemplo.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ✅ Conclusión
&lt;/h2&gt;

&lt;p&gt;Con estos simples pasos, tienes un entorno de desarrollo local que simula Amazon S3 usando LocalStack. Ideal para desarrollo, pruebas automatizadas y aprendizaje sin costos ni conexión a Internet.&lt;/p&gt;

&lt;p&gt;¿Te gustaría extenderlo para trabajar con SDKs en Python, Node.js o integrarlo con Terraform? ¡Déjamelo saber en los comentarios! 🚀&lt;/p&gt;

</description>
      <category>aws</category>
      <category>docker</category>
      <category>localstack</category>
      <category>s3</category>
    </item>
    <item>
      <title>Spring Boot Configuration: When to Require, Default, or Leave Empty Environment Variables</title>
      <dc:creator>Juan Jose Miranda</dc:creator>
      <pubDate>Tue, 13 May 2025 16:11:55 +0000</pubDate>
      <link>https://forem.com/juan_jose_miranda/spring-boot-configuration-when-to-require-default-or-leave-empty-environment-variables-an1</link>
      <guid>https://forem.com/juan_jose_miranda/spring-boot-configuration-when-to-require-default-or-leave-empty-environment-variables-an1</guid>
      <description>&lt;p&gt;Spring Boot supports flexible environment variable interpolation in your &lt;code&gt;application.yml&lt;/code&gt; files, but it's important to &lt;strong&gt;know when to require a variable, leave it empty, or provide a default value&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Choosing the right approach improves reliability, avoids silent misconfigurations, and makes your application easier to maintain across environments.&lt;/p&gt;

&lt;p&gt;Let’s break it down into three types:&lt;/p&gt;




&lt;h3&gt;
  
  
  🔒 1. &lt;code&gt;${VARIABLE}&lt;/code&gt; — &lt;strong&gt;Required&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This format means the variable &lt;strong&gt;must be defined&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
If it's not present, Spring Boot will &lt;strong&gt;fail to start&lt;/strong&gt; with an error.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;When to use:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Use this for &lt;strong&gt;critical configuration&lt;/strong&gt; values your application can’t run without:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database connection details&lt;/li&gt;
&lt;li&gt;API credentials&lt;/li&gt;
&lt;li&gt;Encryption keys
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;datasource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_URL}&lt;/span&gt;       &lt;span class="c1"&gt;# Must be set&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_USER}&lt;/span&gt; &lt;span class="c1"&gt;# Must be set&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_PASS}&lt;/span&gt; &lt;span class="c1"&gt;# Must be set&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🟡 2. &lt;code&gt;${VARIABLE:}&lt;/code&gt; — &lt;strong&gt;Optional (empty by default)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This syntax allows the variable to be &lt;strong&gt;undefined&lt;/strong&gt;, in which case it defaults to an &lt;strong&gt;empty string&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;When to use:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Use when the value is &lt;strong&gt;not always required&lt;/strong&gt;, and you will handle its presence &lt;strong&gt;at runtime&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;api-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${EXTERNAL_API_KEY:}&lt;/span&gt;  &lt;span class="c1"&gt;# Will be empty if not defined&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📌 Remember to &lt;strong&gt;check if it's empty&lt;/strong&gt; before using it in your code.&lt;/p&gt;




&lt;h3&gt;
  
  
  🟢 3. &lt;code&gt;${VARIABLE:default}&lt;/code&gt; — &lt;strong&gt;Optional with fallback value&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This format sets a &lt;strong&gt;default value&lt;/strong&gt; if the variable is not defined.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;When to use:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Use when a &lt;strong&gt;sensible default&lt;/strong&gt; exists and makes development easier. This avoids overconfiguring every environment unnecessarily.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${SERVER_PORT:8080}&lt;/span&gt;  &lt;span class="c1"&gt;# Uses port 8080 if not set&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  ✅ Best Practices Summary
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Required, critical configuration&lt;/td&gt;
&lt;td&gt;&lt;code&gt;${VAR}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optional, check at runtime&lt;/td&gt;
&lt;td&gt;&lt;code&gt;${VAR:}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optional, default fallback&lt;/td&gt;
&lt;td&gt;&lt;code&gt;${VAR:default-value}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  📄 Example: &lt;code&gt;application.yml&lt;/code&gt; with Best Practices
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;profiles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${SPRING_PROFILES_ACTIVE:dev}&lt;/span&gt;  &lt;span class="c1"&gt;# Default to 'dev'&lt;/span&gt;

  &lt;span class="na"&gt;datasource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_URL}&lt;/span&gt;           &lt;span class="c1"&gt;# ❗ Required&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_USERNAME}&lt;/span&gt; &lt;span class="c1"&gt;# ❗ Required&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_PASSWORD}&lt;/span&gt; &lt;span class="c1"&gt;# ❗ Required&lt;/span&gt;
    &lt;span class="na"&gt;driver-class-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_DRIVER:com.mysql.cj.jdbc.Driver}&lt;/span&gt;  &lt;span class="c1"&gt;# ✅ Default fallback&lt;/span&gt;

  &lt;span class="na"&gt;jpa&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;hibernate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ddl-auto&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${HIBERNATE_DDL:auto}&lt;/span&gt;  &lt;span class="c1"&gt;# ✅ Default&lt;/span&gt;

&lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${SERVER_PORT:8080}&lt;/span&gt;  &lt;span class="c1"&gt;# ✅ Default port&lt;/span&gt;
  &lt;span class="na"&gt;servlet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;context-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${CONTEXT_PATH:/}&lt;/span&gt;

&lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${CLIENT_ID:localhost}&lt;/span&gt;     &lt;span class="c1"&gt;# ✅ Fallback value for local use&lt;/span&gt;
  &lt;span class="na"&gt;api-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${EXTERNAL_API_KEY:}&lt;/span&gt;  &lt;span class="c1"&gt;# 🔸 Optional&lt;/span&gt;

&lt;span class="na"&gt;management&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;show-values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;WHEN_AUTHORIZED&lt;/span&gt;  &lt;span class="c1"&gt;# Safer than ALWAYS&lt;/span&gt;
  &lt;span class="na"&gt;endpoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;base-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/actuator&lt;/span&gt;
      &lt;span class="na"&gt;exposure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;health,info&lt;/span&gt;

&lt;span class="na"&gt;security&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;jwt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${JWT_SECRET}&lt;/span&gt;           &lt;span class="c1"&gt;# ❗ Required&lt;/span&gt;
    &lt;span class="na"&gt;expiration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${JWT_EXPIRATION:3600}&lt;/span&gt;  &lt;span class="c1"&gt;# ✅ Default in seconds&lt;/span&gt;

&lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${APP_ENVIRONMENT:local}&lt;/span&gt;
  &lt;span class="na"&gt;feature-flag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enable-beta&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${ENABLE_BETA_FEATURE:false}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🛡️ Final Advice
&lt;/h3&gt;

&lt;p&gt;Always document which environment variables are &lt;strong&gt;mandatory&lt;/strong&gt; and validate them early when possible. This avoids surprises during deployment and improves your system’s robustness.&lt;/p&gt;




</description>
      <category>springboot</category>
      <category>java</category>
      <category>backend</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
