<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Codeanding]]></title><description><![CDATA[Codeanding]]></description><link>https://codeanding.com</link><generator>RSS for Node</generator><lastBuildDate>Tue, 07 Apr 2026 20:39:45 GMT</lastBuildDate><atom:link href="https://codeanding.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Building My Own Nakama with RAG]]></title><description><![CDATA[Last year when I went to React Miami, I was talking with a friend about what anime they were watching and a popular one jumped into the conversation: One Piece. Many friends had recommended it to me, but due to the amount of episodes I doubted if I s...]]></description><link>https://codeanding.com/building-my-own-nakama-with-rag</link><guid isPermaLink="true">https://codeanding.com/building-my-own-nakama-with-rag</guid><category><![CDATA[RAG ]]></category><category><![CDATA[one piece]]></category><category><![CDATA[Python]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Mon, 26 Jan 2026 04:00:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769399995571/1981e390-89be-479f-9c2c-ffdf662d0589.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Last year when I went to <a target="_blank" href="https://codeanding.com/from-hola-to-hello-my-react-miami-adventure">React Miami</a>, I was talking with a friend about what anime they were watching and a popular one jumped into the conversation: One Piece. Many friends had recommended it to me, but due to the amount of episodes I doubted if I should start watching it. My friend convinced me and when I got home I started watching (at that moment I didn't know about One Pace).</p>
<p>In December 2025, I was able to finish watching One Piece, and it was an amazing experience. I loved the story, the references, the characters, and the world created by Eiichiro Oda.</p>
<p>So, maybe you're wondering, why build a RAG system for One Piece? Let me tell you why:</p>
<ul>
<li>When I started the anime, I had a lot of questions. What did I do? Research, ask friends, fall into wiki rabbit holes. And I thought, what if I could build my own nakama - a virtual crewmate who's seen every episode, read the wiki, and can answer anything I ask?</li>
</ul>
<p>Could I just Google everything? Sure. But I wanted something more - a companion for my One Piece journey. Someone who knows the lore, understands the terminology, and is always there when I need answers. That's why I decided to build this RAG system: my own nakama.</p>
<p>What we will cover in this blog post:</p>
<ul>
<li>How I gave my nakama a brain (data pipeline and chunking)</li>
<li>RAG best practices that actually matter</li>
<li>The Buccaneer problem</li>
<li>What I learned</li>
<li>Going to production</li>
<li>When a nakama is (and isn't) the answer</li>
<li>How you can build your own</li>
</ul>
<p>Let's start with: What is RAG?
<em>RAG</em> comes from Retrieval-Augmented Generation, and what does that mean?</p>
<ul>
<li>R: Retrieval: We have a knowledge base (in this case, One Piece data) that we can search for relevant information.</li>
<li>A: Augmented: We use the retrieved information to augment the input to a language model.</li>
<li>G: Generation: The language model generates a response based on the augmented input.</li>
</ul>
<h2 id="heading-giving-my-nakama-a-brain">Giving My Nakama a Brain</h2>
<p>Before my nakama could answer anything, I needed to give them knowledge. Where do you get One Piece data? The internet has plenty of sources. I started with three (you can always add more, but be careful - data quality matters more than quantity):</p>
<h3 id="heading-the-data-sources">The Data Sources</h3>
<p><strong>1. Subtitles from One Pace</strong>
One Pace is a fan project that removes filler from the anime. I grabbed subtitles from 400+ episodes - every line of dialogue, every scene. This became the core of my nakama's memory.</p>
<p><strong>2. Wiki Pages</strong>
The One Piece Wiki has detailed information about characters, races, Devil Fruits, and lore. I scraped key pages and translated them (the Spanish wiki often has more recent info).</p>
<p><strong>3. Manga Transcripts</strong>
For the latest arcs not yet in the anime, manga transcripts fill the gaps.</p>
<h3 id="heading-the-chunking-challenge">The Chunking Challenge</h3>
<p>You can't just dump entire episodes into a database. The text needs to be split into chunks small enough to search effectively, but large enough to preserve context.</p>
<pre><code class="lang-python"><span class="hljs-comment"># My chunking config</span>
chunk_size: int = <span class="hljs-number">500</span>      <span class="hljs-comment"># Max characters per chunk</span>
chunk_overlap: int = <span class="hljs-number">50</span>    <span class="hljs-comment"># Overlap between chunks</span>
</code></pre>
<p>Why overlap? Imagine a sentence gets cut in half at a chunk boundary. With overlap, the important context carries into the next chunk.</p>
<h3 id="heading-cleaning-the-data">Cleaning the Data</h3>
<p>Subtitles are messy. Music markers, formatting codes, speaker tags - all noise that confuses the search:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Before cleaning</span>
<span class="hljs-string">"♪ We Are! ♪ [LUFFY] I'm gonna be King of the Pirates!"</span>

<span class="hljs-comment"># After cleaning</span>
<span class="hljs-string">"I'm gonna be King of the Pirates!"</span>
</code></pre>
<p>The result? <strong>136,000+ clean chunks</strong> of One Piece knowledge, ready to be searched.</p>
<h2 id="heading-the-architecture">The Architecture</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768609187546/53ad614b-637f-44e4-860e-e82a348c84d4.png" alt="RAG Architecture Diagram" /></p>
<p>User asks a question → the query gets embedded → we search the vector database for similar chunks → rerank the results → feed the best chunks + question to the LLM → get an answer with context.</p>
<h2 id="heading-rag-best-practices-what-i-actually-implemented">RAG Best Practices (What I Actually Implemented)</h2>
<p>Building this nakama taught me that generic RAG tutorials skip the important stuff. This is what worked for me:</p>
<h3 id="heading-1-hybrid-search-dont-choose-between-semantic-and-keyword">1. Hybrid Search: Don't Choose Between Semantic and Keyword</h3>
<p>Most tutorials tell you to use vector search OR keyword search. I use both:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Combine vector similarity (70%) with keyword matching (30%)</span>
combined_score = vector_score * <span class="hljs-number">0.7</span> + keyword_score * <span class="hljs-number">0.3</span>
</code></pre>
<p><strong>Why?</strong> Vector search understands meaning ("Who is the rubber pirate?" finds Luffy), but misses exact terms. Keyword search catches specific names and techniques. Together, they cover more ground.</p>
<h3 id="heading-2-two-stage-retrieval-fast-first-accurate-second">2. Two-Stage Retrieval: Fast First, Accurate Second</h3>
<p>Searching 136K chunks needs to be fast. But accuracy matters too. So I split it into two stages.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Stage 1: Fast bi-encoder retrieves 3x more candidates</span>
retrieval_top_k = final_top_k * <span class="hljs-number">3</span>  <span class="hljs-comment"># Get 24 candidates if we need 8</span>

<span class="hljs-comment"># Stage 2: Slower cross-encoder re-ranks for precision</span>
reranked = reranker.rerank(candidates, top_k=final_top_k)
</code></pre>
<p>The bi-encoder (embedding search) is fast - milliseconds to scan thousands of chunks. The cross-encoder is slower but more accurate - it compares the query directly against each candidate. You get speed AND accuracy.</p>
<h3 id="heading-3-overlapping-chunks-dont-lose-context-at-boundaries">3. Overlapping Chunks: Don't Lose Context at Boundaries</h3>
<p>When building a RAG, overlapping is easy to ignore - until you lose answers you know are in your data. Here's what happens without overlap:</p>
<pre><code># Chunk <span class="hljs-number">1</span> ends here:
<span class="hljs-string">"...Luffy ate the Gomu Gomu no Mi which is actually"</span>

# Chunk <span class="hljs-number">2</span> starts here:
<span class="hljs-string">"the Hito Hito no Mi Model: Nika, a mythical zoan fruit..."</span>
</code></pre><p>Someone asks: "What is Luffy's real Devil Fruit?" Neither chunk answers it. The connection between them got split at the boundary.</p>
<p>With 50 characters of overlap:</p>
<pre><code># Chunk <span class="hljs-number">1</span>:
<span class="hljs-string">"...Luffy ate the Gomu Gomu no Mi which is actually the Hito Hito no Mi"</span>

# Chunk <span class="hljs-number">2</span>:
<span class="hljs-string">"which is actually the Hito Hito no Mi Model: Nika, a mythical zoan fruit..."</span>
</code></pre><p>Now both chunks contain the connection. The search can find it.</p>
<pre><code class="lang-python">chunk_size: int = <span class="hljs-number">500</span>
chunk_overlap: int = <span class="hljs-number">50</span>  <span class="hljs-comment"># 10% overlap - don't skip this</span>
</code></pre>
<h3 id="heading-4-lazy-load-heavy-models">4. Lazy-Load Heavy Models</h3>
<p>Embedding models are big. Loading them blocks your application startup. Instead, load on first use:</p>
<pre><code class="lang-python"><span class="hljs-meta">@property</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">model</span>(<span class="hljs-params">self</span>) -&gt; SentenceTransformer:</span>
    <span class="hljs-string">"""Lazy-load the embedding model on first access."""</span>
    <span class="hljs-keyword">if</span> self._model <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:
        self._model = SentenceTransformer(self._model_name)
    <span class="hljs-keyword">return</span> self._model
</code></pre>
<p>Your API starts instantly. The model loads when someone actually asks a question.</p>
<h3 id="heading-5-cache-but-be-smart-about-it">5. Cache, But Be Smart About It</h3>
<p>Repeated questions? Cache the response. But conversational follow-ups need fresh context:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Cache standalone questions</span>
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> conversation_history:
    cached = cache.get(question)
    <span class="hljs-keyword">if</span> cached:
        <span class="hljs-keyword">return</span> cached

<span class="hljs-comment"># Skip cache for conversations (context-dependent)</span>
</code></pre>
<h2 id="heading-the-buccaneer-problem">The Buccaneer Problem</h2>
<p>Someone asked: <strong>"Is Whitebeard a buccaneer?"</strong></p>
<p>My nakama said yes.</p>
<blockquote>
<p>"Yes, Whitebeard is considered a buccaneer in the One Piece universe..."</p>
</blockquote>
<p><strong>Wrong.</strong> In One Piece, "Buccaneer" isn't just a pirate term - it's a <strong>race</strong>. Kuma is the last confirmed Buccaneer. Whitebeard is human.</p>
<p>(There's a fan theory that Whitebeard might have Buccaneer blood - similar build to Kuma, and Oda dropped some hints in Chapter 1100. Not confirmed though.)</p>
<p>So what happened? The retrieval found chunks about Whitebeard, not about the Buccaneer race. And without that context, the LLM fell back to what it knows: "buccaneer" = pirate. Technically correct in the real world, completely wrong in One Piece.</p>
<p>This is the thing about domain-specific terminology. One Piece has its own dictionary - Devil Fruits, Haki, specific races. If your data doesn't cover these terms explicitly, your RAG will hallucinate real-world meanings.</p>
<p>I fixed it two ways.</p>
<p><strong>More data.</strong> I scraped wiki pages specifically about One Piece races:</p>
<pre><code class="lang-python">WIKI_PAGES = [
    <span class="hljs-string">"Buccaneer"</span>,
    <span class="hljs-string">"Lunaria"</span>,
    <span class="hljs-string">"Gyojin"</span>,  <span class="hljs-comment"># Fishmen</span>
    <span class="hljs-string">"Bartholomew_Kuma"</span>,
    <span class="hljs-comment"># ...</span>
]
</code></pre>
<p><strong>Better prompts.</strong> Your system prompt isn't just instructions - it's context the LLM always sees, regardless of what gets retrieved. I added a terminology section:</p>
<pre><code class="lang-python">SYSTEM_PROMPT = <span class="hljs-string">"""You are an expert on One Piece...

CRITICAL ONE PIECE TERMINOLOGY:
- "Buccaneer" is a RACE of people, NOT just a pirate term.
  Bartholomew Kuma is the last known Buccaneer.
- "Lunarian" is a race from the Red Line (King is a Lunarian)
- "Fishmen" and "Merfolk" are aquatic races
...
"""</span>
</code></pre>
<p>Now when someone asks about Whitebeard and buccaneers:</p>
<blockquote>
<p>"No, Whitebeard (Edward Newgate) is not a Buccaneer. In the One Piece universe, Buccaneers are a specific race of people, with Bartholomew Kuma being the last known representative..."</p>
</blockquote>
<p>Much better.</p>
<h2 id="heading-what-i-learned-building-this">What I Learned Building This</h2>
<p><strong>Domain vocabulary will break your RAG.</strong> One Piece has its own dictionary - Devil Fruits, Haki, races like Buccaneers. If your data doesn't define these terms, your RAG will hallucinate real-world meanings. Before building, list the weird terms your users might ask about.</p>
<p><strong>Your system prompt is part of your knowledge base.</strong> I used to think prompts were just instructions. They're not - it's context the LLM always sees. The terminology section in my prompt catches stuff that retrieval misses.</p>
<p><strong>Easy questions won't expose problems.</strong> "Who is Luffy?" works on day one. "Is Whitebeard a buccaneer?" breaks on day 30. Build a test set of weird questions early.</p>
<p><strong>You're never done.</strong> I thought I'd build it, deploy it, move on. Nope. Data → Test → Fail → Fix → Repeat. The Buccaneer problem showed up weeks after I thought I was finished.</p>
<h2 id="heading-going-to-production">Going to Production</h2>
<p>Building a RAG that works on your laptop is one thing. Putting it in front of real users? Different game.</p>
<p><strong>Monitor what fails.</strong> Track which questions get weird answers. The Buccaneer problem? I only found it because someone told me. In production, you need logs. What queries returned low-relevance chunks? What made users ask again? That's your debugging goldmine.</p>
<p><strong>Teach it to say "I don't know".</strong> A confident wrong answer is worse than admitting ignorance. I added a relevance threshold - if the best chunks score below 0.3, my nakama says it doesn't have enough info instead of guessing.</p>
<p><strong>Plan for data updates.</strong> One Piece isn't finished. New episodes, new manga chapters, new lore. How do you add data without re-embedding everything? I batch new content separately and merge it. Not perfect, but it works.</p>
<p><strong>Watch your costs.</strong> Every question = embedding call + LLM call. At scale, this adds up fast. Caching helps (I mentioned this earlier), but also consider: do you really need GPT-4 for every query? Sometimes a smaller model is enough.</p>
<p><strong>Rate limit everything.</strong> Someone will try to break your system. Rate limiting isn't just about costs - it's about not letting one curious user crash your database with 1000 queries.</p>
<p>136K chunks sounds like a lot, but you can always add more. Just be careful - bad data creates bad answers. Quality &gt; quantity, always.</p>
<h2 id="heading-when-a-nakama-isnt-the-answer">When a Nakama Isn't the Answer</h2>
<p>Could I just Google my One Piece questions? Yes. Is this over-engineering? Maybe.</p>
<p><strong>When Google is enough:</strong></p>
<ul>
<li>Simple factual lookups ("When did Ace die?")</li>
<li>Checking episode numbers</li>
<li>Finding character images</li>
</ul>
<p><strong>When a nakama shines:</strong></p>
<ul>
<li>Questions that span multiple sources ("What connections exist between Joy Boy and the Buccaneers?")</li>
<li>Conversational follow-ups ("What about his Devil Fruit?")</li>
<li>Domain-specific terminology (the Buccaneer problem!)</li>
<li>Having a companion who understands context</li>
</ul>
<p>I didn't build this just to answer questions. Using One Piece made it fun to show how RAG actually works - and how it fails. The Buccaneer problem says it all.</p>
<p>And honestly? It's fun having a nakama who knows One Piece as well as I do.</p>
<h2 id="heading-build-your-own-nakama">Build Your Own Nakama</h2>
<p>Want to try it yourself? The code is open source.</p>
<p><strong>Tech Stack:</strong></p>
<ul>
<li>FastAPI + Python (Backend)</li>
<li>PostgreSQL + pgvector (Vector DB)</li>
<li>sentence-transformers (Embeddings)</li>
<li>Next.js (Frontend)</li>
</ul>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/codeanding/onepiece-rag
<span class="hljs-built_in">cd</span> onepiece-rag
docker-compose up -d
<span class="hljs-comment"># Visit http://localhost:3000</span>
</code></pre>
<p>Check the README for detailed setup instructions.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Building this showed me the best way to explain RAG - use a domain you love. The Buccaneer problem wasn't a bug; it was the perfect example of how RAG fails.</p>
<p>Every question it can't answer is a chance to teach it something new. That's the fun part.</p>
<p>If you're thinking about building a RAG system, my advice: pick a domain you love. You'll be debugging it at 2am, and you should at least enjoy the data.</p>
<p>Now if you'll excuse me, I need to go ask my nakama about the Void Century.</p>
<p>In the next entry, we'll explore a more real use case - RAG for the healthcare industry. Stay tuned!</p>
<p>Keep coding and learning!</p>
]]></content:encoded></item><item><title><![CDATA[Supabase in Practice: Auth, Database, and Storage]]></title><description><![CDATA[Hello everyone! When I started building my Year Soundtrack Generator, I needed three things: user authentication, a database, and file storage for audio. Instead of juggling multiple services, I chose Supabase.
In my previous post, I covered how I us...]]></description><link>https://codeanding.com/supabase-in-practice-auth-database-and-storage</link><guid isPermaLink="true">https://codeanding.com/supabase-in-practice-auth-database-and-storage</guid><category><![CDATA[supabase-storage]]></category><category><![CDATA[supabase]]></category><category><![CDATA[supabase auth]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Sat, 03 Jan 2026 04:41:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1767415212879/368a65a0-52d6-4074-9524-5b1603498618.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello everyone! When I started building my <a target="_blank" href="https://soundtrack.codeanding.com/en">Year Soundtrack Generator</a>, I needed three things: user authentication, a database, and file storage for audio. Instead of juggling multiple services, I chose Supabase.</p>
<p>In my <a target="_blank" href="/from-life-moments-to-songs">previous post</a>, I covered how I use ElevenLabs to generate personalized music. Today, let's dive into the backend.</p>
<h2 id="heading-what-is-supabase">What is Supabase?</h2>
<p>Supabase is an open-source Firebase alternative that provides backend services for developers. I chose it for this project because:</p>
<ul>
<li><strong>Free tier</strong>: Generous limits for side projects (500MB database, 1GB storage, 50K monthly active users)</li>
<li><strong>Framework support</strong>: Official SDKs for JavaScript, Flutter, Python, and integrations with Next.js, Astro, SvelteKit, etc.</li>
<li><strong>All-in-one</strong>: Database, auth, and storage in one platform - fewer services to manage</li>
</ul>
<p>For this project, I used three of its core features:</p>
<ul>
<li><strong>Database</strong>: PostgreSQL with real-time subscriptions and auto-generated APIs</li>
<li><strong>Authentication</strong>: Email/password, magic links, and OAuth providers</li>
<li><strong>Storage</strong>: File storage with CDN delivery, perfect for serving audio files</li>
</ul>
<h2 id="heading-database-design-thinking-in-layers">Database Design: Thinking in Layers</h2>
<p>Before writing any code, I had to think about how to structure my data. The key insight was separating <strong>user input</strong> from <strong>AI output</strong>.</p>
<p>Here's what I came up with:</p>
<pre><code>┌──────────────────────────────────┐
│   profiles (credits, settings)   │
└────────────────┬─────────────────┘
                 │
                 ▼
┌──────────────────────────────────┐
│  soundtracks (title, year)       │
└────────────────┬─────────────────┘
                 │
        ┌────────┴────────┐
        ▼                 ▼
┌───────────────┐  ┌───────────────┐
│    moments    │  │    tracks     │
│  (user input) │─▶│  (AI output)  │
└───────────────┘  └───────────────┘
</code></pre><p><strong>Why this separation matters:</strong></p>
<ol>
<li><strong>Re-generation</strong>: If a track generation fails, I can retry without losing the user's original moment description</li>
<li><strong>Partial success</strong>: 3 out of 5 tracks can succeed while 2 fail</li>
<li><strong>Audit trail</strong>: I store the exact prompt used for each track, so I can debug or reproduce results</li>
</ol>
<p><strong>Pro tip</strong>: Supabase can generate TypeScript types from your schema (similar to what Prisma does). It's been really helpful for catching errors early.</p>
<h2 id="heading-authentication-with-magic-links">Authentication with Magic Links</h2>
<p>The frontend is built with <a target="_blank" href="https://astro.build/">Astro</a> using SSR mode. For Supabase auth in SSR frameworks, you need cookie-based sessions. The <code>@supabase/ssr</code> package handles this.</p>
<h3 id="heading-a-note-on-api-keys">A Note on API Keys</h3>
<p>Supabase recently introduced a <a target="_blank" href="https://supabase.com/docs/guides/api/api-keys">new API key system</a>. You'll see two types:</p>
<ul>
<li><strong>Publishable key</strong> (<code>sb_publishable_...</code>): Safe for client-side code. Security comes from Row Level Security (RLS) policies, not from hiding the key.</li>
<li><strong>Secret key</strong> (<code>sb_secret_...</code>): Server-side only. Bypasses RLS - never expose this in client code.</li>
</ul>
<p>The older <code>anon</code> and <code>service_role</code> keys still work but are <a target="_blank" href="https://github.com/orgs/supabase/discussions/29260">being phased out</a>.</p>
<h3 id="heading-row-level-security-rls">Row Level Security (RLS)</h3>
<p>RLS is what makes the publishable key safe. It controls what each user can access at the database level:</p>
<pre><code class="lang-sql"><span class="hljs-comment">-- Users can only read their own soundtracks</span>
<span class="hljs-keyword">create</span> <span class="hljs-keyword">policy</span> <span class="hljs-string">"Users read own soundtracks"</span>
<span class="hljs-keyword">on</span> soundtracks <span class="hljs-keyword">for</span> <span class="hljs-keyword">select</span>
<span class="hljs-keyword">using</span> (auth.uid() = user_id);
</code></pre>
<p>Without RLS enabled, your data is exposed to anyone with the publishable key. Supabase shows security alerts in your dashboard if tables are missing RLS policies - pay attention to them!</p>
<h3 id="heading-setting-up-the-clients">Setting Up the Clients</h3>
<p>For browser-side:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/lib/supabase/client.ts</span>
<span class="hljs-keyword">import</span> { createBrowserClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@supabase/ssr'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> supabase = createBrowserClient&lt;Database&gt;(
  <span class="hljs-keyword">import</span>.meta.env.PUBLIC_SUPABASE_URL,
  <span class="hljs-keyword">import</span>.meta.env.PUBLIC_SUPABASE_PUBLISHABLE_KEY
);
</code></pre>
<p>For server-side (Astro), you need to manage cookies manually with <code>getAll()</code> and <code>setAll()</code> handlers. See the <a target="_blank" href="https://supabase.com/docs/guides/auth/server-side/creating-a-client">@supabase/ssr documentation</a> for the full implementation.</p>
<h3 id="heading-middleware-for-protected-routes">Middleware for Protected Routes</h3>
<p>To protect routes, I use Astro middleware:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/middleware.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> onRequest = <span class="hljs-keyword">async</span> ({ locals, url, cookies, redirect }) =&gt; {
  <span class="hljs-keyword">const</span> supabase = createServerSupabaseClient(cookies);
  <span class="hljs-keyword">const</span> { data: { user } } = <span class="hljs-keyword">await</span> supabase.auth.getUser();

  <span class="hljs-keyword">const</span> protectedRoutes = [<span class="hljs-string">'/create'</span>, <span class="hljs-string">'/profile'</span>];
  <span class="hljs-keyword">const</span> isProtected = protectedRoutes.some(<span class="hljs-function"><span class="hljs-params">route</span> =&gt;</span>
    url.pathname.startsWith(route)
  );

  <span class="hljs-keyword">if</span> (isProtected &amp;&amp; !user) {
    <span class="hljs-keyword">return</span> redirect(<span class="hljs-string">`/auth/login?redirect=<span class="hljs-subst">${url.pathname}</span>`</span>);
  }

  locals.user = user;
};
</code></pre>
<h2 id="heading-file-storage-for-audio">File Storage for Audio</h2>
<p>After ElevenLabs generates an MP3, I upload it directly to Supabase Storage:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Upload to Supabase Storage</span>
<span class="hljs-keyword">const</span> fileName = <span class="hljs-string">`<span class="hljs-subst">${user.id}</span>/<span class="hljs-subst">${soundtrackId}</span>/track_<span class="hljs-subst">${orderIndex}</span>.mp3`</span>;

<span class="hljs-keyword">const</span> { error: uploadError } = <span class="hljs-keyword">await</span> supabase.storage
  .from(<span class="hljs-string">'soundtracks'</span>)
  .upload(fileName, audioBuffer, {
    contentType: <span class="hljs-string">'audio/mpeg'</span>,
    upsert: <span class="hljs-literal">true</span>,
  });

<span class="hljs-comment">// Get public URL for playback</span>
<span class="hljs-keyword">const</span> { data: { publicUrl } } = supabase.storage
  .from(<span class="hljs-string">'soundtracks'</span>)
  .getPublicUrl(fileName);
</code></pre>
<p>The path structure <code>{user_id}/{soundtrack_id}/track_{index}.mp3</code> makes it easy to:</p>
<ul>
<li>Find all tracks for a soundtrack</li>
<li>Clean up when a user deletes their data</li>
<li>Set bucket policies per user</li>
</ul>
<h3 id="heading-bucket-policies">Bucket Policies</h3>
<p>Storage buckets also need policies. I configured mine to allow public reads (so anyone can play shared soundtracks) but restrict writes to authenticated users:</p>
<pre><code class="lang-sql"><span class="hljs-comment">-- Allow public read access</span>
<span class="hljs-keyword">create</span> <span class="hljs-keyword">policy</span> <span class="hljs-string">"Public read access"</span>
<span class="hljs-keyword">on</span> storage.objects <span class="hljs-keyword">for</span> <span class="hljs-keyword">select</span>
<span class="hljs-keyword">using</span> (bucket_id = <span class="hljs-string">'soundtracks'</span>);

<span class="hljs-comment">-- Allow authenticated users to upload</span>
<span class="hljs-keyword">create</span> <span class="hljs-keyword">policy</span> <span class="hljs-string">"Authenticated users can upload"</span>
<span class="hljs-keyword">on</span> storage.objects <span class="hljs-keyword">for</span> <span class="hljs-keyword">insert</span>
<span class="hljs-keyword">with</span> <span class="hljs-keyword">check</span> (bucket_id = <span class="hljs-string">'soundtracks'</span> <span class="hljs-keyword">and</span> auth.role() = <span class="hljs-string">'authenticated'</span>);
</code></pre>
<h2 id="heading-rate-limiting">Rate Limiting</h2>
<p>Supabase doesn't include built-in rate limiting for the Data API. Common options:</p>
<ul>
<li><strong>Cloudflare</strong>: Free rate limiting rules if your domain is proxied through them</li>
<li><strong>Redis (Upstash)</strong>: Best for high-traffic apps with atomic operations</li>
<li><strong>Database table</strong>: Simple approach for smaller projects</li>
</ul>
<p>For this project, I use <strong>Cloudflare</strong> at the DNS level (my domain is proxied through them), plus a simple <code>usage_logs</code> table for app-level tracking:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkRateLimit</span>(<span class="hljs-params">userId: <span class="hljs-built_in">string</span>, action: <span class="hljs-built_in">string</span></span>) </span>{
  <span class="hljs-keyword">const</span> windowMs = <span class="hljs-number">60</span> * <span class="hljs-number">60</span> * <span class="hljs-number">1000</span>; <span class="hljs-comment">// 1 hour</span>
  <span class="hljs-keyword">const</span> maxRequests = <span class="hljs-number">10</span>; <span class="hljs-comment">// 10 tracks per hour</span>
  <span class="hljs-keyword">const</span> since = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(<span class="hljs-built_in">Date</span>.now() - windowMs);

  <span class="hljs-keyword">const</span> { count } = <span class="hljs-keyword">await</span> supabase
    .from(<span class="hljs-string">'usage_logs'</span>)
    .select(<span class="hljs-string">'*'</span>, { count: <span class="hljs-string">'exact'</span> })
    .eq(<span class="hljs-string">'user_id'</span>, userId)
    .eq(<span class="hljs-string">'action'</span>, action)
    .gte(<span class="hljs-string">'created_at'</span>, since.toISOString());

  <span class="hljs-keyword">return</span> { allowed: (count || <span class="hljs-number">0</span>) &lt; maxRequests };
}
</code></pre>
<p>For more options, see <a target="_blank" href="https://supabase.com/docs/guides/api/securing-your-api">Supabase's guide on securing your API</a>.</p>
<hr />
<p>That's how I integrated auth, database, and storage with Supabase. For a side project, having everything in one platform with a free tier made it easy to go from idea to deployed app.</p>
<p>You can try the app at <a target="_blank" href="https://soundtrack.codeanding.com/en">soundtrack.codeanding.com/en</a>. Have you used Supabase with Astro or another SSR framework? I'd love to hear about your experience!</p>
<p><em>This is part 2 of a 2-part series. <a target="_blank" href="/from-life-moments-to-songs">Part 1</a> covers how I use ElevenLabs Music API to generate personalized songs from life moments.</em></p>
]]></content:encoded></item><item><title><![CDATA[From Life Moments to Songs]]></title><description><![CDATA[Think about the moments that defined your year. Maybe it was a big win at work, a trip that changed your perspective, or even a difficult experience that taught you something important. Every moment—joyful or challenging—carries an emotion worth reme...]]></description><link>https://codeanding.com/from-life-moments-to-songs</link><guid isPermaLink="true">https://codeanding.com/from-life-moments-to-songs</guid><category><![CDATA[elevenlabs]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Thu, 01 Jan 2026 01:57:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1767232540771/12b5be3f-3719-434c-8b07-b34a8167e16f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Think about the moments that defined your year. Maybe it was a big win at work, a trip that changed your perspective, or even a difficult experience that taught you something important. Every moment—joyful or challenging—carries an emotion worth remembering.</p>
<p>What if you could <em>hear</em> those moments as songs?</p>
<p>That's exactly what I built: a <strong>Year Soundtrack Generator</strong> that transforms your life moments into personalized AI-generated songs. Before we dive into the code, here's what we're building: <a target="_blank" href="https://soundtrack.codeanding.com/en">soundtrack.codeanding.com/en</a></p>
<h2 id="heading-why-elevenlabs-music-api">Why ElevenLabs Music API?</h2>
<p>Earlier this year, I participated in a hackathon where we received ElevenLabs credits. Most people know them for voice cloning and text-to-speech, but they also have a <strong>Music API</strong> that generates complete songs with vocals. With the year ending and credits still available, I wanted to build something meaningful before they expired.</p>
<p>ElevenLabs stood out because:</p>
<ul>
<li>It generates music with actual vocals (not just instrumentals)</li>
<li>The API is straightforward to integrate</li>
<li>It supports multiple languages for lyrics</li>
</ul>
<p>Here's the breakdown of how it works:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.elevenlabs.io/v1/music'</span>, {
  method: <span class="hljs-string">'POST'</span>,
  headers: {
    <span class="hljs-string">'xi-api-key'</span>: <span class="hljs-built_in">this</span>.apiKey,
    <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>,
  },
  body: <span class="hljs-built_in">JSON</span>.stringify({
    prompt: request.prompt,
    music_length_ms: <span class="hljs-built_in">Math</span>.min(<span class="hljs-built_in">Math</span>.max(durationMs, <span class="hljs-number">3000</span>), <span class="hljs-number">300000</span>), <span class="hljs-comment">// 3s to 5min</span>
    model_id: <span class="hljs-string">'music_v1'</span>,
    force_instrumental: <span class="hljs-literal">false</span>, <span class="hljs-comment">// Allow vocals based on prompt</span>
  }),
});
</code></pre>
<p>The key parameters are:</p>
<ul>
<li><strong>prompt</strong>: A text description of what you want the song to be about</li>
<li><strong>music_length_ms</strong>: Duration between 3 seconds and 5 minutes</li>
<li><strong>model_id</strong>: Currently <code>music_v1</code></li>
<li><strong>force_instrumental</strong>: Set to <code>false</code> to include vocals</li>
</ul>
<p>Credits-wise, expect around <strong>500 credits per minute</strong> of generated audio.</p>
<h2 id="heading-the-challenge-turning-text-into-music">The Challenge: Turning Text into Music</h2>
<p>Now comes the fun part - how do you tell an AI to make a song about "I got promoted at work"?</p>
<p>My first attempts were... not great. When I just passed the user's moment description directly, the AI would generate very literal lyrics like "I went to the office and got a promotion." Not exactly the emotional soundtrack I was going for!</p>
<p>I needed a smarter approach. Here's my 3-layer prompt system:</p>
<h3 id="heading-layer-1-emotion-music-theory">Layer 1: Emotion → Music Theory</h3>
<p>First, I map emotions to actual music characteristics. A happy moment should sound different from a triumphant one:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> EMOTION_TO_MUSIC: Record&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>&gt; = {
  happy: <span class="hljs-string">'upbeat, major key, bright instrumentation, energetic tempo around 120-140 BPM'</span>,
  sad: <span class="hljs-string">'melancholic, minor key, slow tempo 60-80 BPM, piano and strings, emotional'</span>,
  nostalgic: <span class="hljs-string">'warm, analog feel, vintage production, reverb-soaked, mid-tempo'</span>,
  triumphant: <span class="hljs-string">'epic, orchestral swells, powerful drums, anthemic, building crescendo'</span>,
  peaceful: <span class="hljs-string">'ambient, soft, acoustic, gentle, relaxing, 70-90 BPM'</span>,
  energetic: <span class="hljs-string">'high energy, driving beat, electronic elements, 130+ BPM, punchy'</span>,
};
</code></pre>
<h3 id="heading-layer-2-genre-style-modifiers">Layer 2: Genre → Style Modifiers</h3>
<p>Next, users select their preferred music style. Each genre has specific production characteristics:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> STYLE_MODIFIERS: Record&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>&gt; = {
  pop: <span class="hljs-string">'catchy hooks, polished production, radio-friendly pop'</span>,
  rock: <span class="hljs-string">'electric guitars, drums, raw rock energy'</span>,
  <span class="hljs-string">'lo-fi'</span>: <span class="hljs-string">'lo-fi hip hop, vinyl crackle, mellow beats, chill'</span>,
  electronic: <span class="hljs-string">'synthesizers, electronic beats, modern EDM production'</span>,
  <span class="hljs-string">'j-rock'</span>: <span class="hljs-string">'Japanese rock, anime soundtrack style, visual kei influences'</span>,
  <span class="hljs-string">'k-pop'</span>: <span class="hljs-string">'Korean pop, bright synths, catchy hooks, polished K-pop production'</span>,
  <span class="hljs-comment">// ... 10 more genres</span>
};
</code></pre>
<h3 id="heading-layer-3-language-vocal-direction">Layer 3: Language → Vocal Direction</h3>
<p>Since the app supports Spanish, English, and Portuguese, I also direct the AI on vocal style:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> LANGUAGE_VOCAL_DIRECTION: Record&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>&gt; = {
  en: <span class="hljs-string">'English vocals, clear pronunciation'</span>,
  es: <span class="hljs-string">'Spanish vocals, Latin influence'</span>,
  pt: <span class="hljs-string">'Portuguese vocals, Brazilian or Portuguese influence'</span>,
};
</code></pre>
<h2 id="heading-the-secret-sauce-artistic-transformation">The Secret Sauce: Artistic Transformation</h2>
<p>Here's what I learned after experimenting with different prompts: the model tends to generate very literal lyrics. If your moment is "Beach vacation with friends," you'll get lyrics about sand and waves.</p>
<p>The fix? Explicit instructions for poetic, metaphorical writing:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> prompt = [
  styleDesc,
  emotionDesc,
  vocalLang,
  <span class="hljs-string">`Song about: "<span class="hljs-subst">${safeTitle}</span>"`</span>,
  <span class="hljs-string">`Core emotion to convey: <span class="hljs-subst">${emotionContext}</span>`</span>,
  <span class="hljs-string">`Context for inspiration (transform into poetry, NEVER copy literally): <span class="hljs-subst">${safeDescription}</span>`</span>,
  <span class="hljs-string">'IMPORTANT: Write artistic, metaphorical lyrics using imagery and symbolism'</span>,
  <span class="hljs-string">'Focus on the emotional journey and transformation, not literal events'</span>,
  <span class="hljs-string">'Use universal themes like light/dark, rise/fall, storms/calm to express feelings'</span>,
  <span class="hljs-string">'30-45 second track with vocals, clear intro and outro'</span>,
].join(<span class="hljs-string">'. '</span>);
</code></pre>
<p>The key phrases that changed everything:</p>
<ul>
<li>"Transform into poetry, NEVER copy literally"</li>
<li>"Artistic, metaphorical lyrics using imagery and symbolism"</li>
<li>"Universal themes like light/dark, rise/fall, storms/calm"</li>
</ul>
<p>Now instead of "I went to the beach," I get lyrics about "waves carrying yesterday's promises" and "salt-kissed memories fading into golden horizons."</p>
<h2 id="heading-multi-language-support">Multi-language Support</h2>
<p>Additionally, for this to work in Spanish and Portuguese, I had to think about cultural context too. The <code>LANGUAGE_VOCAL_DIRECTION</code> doesn't just specify the language - it adds cultural flavor:</p>
<ul>
<li>English: Clear pronunciation for accessibility</li>
<li>Spanish: Latin influence for rhythm and warmth</li>
<li>Portuguese: Brazilian/Portuguese influence for that saudade feeling</li>
</ul>
<h2 id="heading-what-i-learned">What I Learned</h2>
<p>After building this, here are my key takeaways:</p>
<p><strong>What works well:</strong></p>
<ul>
<li>Emotional mapping creates genuinely different-sounding tracks</li>
<li>The "artistic transformation" instruction dramatically improves lyrics</li>
<li>45-second tracks are the sweet spot for individual moments</li>
<li>Multi-language vocals work surprisingly well</li>
</ul>
<p><strong>What could be better:</strong></p>
<ul>
<li>The model sometimes doesn't follow style instructions closely (especially for niche genres)</li>
<li>Very specific prompts can confuse the model</li>
<li>No control over specific instruments or arrangements</li>
</ul>
<p><strong>Cost breakdown for a typical soundtrack:</strong></p>
<ul>
<li>5 moments × 45 seconds = ~3.75 minutes of audio</li>
<li>~1,875 credits per soundtrack</li>
<li>Plus optional 2-minute "global" track combining all moments</li>
</ul>
<h2 id="heading-try-it-yourself">Try It Yourself</h2>
<p>I hope you found this guide helpful! If you want to try generating your own year soundtrack, check out the live app: <a target="_blank" href="https://soundtrack.codeanding.com/en">soundtrack.codeanding.com/en</a></p>
<p>The ElevenLabs Music API documentation is here: <a target="_blank" href="https://elevenlabs.io/docs/api-reference/music">ElevenLabs Docs</a></p>
<p>I'd love to hear your thoughts - have you experimented with ElevenLabs Music API? What creative uses have you found for AI-generated music?</p>
<p>Let's keep coding and learning together!</p>
<hr />
<p><em>This is part 1 of a 2-part series. In part 2, I'll cover how I used Supabase for authentication, database, and audio file storage.</em></p>
]]></content:encoded></item><item><title><![CDATA[Claude Code: Preguntas y Recursos del Meetup Santiago]]></title><description><![CDATA[¡Hola a todos!
Bienvenidos a esta nueva entrada donde recopilo las preguntas más frecuentes de la comunidad sobre Claude Code. Si alguna vez te has preguntado cómo empezar, cómo optimizar tu flujo de trabajo, o simplemente quieres saber qué diablos e...]]></description><link>https://codeanding.com/claude-code-preguntas-y-recursos-del-meetup-santiago</link><guid isPermaLink="true">https://codeanding.com/claude-code-preguntas-y-recursos-del-meetup-santiago</guid><category><![CDATA[claude-code]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Fri, 19 Dec 2025 03:27:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1766113524645/3b9d858e-f523-43c9-9ac2-c522063a9aaf.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>¡Hola a todos!</p>
<p>Bienvenidos a esta nueva entrada donde recopilo las preguntas más frecuentes de la comunidad sobre Claude Code. Si alguna vez te has preguntado cómo empezar, cómo optimizar tu flujo de trabajo, o simplemente quieres saber qué diablos es MCP… ¡estás en el lugar correcto!</p>
<p>Este post nació como material de apoyo para el meetup de Claude Code en Santiago, pero decidí expandirlo para que sirva como referencia para cualquiera que quiera sacarle el máximo provecho a esta herramienta.</p>
<h2 id="heading-que-encontraras-aqui">¿Qué encontrarás aquí?</h2>
<ul>
<li>Primeros pasos con Claude Code</li>
<li>Workflows y mejores prácticas</li>
<li>Optimización de tokens y contexto</li>
<li>Manejo de proyectos grandes</li>
<li>Integraciones (Figma, MCP, GitHub)</li>
<li>Seguridad y privacidad</li>
<li>Novedades recientes</li>
<li>Cursos gratuitos para seguir aprendiendo</li>
<li>Preguntas para el meetup</li>
</ul>
<p>¡Vamos a ello!</p>
<h2 id="heading-1-primeros-pasos">1. Primeros pasos</h2>
<h3 id="heading-como-empezar-a-usar-claude-code">¿Cómo empezar a usar Claude Code?</h3>
<p>La instalación es desde la terminal. Necesitas Node.js 18+ y una cuenta de Claude (Pro, Max, Team, Enterprise) o créditos en la API.</p>
<pre><code class="lang-bash">npm install -g @anthropic-ai/claude-code
claude
</code></pre>
<p>Al ejecutar <code>claude</code> por primera vez, se abre el proceso de autenticación. Después, navega a cualquier directorio de proyecto y ejecuta <code>claude</code> para empezar.</p>
<p><strong>Recursos:</strong></p>
<ul>
<li><a target="_blank" href="https://code.claude.com/docs/en/quickstart">Quickstart oficial</a></li>
<li><a target="_blank" href="https://code.claude.com/docs/en/setup">Guía de instalación</a></li>
</ul>
<h3 id="heading-y-si-soy-principiante-en-programacion">¿Y si soy principiante en programación?</h3>
<p>Claude Code tiene un modo llamado <strong>Learning</strong> que convierte la experiencia en colaborativa. En lugar de solo generar código, Claude te pide que implementes pequeñas piezas tú mismo, marcándolas con <code>TODO(human)</code>.</p>
<p>Para activarlo: <code>/output-style learning</code></p>
<p>También existe el modo <strong>Explanatory</strong> que agrega "Insights" educativos mientras trabaja, explicando decisiones de implementación y patrones del codebase.</p>
<p><strong>Recursos:</strong></p>
<ul>
<li><a target="_blank" href="https://code.claude.com/docs/en/output-styles">Output styles</a></li>
</ul>
<h2 id="heading-2-workflows-y-mejores-practicas">2. Workflows y mejores prácticas</h2>
<h3 id="heading-como-estructurar-flujos-de-desarrollo-end-to-end">¿Cómo estructurar flujos de desarrollo end-to-end?</h3>
<p>La clave está en usar Claude Code para tareas donde pueda iterar contra un objetivo claro: tests, mocks visuales, o especificaciones.</p>
<p><strong>Flujo sugerido (TDD):</strong></p>
<ol>
<li>Pedir a Claude que escriba tests basados en inputs/outputs esperados</li>
<li>Verificar que los tests fallen</li>
<li>Pedir que implemente el código sin modificar los tests</li>
<li>Iterar hasta que todos los tests pasen</li>
<li>Commit cuando estés satisfecho</li>
</ol>
<p><strong>Para trabajo visual (Figma → Código):</strong></p>
<ol>
<li>Dar a Claude acceso a screenshots (via MCP Puppeteer o manualmente)</li>
<li>Pasar el mock visual (imagen o path)</li>
<li>Pedir que implemente, tome screenshots, e itere hasta que coincida</li>
</ol>
<p><strong>Recursos:</strong></p>
<ul>
<li><a target="_blank" href="https://www.anthropic.com/engineering/claude-code-best-practices">Best practices for agentic coding</a></li>
</ul>
<p><strong>Tips rápidos:</strong></p>
<ul>
<li><strong>Prompt suggestions:</strong> Claude ahora sugiere prompts mientras escribes. Presiona <code>Tab</code> para aceptar o <code>Enter</code> para enviar</li>
<li><strong>Cambiar modelo:</strong> <code>Alt+P</code> (Linux/Windows) u <code>Option+P</code> (macOS) para cambiar de modelo mientras escribes</li>
<li><strong>Thinking mode:</strong> Viene activado por defecto para Opus 4.5. Configúralo en <code>/config</code></li>
</ul>
<h3 id="heading-como-configurar-contexto-por-proyecto">¿Cómo configurar contexto por proyecto?</h3>
<p>Hay dos formas principales de darle contexto persistente a Claude Code:</p>
<p><strong>1. CLAUDE.md</strong> — El archivo de memoria del proyecto. Claude lo lee automáticamente al iniciar sesión. Puedes incluir convenciones de código, estructura del proyecto, comandos comunes e instrucciones de resumen para <code>/compact</code>.</p>
<pre><code class="lang-markdown"><span class="hljs-section"># Proyecto X</span>

<span class="hljs-section">## Stack</span>
<span class="hljs-bullet">-</span> React 18 + TypeScript
<span class="hljs-bullet">-</span> PostgreSQL + Prisma

<span class="hljs-section">## Convenciones</span>
<span class="hljs-bullet">-</span> Usar functional components
<span class="hljs-bullet">-</span> Tests con Vitest
<span class="hljs-bullet">-</span> Commits en español

<span class="hljs-section">## Comandos útiles</span>
<span class="hljs-bullet">-</span> <span class="hljs-code">`npm run dev`</span> - desarrollo
<span class="hljs-bullet">-</span> <span class="hljs-code">`npm run test`</span> - tests
</code></pre>
<p><strong>2. <code>.claude/rules/</code></strong> — Directorio para reglas modulares del proyecto. Útil cuando tienes muchas convenciones y quieres organizarlas en archivos separados (ej: <code>frontend.md</code>, <code>testing.md</code>, <code>api.md</code>). Claude carga todas las reglas automáticamente. Más info en <a target="_blank" href="https://code.claude.com/docs/en/memory">memory docs</a>.</p>
<p>También puedes crear <strong>slash commands</strong> personalizados en <code>.claude/commands/</code>:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"Analiza el performance de este código y sugiere 3 optimizaciones:"</span> &gt; .claude/commands/optimize.md
</code></pre>
<p>Después usas <code>/project:optimize</code> en Claude Code.</p>
<p><strong>Recursos:</strong></p>
<ul>
<li><a target="_blank" href="https://code.claude.com/docs/en/common-workflows">Common workflows</a></li>
<li><a target="_blank" href="https://code.claude.com/docs/en/slash-commands">Slash commands</a></li>
</ul>
<h2 id="heading-3-optimizacion-de-tokens-y-contexto">3. Optimización de tokens y contexto</h2>
<h3 id="heading-como-evitar-perder-contexto-en-sesiones-largas">¿Cómo evitar perder contexto en sesiones largas?</h3>
<p>El problema principal es que cuando el contexto se llena, Claude Code hace un resumen automático (compaction) y puede perder detalles importantes.</p>
<p><strong>Estrategias:</strong></p>
<ol>
<li><p><strong>Usar <code>/compact</code> manualmente</strong> antes de que se llene, con instrucciones específicas:</p>
<pre><code>/compact Enfócate en los cambios de código y resultados de tests
</code></pre></li>
<li><p><strong>Configurar instrucciones de resumen en CLAUDE.md:</strong></p>
<pre><code class="lang-markdown"><span class="hljs-section"># Summary instructions</span>
Cuando uses compact, enfócate en:
<span class="hljs-bullet">-</span> Output de tests
<span class="hljs-bullet">-</span> Cambios de código
<span class="hljs-bullet">-</span> Decisiones de arquitectura
</code></pre>
</li>
<li><p><strong>Dividir tareas complejas</strong> en sesiones más pequeñas y enfocadas</p>
</li>
<li><p><strong>Usar subagents</strong> para tareas específicas (cada uno tiene su propio contexto)</p>
</li>
<li><p><strong>Limpiar entre tareas:</strong> <code>/clear</code> reinicia el contexto</p>
</li>
</ol>
<p><strong>Gestión de sesiones:</strong></p>
<ul>
<li><strong>Named sessions:</strong> Usa <code>/rename</code> para nombrar tus sesiones y <code>/resume &lt;n&gt;</code> desde la terminal (<code>claude --resume &lt;n&gt;</code>) para reanudarlas después</li>
<li><strong><code>/stats</code>:</strong> Muestra estadísticas interesantes de tu uso (modelo favorito, gráfico de uso, streak)</li>
</ul>
<h3 id="heading-cuanto-cuesta-usar-claude-code">¿Cuánto cuesta usar Claude Code?</h3>
<p>Depende del tipo de suscripción:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Plan</td><td>Precio</td><td>Claude Code incluido</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Pro</strong></td><td>$20/mes</td><td>Sí, con límites de uso</td></tr>
<tr>
<td><strong>Max</strong></td><td>$100/mes o $200/mes</td><td>Sí, con más uso incluido</td></tr>
<tr>
<td><strong>Team</strong></td><td>$30/usuario/mes</td><td>Sí, con seats premium</td></tr>
<tr>
<td><strong>API</strong></td><td>Pay-as-you-go</td><td>Pago por tokens consumidos</td></tr>
</tbody>
</table>
</div><p>Para usuarios de <strong>API/Console</strong>, el costo promedio reportado es ~$6/desarrollador/día, pero varía según el modelo usado (Opus es más caro que Sonnet/Haiku) y la intensidad de uso.</p>
<p>Usa <code>/cost</code> para ver estadísticas de uso de la sesión actual (solo aplica para usuarios de API).</p>
<p><strong>Recursos:</strong></p>
<ul>
<li><a target="_blank" href="https://code.claude.com/docs/en/costs">Manage costs</a></li>
</ul>
<h2 id="heading-4-proyectos-grandes-y-codigo-legacy">4. Proyectos grandes y código legacy</h2>
<h3 id="heading-como-maneja-claude-repositorios-con-multiples-servicios">¿Cómo maneja Claude repositorios con múltiples servicios?</h3>
<p>Claude Code usa <strong>agentic search</strong> para entender la estructura del proyecto. No requiere que selecciones archivos manualmente — analiza dependencias y estructura de forma autónoma.</p>
<p>Para proyectos muy grandes, puedes trabajar en paralelo usando <strong>git worktrees</strong>:</p>
<pre><code class="lang-bash">git worktree add ../project-feature-a -b feature-a
<span class="hljs-built_in">cd</span> ../project-feature-a
claude
</code></pre>
<p>Cada worktree tiene su propio estado de archivos aislado, permitiendo múltiples instancias de Claude Code trabajando en paralelo sin interferir.</p>
<p><strong>Background agents:</strong> Claude Code ahora soporta agentes que corren en segundo plano mientras tú sigues trabajando en otras cosas. Ideal para tareas largas como refactoring o generación de tests.</p>
<h3 id="heading-como-hacer-reverse-engineering-y-documentar-sistemas-existentes">¿Cómo hacer reverse engineering y documentar sistemas existentes?</h3>
<ol>
<li>Navega al proyecto y ejecuta <code>claude</code></li>
<li>Pregunta: "Explícame este codebase" o "¿Cuál es la arquitectura de este proyecto?"</li>
<li>Claude analizará archivos y proporcionará un resumen</li>
</ol>
<p>Para documentación continua, el equipo de Security de Anthropic recomienda usar Claude para ingerir múltiples fuentes de documentación, crear runbooks en markdown, y guardar estos documentos condensados como contexto para debugging.</p>
<h3 id="heading-como-busca-claude-en-el-codebase">¿Cómo busca Claude en el codebase?</h3>
<p>Claude Code usa <strong>búsqueda agéntica</strong>, no es puramente semántica ni puramente léxica. Claude decide qué archivos examinar basándose en la tarea, ejecuta búsquedas, y profundiza según necesite.</p>
<p>Internamente usa <code>ripgrep</code> para búsquedas de texto. Si tienes problemas con búsquedas, instala ripgrep en tu sistema:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># macOS</span>
brew install ripgrep

<span class="hljs-comment"># Ubuntu/Debian</span>
sudo apt install ripgrep
</code></pre>
<h2 id="heading-5-integraciones">5. Integraciones</h2>
<h3 id="heading-como-funciona-la-integracion-con-figma">¿Cómo funciona la integración con Figma?</h3>
<p>Hay varias formas:</p>
<ol>
<li><strong>Copiar/pegar imágenes:</strong> Arrastra un screenshot del diseño directamente a Claude Code</li>
<li><strong>Path de archivo:</strong> "Implementa el diseño en /path/to/mock.png"</li>
<li><strong>MCP con Figma:</strong> Conecta el servidor MCP de Figma para acceso directo a tus archivos de diseño</li>
</ol>
<p>El workflow recomendado:</p>
<ol>
<li>Alimentar archivos de Figma a Claude Code</li>
<li>Configurar loops autónomos donde Claude escribe código, corre tests, e itera</li>
<li>Revisar soluciones antes de refinamientos finales</li>
</ol>
<p><strong>Recursos:</strong></p>
<ul>
<li><a target="_blank" href="https://claude.ai/directory">Connectors directory</a></li>
<li><a target="_blank" href="https://www.anthropic.com/news/how-anthropic-teams-use-claude-code">How Anthropic teams use Claude Code</a></li>
</ul>
<h3 id="heading-que-es-mcp-y-como-se-usa">¿Qué es MCP y cómo se usa?</h3>
<p><strong>Model Context Protocol (MCP)</strong> es un estándar abierto para conectar aplicaciones de IA con sistemas externos. Piensa en MCP como un puerto USB-C para aplicaciones de IA.</p>
<p>Con MCP puedes conectar Claude Code a issue trackers (Jira, Linear, GitHub), bases de datos (PostgreSQL), herramientas de diseño (Figma), servicios de comunicación (Slack, Gmail), y cientos más.</p>
<p><strong>Configuración básica:</strong></p>
<pre><code class="lang-bash"><span class="hljs-comment"># Agregar un servidor MCP</span>
claude mcp add --transport http notion https://mcp.notion.com/mcp

<span class="hljs-comment"># Listar servidores configurados</span>
claude mcp list

<span class="hljs-comment"># Ver estado</span>
/mcp
</code></pre>
<p><strong>Recursos:</strong></p>
<ul>
<li><a target="_blank" href="https://code.claude.com/docs/en/mcp">MCP en Claude Code</a></li>
<li><a target="_blank" href="https://modelcontextprotocol.io">MCP Overview</a></li>
</ul>
<h3 id="heading-que-otras-integraciones-hay-disponibles">¿Qué otras integraciones hay disponibles?</h3>
<p><strong>Claude in Chrome (Beta):</strong> Una extensión que te permite controlar tu browser directamente desde Claude Code. Claude puede leer, hacer click y navegar websites junto contigo. Útil para workflows de testing visual y scraping.</p>
<p>Ver más en: <a target="_blank" href="https://claude.ai/chrome">claude.ai/chrome</a></p>
<p><strong>Claude Code in Slack:</strong> Lanzado en diciembre 2025, permite delegar tareas de coding directamente desde threads de Slack. Claude analiza mensajes recientes para determinar el repo correcto, postea actualizaciones de progreso, y comparte links para revisar PRs.</p>
<p>Esto representa un shift importante: los coding assistants están migrando de IDEs hacia herramientas de colaboración donde ya ocurre la comunicación del equipo.</p>
<h2 id="heading-6-seguridad-y-privacidad">6. Seguridad y privacidad</h2>
<h3 id="heading-como-se-protege-la-informacion-privada">¿Cómo se protege la información privada?</h3>
<p><strong>Safeguards de Claude Code:</strong></p>
<ol>
<li><strong>Sistema de permisos:</strong> Por defecto es read-only. Pide permiso antes de modificar archivos o ejecutar comandos</li>
<li><strong>Detección de inyección de comandos:</strong> Comandos bash sospechosos requieren aprobación manual</li>
<li><strong>Verificación de confianza:</strong> Primera ejecución en un codebase y nuevos servidores MCP requieren verificación</li>
<li><strong>Blocklist de comandos:</strong> Bloquea comandos riesgosos como <code>curl</code> y <code>wget</code> por defecto</li>
</ol>
<p><strong>Sandboxing:</strong></p>
<p>Claude Code incluye sandboxing a nivel de OS que proporciona aislamiento de filesystem (solo lectura/escritura en el directorio de trabajo) y aislamiento de red (acceso a internet solo a través de proxy controlado).</p>
<p>Para activar: <code>/sandbox</code></p>
<p><strong>Privacidad de datos:</strong></p>
<ul>
<li>Los datos se encriptan en tránsito y en reposo</li>
<li>Por defecto, empleados de Anthropic no pueden acceder a tus conversaciones</li>
<li>Puedes desactivar el uso de tus datos para entrenamiento en Privacy Settings</li>
<li>Chats en modo Incognito no se usan para mejorar modelos</li>
</ul>
<p><strong>Recursos:</strong></p>
<ul>
<li><a target="_blank" href="https://code.claude.com/docs/en/security">Security</a></li>
<li><a target="_blank" href="https://www.anthropic.com/engineering/claude-code-sandboxing">Claude Code Sandboxing</a></li>
<li><a target="_blank" href="https://privacy.anthropic.com">Privacy Center</a></li>
</ul>
<h3 id="heading-el-codigo-que-genera-claude-sigue-buenas-practicas-de-seguridad">¿El código que genera Claude sigue buenas prácticas de seguridad?</h3>
<p>Claude está entrenado para seguir buenas prácticas, pero como con cualquier herramienta:</p>
<ol>
<li><strong>Siempre revisa el código</strong> antes de ejecutar o hacer commit</li>
<li><strong>Usa el sistema de permisos</strong>, no actives "Accept all" para todo</li>
<li><strong>Considera usar VMs</strong> para scripts que interactúan con servicios externos</li>
<li><strong>En producción</strong>, implementa hooks de validación y testing automatizado</li>
</ol>
<h2 id="heading-7-futuro-de-claude-code">7. Futuro de Claude Code</h2>
<h3 id="heading-que-viene-proximamente">¿Qué viene próximamente?</h3>
<p>Basado en los anuncios recientes:</p>
<ul>
<li><strong>Claude Agent SDK:</strong> El SDK de Claude Code se está expandiendo para construir agentes de propósito general, no solo coding</li>
<li><strong>Mejoras en MCP:</strong> Expansión continua del ecosistema de integraciones</li>
<li><strong>Claude Code Web:</strong> Ya disponible como research preview — ejecución en sandbox aislado en la nube, sin necesidad de CLI local</li>
<li><strong>Tool Search Tool:</strong> Descubrimiento dinámico de herramientas para reducir uso de contexto</li>
</ul>
<h3 id="heading-usaron-claude-code-para-construir-claude-code">¿Usaron Claude Code para construir Claude Code?</h3>
<p>Sí. Anthropic usa Claude Code extensivamente en su desarrollo interno. El equipo de Product Engineering lo describe como su "first stop" para cualquier tarea de programación.</p>
<h2 id="heading-8-claude-vs-competencia">8. Claude vs Competencia</h2>
<h3 id="heading-por-que-elegir-claude-code-sobre-otras-herramientas">¿Por qué elegir Claude Code sobre otras herramientas?</h3>
<p><strong>Diferenciadores clave:</strong></p>
<ol>
<li><strong>Terminal-first:</strong> No es otro IDE ni chat window. Trabaja donde ya trabajas</li>
<li><strong>Agnóstico:</strong> No impone workflows específicos. Flexible, scriptable, componible</li>
<li><strong>Unix philosophy:</strong> Diseñado para ser compuesto con otras herramientas</li>
<li><strong>MCP:</strong> Estándar abierto para integraciones (no lock-in)</li>
<li><strong>Transparencia:</strong> Siempre pide permiso, muestra su razonamiento</li>
</ol>
<p><strong>Modelos disponibles:</strong></p>
<ul>
<li>Opus 4.5 (más inteligente)</li>
<li>Sonnet 4.5 (balance)</li>
<li>Haiku 4.5 (más rápido)</li>
</ul>
<h2 id="heading-9-novedades-agent-skills-18-dic-2025">9. Novedades: Agent Skills (18 dic 2025)</h2>
<h3 id="heading-hay-planes-para-mejorar-el-versionado-de-skills">¿Hay planes para mejorar el versionado de skills?</h3>
<p>¡Justo ayer Anthropic anunció varias mejoras!</p>
<ol>
<li><p><strong>Agent Skills es ahora un estándar abierto</strong> — La especificación está disponible en <a target="_blank" href="https://agentskills.io">agentskills.io</a>, permitiendo portabilidad entre plataformas (incluso fuera de Claude)</p>
</li>
<li><p><strong>Nuevo endpoint <code>/v1/skills</code></strong> — Control programático para versionado y gestión de skills custom. Puedes referenciar "latest" durante desarrollo y fijar versiones específicas para producción</p>
</li>
<li><p><strong>Gestión organizacional</strong> — Administradores de Team y Enterprise pueden gestionar skills desde una ubicación central</p>
</li>
<li><p><strong>Directorio de skills de partners</strong> — Skills preconstruidos de Atlassian (Jira, Trello), Figma, Canva, Stripe, Notion, Zapier y más</p>
</li>
<li><p><strong>Quick-create flow</strong> — Crear skills describiendo lo que quieres en lenguaje natural</p>
</li>
</ol>
<p><strong>Recursos:</strong></p>
<ul>
<li><a target="_blank" href="https://www.anthropic.com/news/skills">Agent Skills Announcement</a></li>
<li><a target="_blank" href="https://agentskills.io">Agent Skills Open Standard</a></li>
</ul>
<h2 id="heading-10-cursos-gratuitos-para-seguir-aprendiendo">10. Cursos gratuitos para seguir aprendiendo</h2>
<p>Si quieres profundizar más en Claude Code, estos cursos gratuitos son un excelente punto de partida:</p>
<h3 id="heading-claude-code-in-action-anthropic-academy">Claude Code in Action (Anthropic Academy)</h3>
<p>El curso oficial de Anthropic. Cubre desde la arquitectura de coding assistants hasta integraciones avanzadas con MCP y GitHub.</p>
<p><strong>Lo que aprenderás:</strong></p>
<ul>
<li>Arquitectura de Claude Code y sistema de herramientas</li>
<li>Gestión de contexto y recursos del proyecto</li>
<li>Custom commands y automatizaciones</li>
<li>Integración con GitHub workflows</li>
<li>Hooks y el SDK de Claude Code</li>
</ul>
<p><strong>Prerrequisitos:</strong> Familiaridad con terminal y Git básico</p>
<p>Ver más en: <a target="_blank" href="https://anthropic.skilljar.com/claude-code-in-action">anthropic.skilljar.com/claude-code-in-action</a></p>
<h3 id="heading-claude-code-software-engineering-with-generative-ai-agents-coursera">Claude Code: Software Engineering with Generative AI Agents (Coursera)</h3>
<p>Curso de Vanderbilt University impartido por Dr. Jules White. Este es más extenso (~5 horas) y va desde cero hasta workflows avanzados con múltiples agentes en paralelo.</p>
<p><strong>Lo que aprenderás:</strong></p>
<ul>
<li>Patrón "Best of N" para generar múltiples versiones de features</li>
<li>CLAUDE.md files para contexto persistente</li>
<li>Git worktrees con múltiples instancias de Claude</li>
<li>Subagents trabajando en paralelo</li>
<li>Prompting multimodal (de boceto a código)</li>
</ul>
<p><strong>Prerrequisitos:</strong> Experiencia básica en desarrollo de software y Git</p>
<p>Ver más en: <a target="_blank" href="https://www.coursera.org/learn/claude-code">coursera.org/learn/claude-code</a></p>
<h3 id="heading-claude-code-a-highly-agentic-coding-assistant-deeplearningai">Claude Code: A Highly Agentic Coding Assistant (DeepLearning.AI)</h3>
<p>Curso corto (~2 horas) de Anthropic en colaboración con DeepLearning.AI. Muy práctico, con tres proyectos hands-on.</p>
<p><strong>Proyectos incluidos:</strong></p>
<ul>
<li>Explorar y desarrollar el codebase de un RAG chatbot</li>
<li>Refactorizar un Jupyter notebook de e-commerce y convertirlo en dashboard</li>
<li>Crear una web app desde un mockup de Figma</li>
</ul>
<p><strong>Lo que aprenderás:</strong></p>
<ul>
<li>CLAUDE.md y gestión de contexto</li>
<li>Testing, debugging y refactoring</li>
<li>Git worktrees para desarrollo paralelo</li>
<li>GitHub integration y hooks</li>
<li>MCP servers (Playwright, Figma)</li>
</ul>
<p><strong>Prerrequisitos:</strong> Familiaridad con Python y Git</p>
<p>Ver más en: <a target="_blank" href="https://www.deeplearning.ai/short-courses/claude-code-a-highly-agentic-coding-assistant/">deeplearning.ai/short-courses/claude-code-a-highly-agentic-coding-assistant</a></p>
<h2 id="heading-11-preguntas-para-el-meetup">11. Preguntas para el Meetup</h2>
<p>Las siguientes preguntas serán respondidas durante el meetup y este post se actualizará con las respuestas:</p>
<ul>
<li>¿Cómo anticipa Anthropic la evolución de agentic systems en mercados con infraestructura fragmentada (LatAm)?</li>
<li>¿Cuál será el impacto en el trabajo de ingenieros a mediano/largo plazo?</li>
<li>¿Habrá programas de internship para latinoamericanos?</li>
<li>¿Cómo se proyecta Claude Code a futuro?</li>
<li>¿Cómo ven el desarrollo de software en 5-10 años?</li>
<li>¿Cuándo habrá más uso de tokens por semana?</li>
</ul>
<h2 id="heading-recursos-adicionales">Recursos adicionales</h2>
<p><strong>Documentación oficial:</strong></p>
<ul>
<li><a target="_blank" href="https://code.claude.com/docs/en/overview">Claude Code Overview</a></li>
<li><a target="_blank" href="https://www.anthropic.com/engineering/claude-code-best-practices">Claude Code Best Practices</a></li>
<li><a target="_blank" href="https://code.claude.com/docs/en/common-workflows">Common Workflows</a></li>
</ul>
<p><strong>Directorio de herramientas:</strong></p>
<ul>
<li><a target="_blank" href="https://claude.ai/directory">claude.ai/directory</a></li>
</ul>
<p><strong>Comunidad:</strong></p>
<ul>
<li><a target="_blank" href="https://discord.com/invite/6PPFFzqPDZ">Discord - Claude Developers</a></li>
<li><a target="_blank" href="https://github.com/anthropics/claude-code">GitHub - Claude Code</a></li>
</ul>
<p><em>Post actualizado: 19 de diciembre del 2025</em></p>
<p><em>¿Tienes más preguntas? Déjalas en los comentarios y las agregaremos al post.</em></p>
]]></content:encoded></item><item><title><![CDATA[From 'Hola' to 'Hello': My React Miami Adventure]]></title><description><![CDATA[Hello everyone!
This month I had a very special experience: I participated as a speaker at React Miami 2025, an event that wasn't just a technical opportunity, but also a moment to step out of my comfort zone. In this post, I want to share how it wen...]]></description><link>https://codeanding.com/from-hola-to-hello-my-react-miami-adventure</link><guid isPermaLink="true">https://codeanding.com/from-hola-to-hello-my-react-miami-adventure</guid><category><![CDATA[react miami]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Fri, 25 Apr 2025 08:46:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1745570752043/ebfc4f45-078a-4b03-b561-6af8980d2bfa.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello everyone!</p>
<p>This month I had a very special experience: I participated as a speaker at <strong>React Miami 2025</strong>, an event that wasn't just a technical opportunity, but also a moment to step out of my comfort zone. In this post, I want to share how it went from application to stage — with nerves, learnings, and moments that I'll treasure for a long time.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745569013968/64dbf4ef-183a-4abe-8b68-282ba5f96aaa.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-it-all-started-with-an-application">It All Started with an Application</h2>
<p>After giving a talk at <a target="_blank" href="https://codeanding.com/aws-community-day-argentina">AWS Community Day Argentina</a>, I saw that the <em>Call for Speakers</em> was opened for an event called React Miami. I wanted to try something different, so I submitted a talk about a stack I had been using recently: <strong>React + Serverless + Terraform</strong>.</p>
<p>At work, I had been building solutions that automate infrastructure with Terraform, and I thought it would be a good opportunity to share how this can help frontend teams focus on <strong>creating amazing experiences for users</strong>, without having to worry about the infrastructure part.</p>
<p>A few months later, I received an email from <a target="_blank" href="https://www.linkedin.com/in/michelle-bakels-2052687a">Michelle Bakels</a>: my talk had been accepted! The mix of nerves and excitement I felt at that moment was incredible.</p>
<h2 id="heading-day-before-the-event-equipment-check-and-first-connections">Day Before the Event: Equipment Check and First Connections</h2>
<p>The event was held at the Hyatt Regency. The day before the event, Wednesday, April 16th, we did the <em>speaker test check</em> — a session to test our equipment, adapters, slides, and make sure everything was ready for the stage. While other speakers were doing their tests, a relaxed atmosphere developed where we could meet and exchange experiences.</p>
<p>That's where I met <a target="_blank" href="https://aileenvl.com/"><strong>Aileen Villanueva</strong></a>, also a speaker. I had written to her before the event after seeing her name on the agenda, and that's when we discovered that we had already coincided at events like Google Community Nation and Google I/O, although we had never spoken. It was really nice to meet in person at React Miami. (Spoiler: Her talk was fantastic!).</p>
<p>These preliminary moments were key to helping me feel more confident. There's something very special about connecting with other people who share the same nervousness and excitement.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745569263536/11008be0-a4b4-4164-9dd8-f82d031d564c.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-a-message-that-marked-the-beginning">A Message That Marked the Beginning</h2>
<p>The first official day of the event, Thursday, April 17th, opened with an important message about something that isn't always mentioned in these types of spaces: <strong>mental health in technology</strong>.</p>
<p>Gabe Greenberg, CEO of G2i, presented <a target="_blank" href="https://www.developerhealth.org/">Developer Health</a>, an initiative focused on emotional well-being for people working in software development. It was refreshing to hear from the start that we are more than just code, and that it's okay to talk about how we feel.</p>
<p>This initiative particularly resonated with me. Seeing an event of this caliber prioritize emotional well-being seemed like an important step for our industry. The organization that Gabe formed with G2i is creating a necessary space where we can talk about code and also about how we feel while writing it. I hope more events incorporate this approach.</p>
<p>Throughout the day, there were many interesting talks on different topics, and I found a lot of value in the presentations. Check out the G2i YouTube channel so you can see them for yourselves.</p>
<h2 id="heading-swag-community-and-many-conversations">Swag, Community, and Many Conversations</h2>
<p>The opening day was also when I got to explore the booths. I learned about new tools, talked with various teams, and of course, <strong>got some nice swag for the community</strong> 😄</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745547074777/84cd0e61-2181-4953-babf-8400785c5a6a.jpeg" alt /></p>
<p>At the speakers and sponsors meetup, I met <a target="_blank" href="https://www.linkedin.com/in/samhitharamaprasad/"><strong>Samhitha Rama Prasad</strong></a>, who mentioned that this was her first time as a speaker. I was really happy to hear that because she did a great job. Kudos to her!</p>
<p>This networking between talks and events was one of the most enriching parts. There's as much learning in informal conversations as there is in official presentations.</p>
<h2 id="heading-the-5k-run-that-inspired-me-anyway">The 5K Run... That Inspired Me Anyway</h2>
<p>On the morning of Friday, April 18th, a 5K run was organized to start the day with energy. I couldn't attend due to insomnia the night before 🙈, but I loved the idea. It would be great to do something like this in the city where I am now, as a way to combine community, technology, and movement. I'm keeping this idea for later.</p>
<h2 id="heading-my-talk">My Talk</h2>
<p>That same Friday the 18th, at 10:05 a.m., I gave my talk: <strong>"React, Serverless, Terraform: The Dream Team for Fullstack Wizards"</strong>. Although I had given other talks before, this was my <strong>first time giving a technical talk in English</strong>, which made the preparation more intense.</p>
<p>Since I didn't want to risk technical problems, I decided to record the demo on video. It was a calm decision that allowed me to focus on the message.</p>
<p>I started out quite nervous, but decided to break the ice with some jokes to connect with the audience. I heard some laughter (or at least that's what it seemed like from the stage!), which helped me relax a bit. As the presentation progressed, I felt it flowing better. With the stage lights, it was difficult to see the audience clearly, but the talk moved forward, and I was able to share everything I had prepared.</p>
<p>When it finished, I felt great relief and satisfaction. Giving a technical talk in another language was quite a challenge, but it was also an enriching experience that helped me grow both professionally and personally. Seeing that I could communicate complex ideas in English and hold the audience's attention confirmed that stepping out of your comfort zone is truly worth it.</p>
<p>If you want to see the presentation and more, they're here:<br />👉 <a target="_blank" href="https://codeanding.com/react-serverless-terraform-the-dream-team-for-fullstack-wizards">codeanding.com/react-serverless-terraform-the-dream-team-for-fullstack-wizards</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745569336214/5cde32a0-afb8-4743-83d9-1009c5391b7a.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-what-i-liked-about-the-content">What I Liked About the Content</h2>
<p>One of the things I enjoyed most was seeing how other speakers approach topics that I use daily. I was particularly struck by:</p>
<ul>
<li><p>The use of <strong>Zustand</strong> to manage state in a clear and simple way, without unnecessary complications. I found it especially interesting because I've seen Zustand implemented in production projects, and confirming its benefits in the presentations gave me ideas to optimize how we're currently using it.</p>
</li>
<li><p>The practical explanations about <strong>React 19</strong> updates, which left me with ideas to apply in my next projects.</p>
</li>
</ul>
<p>If you want to see the talks, they'll be uploaded soon to the G2i channel:<br />📺 <a target="_blank" href="https://www.youtube.com/@g2i_co">youtube.com/@g2i_co</a><br />And the complete schedule is here:<br />🗓 <a target="_blank" href="https://www.reactmiami.com/schedule">reactmiami.com/schedule</a></p>
<h2 id="heading-the-miami-experience">The Miami Experience</h2>
<p>Something I didn't expect was how good I felt in Miami (the weather was very similar to Lima 🇵🇪 in summer). The city has a special vibe, relaxed but energetic at the same time. I loved finding so much Latino community – hearing Spanish in the streets made me feel a little closer to home.</p>
<p>Between event sessions, I was able to walk along the waterfront and see the impressive yachts in the bay. One of my favorite moments was trying a Cuban cafecito at a small local cafe – that shot of sweet, strong coffee was the perfect boost to keep going with energy.</p>
<p>The kindness of the people was notable, from the hotel staff to the event attendees. That warm atmosphere definitely contributed to making the experience even more special.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745569459610/7538b9ae-f814-4394-bf62-83dbf7ed1ec8.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-some-tips-if-youre-thinking-of-applying">Some Tips If You're Thinking of Applying</h2>
<p>If you're considering applying to an international event or one in another language, here's what helped me:</p>
<ul>
<li><p><strong>Do it even if you're afraid.</strong> The worst that can happen is that you don't get selected... and even then, you'll have already learned a lot.</p>
</li>
<li><p><strong>Record your demo if you can.</strong> It gave me peace of mind and allowed me to focus on speaking clearly.</p>
</li>
<li><p><strong>It's okay if you don't sleep perfectly.</strong> Sometimes nerves win, but what's important is to be present when the moment arrives.</p>
</li>
<li><p><strong>Connect with the community.</strong> It's easier than it seems, and you form beautiful connections.</p>
</li>
<li><p><strong>Use humor to break the ice.</strong> A small joke can help you connect with the audience and relax.</p>
</li>
</ul>
<h2 id="heading-whats-next">What's Next?</h2>
<p>Tickets are already available for the 2026 edition:<br />🎟 <a target="_blank" href="https://tickets.joinshowup.io/event/react-miami-2026-oloikn">tickets.joinshowup.io/event/react-miami-2026-oloikn</a></p>
<p>If you have the opportunity to attend or apply, do it! You never know what might happen when you dare to step out of your comfort zone.</p>
<p>For me, this experience has been a turning point. Now I feel ready to continue applying to more international Call for Papers in English. I discovered that language is not as big a barrier as I imagined, and that sharing knowledge in global communities is a tremendously enriching experience.</p>
<p>Thanks for reading this far :)<br /><strong>Let's keep coding and learning together 💻🌴</strong></p>
]]></content:encoded></item><item><title><![CDATA[React, Serverless, Terraform: The Dream Team for Fullstack Wizards]]></title><description><![CDATA[If you're reading this, you might have attended my talk at the conference or found this through the slides. Either way, welcome. This post expands on the key concepts from the presentation and provides practical resources to implement this architectu...]]></description><link>https://codeanding.com/react-serverless-terraform-the-dream-team-for-fullstack-wizards</link><guid isPermaLink="true">https://codeanding.com/react-serverless-terraform-the-dream-team-for-fullstack-wizards</guid><category><![CDATA[serverless]]></category><category><![CDATA[Terraform]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Fri, 18 Apr 2025 14:10:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1744965169201/515dae3b-aefc-4991-a252-fe9e836067b9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you're reading this, you might have attended my talk at the conference or found this through the slides. Either way, welcome. This post expands on the key concepts from the presentation and provides practical resources to implement this architecture yourself.</p>
<p>Modern React applications often start simple, but quickly become complex as user bases grow. The traditional deployment process introduces significant challenges:</p>
<ul>
<li><p>Managing server infrastructure becomes increasingly time-consuming</p>
</li>
<li><p>Scaling becomes difficult and expensive</p>
</li>
<li><p>Configuration drift makes environments inconsistent</p>
</li>
<li><p>Deployment processes become brittle and error-prone</p>
</li>
</ul>
<h2 id="heading-a-fullstack-alternative">A Fullstack Alternative</h2>
<p>The combination of <strong>React</strong>, <strong>Serverless</strong>, and <strong>Terraform</strong> creates a powerful solution to these challenges.</p>
<h3 id="heading-react-frontend-excellence">React: Frontend Excellence</h3>
<p>React continues to dominate frontend development with good reason. Its component-based architecture and robust ecosystem make it ideal for building interactive interfaces. But its greatest strength lies in allowing developers to focus on UI logic without worrying about infrastructure.</p>
<h3 id="heading-serverless-backend-simplicity">Serverless: Backend Simplicity</h3>
<p>Serverless architecture removes the need to provision and manage servers. AWS Lambda functions, API Gateway, DynamoDB, and S3 provide everything needed for a backend that:</p>
<ul>
<li><p>Automatically scales with demand</p>
</li>
<li><p>Reduces operational overhead</p>
</li>
<li><p>Enables usage-based cost efficiency</p>
</li>
<li><p>Supports rapid development through modular services</p>
</li>
</ul>
<h3 id="heading-terraform-infrastructure-automation">Terraform: Infrastructure Automation</h3>
<p>Terraform brings infrastructure into the same development lifecycle as your application code. Here's a quick example:</p>
<pre><code class="lang-typescript">resource <span class="hljs-string">"aws_lambda_function"</span> <span class="hljs-string">"api_function"</span> {
  function_name = <span class="hljs-string">"api_handler"</span>
  runtime       = <span class="hljs-string">"nodejs18.x"</span>
  handler       = <span class="hljs-string">"index.handler"</span>
  role          = aws_iam_role.lambda_role.arn
  s3_bucket     = aws_s3_bucket.lambda_bucket.id
  s3_key        = <span class="hljs-string">"lambda.zip"</span>
}
</code></pre>
<p>This declarative approach ensures that your infrastructure is:</p>
<ul>
<li><p>Version-controlled alongside your code</p>
</li>
<li><p>Consistent across environments</p>
</li>
<li><p>Self-documenting</p>
</li>
<li><p>Reproducible with a single command</p>
</li>
</ul>
<h2 id="heading-slide-deck-from-the-talk">Slide Deck from the Talk</h2>
<p>You can view the full presentation below:</p>
<iframe src="https://docs.google.com/presentation/d/e/2PACX-1vRErdBRRUYFws4hXQ9z9615Opy260VwYM5FLAChqvgfJddJQEMblPEA5w0CUkcUtYgK39BpgDycpU6T/pubembed?start=true&amp;loop=true&amp;delayms=3000" width="760" height="569"></iframe>

<h2 id="heading-implementation-guide">Implementation Guide</h2>
<p>For those who want to implement this architecture, I’ve published the exact example used in the demo from my React Miami talk. It’s a simple card exchange app built with React, connected to a serverless backend — deployed and managed entirely with Terraform.</p>
<p><strong>GitHub Repository</strong>: <a target="_blank" href="https://github.com/codeanding/exchange-tcg.git">https://github.com/codeanding/exchange-tcg.git</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744961564182/89c01e01-ba07-4e15-a370-3a833883ee3a.png" alt class="image--center mx-auto" /></p>
<p>The repository includes:</p>
<ul>
<li><p>A complete React application</p>
</li>
<li><p>Serverless backend functions</p>
</li>
<li><p>Terraform configuration files</p>
</li>
<li><p>Deployment scripts and CI/CD templates</p>
</li>
</ul>
<h2 id="heading-key-benefits-for-development-teams">Key Benefits for Development Teams</h2>
<p>Teams implementing this architecture typically see:</p>
<ul>
<li><p>75% reduction in deployment time</p>
</li>
<li><p>Significant decrease in infrastructure management overhead</p>
</li>
<li><p>Improved consistency between development and production</p>
</li>
<li><p>Faster onboarding for new team members</p>
</li>
</ul>
<h2 id="heading-common-challenges-and-solutions">Common Challenges and Solutions</h2>
<p>While this approach solves many problems, it introduces some new considerations:</p>
<p><strong>Cold Starts</strong>: Lambda functions can experience latency on first execution. This can be mitigated through provisioned concurrency or careful function design.</p>
<p><strong>State Management</strong>: With distributed serverless functions, state management requires different approaches than traditional monoliths.</p>
<p><strong>Local Development</strong>: Testing the full stack locally requires special tooling like AWS SAM or localstack.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>If you found the conference talk helpful, please share your feedback and let me know how you're implementing these patterns in your own work!</p>
<p>Until the next post, let's keep coding and learning together!</p>
]]></content:encoded></item><item><title><![CDATA[Recursos de la presentación: AWSome Women Community Summit]]></title><description><![CDATA[Este fue el proyecto que presenté en el Awesome Women Summit 2025, donde exploramos cómo desplegar un backend en AWS ECS Fargate usando Terraform.
Spoiler: No más clics infinitos en la consola de AWS... ¡Solo código que puedes versionar y reutilizar!...]]></description><link>https://codeanding.com/recursos-de-la-presentacion-awsome-women-community-summit</link><guid isPermaLink="true">https://codeanding.com/recursos-de-la-presentacion-awsome-women-community-summit</guid><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Sat, 29 Mar 2025 19:00:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1745543867570/1a518506-85bf-42d1-92eb-d09c1b3f4200.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Este fue el proyecto que presenté en el <strong>Awesome Women Summit 2025</strong>, donde exploramos cómo desplegar un backend en AWS ECS Fargate usando Terraform.</p>
<p>Spoiler: No más clics infinitos en la consola de AWS... ¡Solo código que puedes versionar y reutilizar!</p>
<h2 id="heading-repositorio-del-proyecto">Repositorio del proyecto</h2>
<p><a target="_blank" href="https://github.com/codeanding/terraform-aws-backend-demo">Ver en GitHub</a></p>
<p>Incluye:</p>
<ul>
<li><p>Infraestructura modular con Terraform</p>
</li>
<li><p>Backend en NestJS + Prisma</p>
</li>
<li><p>Scripts listos para despliegue y destrucción</p>
</li>
<li><p>Buenas prácticas para ECR, ECS, ALB, RDS y más</p>
</li>
</ul>
<h2 id="heading-presentacion-de-la-charla">Presentación de la charla</h2>
<p>Puedes revisar las slides aquí:<br /><a target="_blank" href="https://docs.google.com/presentation/d/1aw_2-8OxrCvydUso37MkIUSW9q5Ui9Nz/edit?usp=sharing&amp;ouid=112888420353347319258&amp;rtpof=true&amp;sd=true">Infraestructura como Código con Terraform - Presentación</a></p>
<h2 id="heading-demo-y-como-usarlo">Demo y cómo usarlo</h2>
<p>En el repo encontrarás todo lo necesario para:</p>
<ul>
<li><p>Desplegar toda la infraestructura con un solo script</p>
</li>
<li><p>Generar un diagrama visual de tu arquitectura</p>
</li>
<li><p>Construir y subir tu imagen Docker a ECR</p>
</li>
<li><p>Probar tu backend con Swagger</p>
</li>
<li><p>¡Y destruir todo cuando terminas sin complicaciones!</p>
</li>
</ul>
<h2 id="heading-recursos-utiles">Recursos útiles</h2>
<ul>
<li><p><a target="_blank" href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs">Terraform AWS Provider</a></p>
</li>
<li><p><a target="_blank" href="https://docs.aws.amazon.com/AmazonECS/latest/userguide/what-is-fargate.html">Guía oficial de ECS Fargate</a></p>
</li>
<li><p><a target="_blank" href="https://docs.nestjs.com/">NestJS</a></p>
</li>
<li><p><a target="_blank" href="https://www.prisma.io/docs/">Prisma</a></p>
</li>
<li><p><a target="_blank" href="https://developer.hashicorp.com/terraform/cli/commands/graph">Graphviz para Terraform</a></p>
</li>
</ul>
<h2 id="heading-gracias">Gracias</h2>
<p>Gracias a quienes estuvieron en la charla y a quienes siguen aprendiendo y compartiendo. ¡Espero que esto te inspire a automatizar tu infraestructura sin miedo!</p>
<p>¡Nos vemos!</p>
]]></content:encoded></item><item><title><![CDATA[Building an Automated Anime News Feed with AWS EventBridge and Slack]]></title><description><![CDATA[Do you like anime? Well, I love it, and like many other topics, there are usually interesting news worth reading with a cup of coffee to start the morning. However, since there are many news items per day, I was thinking that instead of going to look...]]></description><link>https://codeanding.com/building-an-automated-anime-news-feed-with-aws-eventbridge-and-slack</link><guid isPermaLink="true">https://codeanding.com/building-an-automated-anime-news-feed-with-aws-eventbridge-and-slack</guid><category><![CDATA[AWS EventBridge]]></category><category><![CDATA[Anime]]></category><category><![CDATA[slack]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Tue, 18 Feb 2025 06:02:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1739858475491/a8ab432d-16bb-4f92-9ad1-98ae376de9cb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Do you like anime? Well, I love it, and like many other topics, there are usually interesting news worth reading with a cup of coffee to start the morning. However, since there are many news items per day, I was thinking that instead of going to look for them on a trusted blog, I could receive them as a Slack notification daily (although it could also be Discord or others).</p>
<p>Join me to see how I spent some time doing what we like most: automating something we can do daily in 1 minute.</p>
<p>For this we need:</p>
<ul>
<li><p>An Amazon AWS account</p>
</li>
<li><p>A Slack account</p>
</li>
<li><p>A reliable source of anime news (in my case I'll use Crunchyroll)</p>
</li>
</ul>
<h2 id="heading-solution-architecture">Solution Architecture</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739851124642/6b3430d3-cb41-4d62-b9ff-264b3f7136ee.png" alt class="image--center mx-auto" /></p>
<p>Before starting to write code, let me tell you how I thought about this solution. The idea is quite simple: we need something that periodically checks the news and sends it to Slack. But why did I choose these specific AWS services?</p>
<h3 id="heading-the-data-flow">The Data Flow</h3>
<p>Here's how a news item flows through the system:</p>
<ol>
<li><p>EventBridge acts as our alarm clock, triggering every morning at 10 AM</p>
</li>
<li><p>This "alarm clock" triggers our Lambda function</p>
</li>
<li><p>Lambda does the heavy lifting:</p>
<ul>
<li><p>Connects to Crunchyroll's RSS to get the latest news</p>
</li>
<li><p>Processes the information and formats it nicely</p>
</li>
<li><p>Sends everything to Slack through a webhook</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-what-is-aws-lambda">What is AWS Lambda?</h3>
<p>Lambda is like having a small program that sleeps until you need it. The great thing is:</p>
<ul>
<li><p>You only pay when it runs (and the free tier is super generous)</p>
</li>
<li><p>No need to worry about servers or infrastructure</p>
</li>
<li><p>It can handle everything from simple tasks to complex processes</p>
</li>
<li><p>It integrates perfectly with other AWS services</p>
</li>
</ul>
<p>In our case, Lambda is perfect because:</p>
<ul>
<li><p>The task is relatively simple and quick</p>
</li>
<li><p>We don't need a server running 24/7</p>
</li>
<li><p>RSS processing and sending to Slack takes seconds</p>
</li>
</ul>
<h3 id="heading-what-is-aws-sam">What is AWS SAM?</h3>
<p>SAM is like having a personal assistant that handles all the tedious parts of configuring AWS services. Instead of clicking around in the AWS console:</p>
<ul>
<li><p>We write everything in a YAML file</p>
</li>
<li><p>SAM takes care of creating and configuring everything needed</p>
</li>
<li><p>Makes development and deployment much simpler</p>
</li>
<li><p>If something goes wrong, it's easy to destroy everything and start over</p>
</li>
</ul>
<h3 id="heading-what-is-aws-eventbridge-and-why-use-it">What is AWS EventBridge and why use it?</h3>
<p>EventBridge is the service that makes all of this automatic. It's like having a cron job in the cloud, but on steroids:</p>
<ul>
<li><p>Can schedule tasks with second-level precision</p>
</li>
<li><p>Natively integrates with Lambda</p>
</li>
<li><p>Highly reliable (you won't miss news because the server went down)</p>
</li>
<li><p>Allows schedule modifications without touching the code</p>
</li>
</ul>
<p>In our case, we configure it to run every day at 10 AM, but we could easily change it to run every hour or even every 5 minutes if we wanted to stay super updated.</p>
<h3 id="heading-why-this-architecture">Why this architecture?</h3>
<p>You might ask yourself, why not use a simple script on a server? Well, this architecture has several advantages:</p>
<ul>
<li><p>Zero-maintenance: No need to worry about operating system updates or dependencies</p>
</li>
<li><p>Scalable: If we wanted to add more news sources or Slack channels, it's trivial</p>
</li>
<li><p>Cost-efficient: With the free tier, this will probably be free for a good while</p>
</li>
<li><p>Reliable: AWS ensures everything works, you only worry about the code</p>
</li>
</ul>
<h2 id="heading-getting-started">Getting Started</h2>
<h3 id="heading-1-project-structure">1. Project Structure</h3>
<p>Our project will have this structure:</p>
<pre><code class="lang-bash">eventbridge-with-sam/
├── src/
│   ├── helpers/
│   │   ├── slack.helper.ts
│   │   ├── xml.helper.ts
│   ├── services/
│   │   └── news.service.ts
│   ├── tasks/
│   │   └── fetch-news.ts
│   ├── interfaces/
│   │   └── news.ts
├── template.yml
└── package.json
</code></pre>
<h3 id="heading-2-code-implementation">2. Code Implementation</h3>
<p>Let's go step by step, explaining each part of the code and why we structured it this way. First, our Slack helper (<code>slack.helper.ts</code>). This will handle all communication with Slack:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> SlackHelper {
  <span class="hljs-comment">// Sends formatted messages to Slack using webhook</span>
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> sendMessage(message: <span class="hljs-built_in">string</span>) {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> axios.post(process.env.SLACK_WEBHOOK_URL!, { text: message });
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Message sent to Slack:'</span>, message);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error sending message to Slack:'</span>, error);
      <span class="hljs-keyword">throw</span> error;
    }
  }
}
</code></pre>
<p>Now, we need a helper to handle the RSS XML (xml.helper.ts):</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { parseStringPromise } <span class="hljs-keyword">from</span> <span class="hljs-string">'xml2js'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> XMLHelper {
  <span class="hljs-comment">// Parses XML data into a structured format</span>
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> parseXML(xml: <span class="hljs-built_in">string</span>) {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> parseStringPromise(xml);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error parsing XML:'</span>, error);
      <span class="hljs-keyword">throw</span> error;
    }
  }
}
</code></pre>
<p>To keep our code well-typed, we define the interface for our news:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> AnimeNewsItem {
  title: <span class="hljs-built_in">string</span>;
  link: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p>The main service (news.service.ts) is where the magic happens. This is where we fetch the news and process it:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
<span class="hljs-keyword">import</span> { SlackHelper } <span class="hljs-keyword">from</span> <span class="hljs-string">'../helper/slack.helper'</span>;
<span class="hljs-keyword">import</span> { XMLHelper } <span class="hljs-keyword">from</span> <span class="hljs-string">'../helper/xml.helper'</span>;
<span class="hljs-keyword">import</span> { AnimeNewsItem } <span class="hljs-keyword">from</span> <span class="hljs-string">'../interfaces/news'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> NewsService {
  <span class="hljs-comment">// Main function to fetch and process news</span>
  <span class="hljs-keyword">async</span> fetchAndSendNews() {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-comment">// Fetch RSS feed</span>
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(process.env.CRUNCHYROLL_RSS_URL!);
      <span class="hljs-keyword">const</span> xmlData = response.data;

      <span class="hljs-comment">// Parse XML to JSON</span>
      <span class="hljs-keyword">const</span> newsJson = <span class="hljs-keyword">await</span> XMLHelper.parseXML(xmlData);
      <span class="hljs-keyword">const</span> rawItems = newsJson.rss.channel[<span class="hljs-number">0</span>].item;

      <span class="hljs-keyword">if</span> (!rawItems || rawItems.length === <span class="hljs-number">0</span>) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'No news found for today.'</span>);
        <span class="hljs-keyword">return</span>;
      }

      <span class="hljs-comment">// Transform raw items into our NewsItem format</span>
      <span class="hljs-keyword">const</span> items: AnimeNewsItem[] = rawItems.map(<span class="hljs-function">(<span class="hljs-params">news: <span class="hljs-built_in">any</span></span>) =&gt;</span> ({
        title: news.title[<span class="hljs-number">0</span>],
        link: news.link[<span class="hljs-number">0</span>],
      }));

      <span class="hljs-comment">// Format message for Slack</span>
      <span class="hljs-keyword">let</span> message = <span class="hljs-string">`📰 *Latest News Update:*\n\n`</span>;
      items.forEach(<span class="hljs-function">(<span class="hljs-params">news</span>) =&gt;</span> {
        message += <span class="hljs-string">`🔹 *<span class="hljs-subst">${news.title}</span>*\n🔗 <span class="hljs-subst">${news.link}</span>\n\n`</span>;
      });

      <span class="hljs-keyword">await</span> SlackHelper.sendMessage(message);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error in news processing:'</span>, error);
      <span class="hljs-keyword">throw</span> error;
    }
  }
}
</code></pre>
<p>Also, we add our Lambda task (<code>fetch-news.ts</code>) which will be the entry point when EventBridge invokes it:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { EventBridgeEvent } <span class="hljs-keyword">from</span> <span class="hljs-string">'aws-lambda'</span>;
<span class="hljs-keyword">import</span> { NewsService } <span class="hljs-keyword">from</span> <span class="hljs-string">'../services/news.service'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> fetchAndSendNews = <span class="hljs-keyword">async</span> (event: EventBridgeEvent&lt;<span class="hljs-string">'Scheduled Event'</span>, {}&gt;) =&gt; {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'[Scheduled Task] Fetching news...'</span>);
  <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> NewsService().fetchAndSendNews();
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'[Scheduled Task] News sent.'</span>);
};
</code></pre>
<p>Finally, our configuration file (template.yml) that defines all the infrastructure:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">AWSTemplateFormatVersion:</span> <span class="hljs-number">2010-09-09</span>
<span class="hljs-attr">Description:</span> <span class="hljs-string">&gt;-
  news-automation
</span>
<span class="hljs-attr">Transform:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">AWS::Serverless-2016-10-31</span>

<span class="hljs-attr">Globals:</span>
  <span class="hljs-attr">Api:</span>
    <span class="hljs-attr">Cors:</span>
      <span class="hljs-attr">AllowMethods:</span> <span class="hljs-string">"'*'"</span>
      <span class="hljs-attr">AllowHeaders:</span> <span class="hljs-string">"'*'"</span>
      <span class="hljs-attr">AllowOrigin:</span> <span class="hljs-string">"'*'"</span>

  <span class="hljs-attr">Function:</span>
    <span class="hljs-attr">CodeUri:</span> <span class="hljs-string">./dist</span>
    <span class="hljs-attr">Runtime:</span> <span class="hljs-string">nodejs18.x</span>
    <span class="hljs-attr">MemorySize:</span> <span class="hljs-number">128</span>
    <span class="hljs-attr">Timeout:</span> <span class="hljs-number">10</span>
    <span class="hljs-attr">AutoPublishAlias:</span> <span class="hljs-string">Live</span>

    <span class="hljs-attr">Environment:</span>
      <span class="hljs-attr">Variables:</span>
        <span class="hljs-attr">CRUNCHYROLL_RSS_URL:</span> <span class="hljs-type">!Sub</span> <span class="hljs-string">'<span class="hljs-template-variable">{{resolve:ssm:/services/shared/CRUNCHYROLL_RSS_URL}}</span>'</span>
        <span class="hljs-attr">SLACK_WEBHOOK_URL:</span> <span class="hljs-type">!Sub</span> <span class="hljs-string">'<span class="hljs-template-variable">{{resolve:ssm:/services/shared/SLACK_WEBHOOK_URL}}</span>'</span>

<span class="hljs-attr">Resources:</span>
  <span class="hljs-attr">fetchAndSendNews:</span>
    <span class="hljs-attr">Type:</span> <span class="hljs-string">AWS::Serverless::Function</span>
    <span class="hljs-attr">Properties:</span>
      <span class="hljs-attr">Handler:</span> <span class="hljs-string">tasks/fetch-news.fetchAndSendNews</span>
      <span class="hljs-attr">Description:</span> <span class="hljs-string">Fetch</span> <span class="hljs-string">news</span> <span class="hljs-string">from</span> <span class="hljs-string">RSS</span> <span class="hljs-string">feed</span> <span class="hljs-string">and</span> <span class="hljs-string">send</span> <span class="hljs-string">to</span> <span class="hljs-string">Slack</span>
      <span class="hljs-attr">MemorySize:</span> <span class="hljs-number">300</span>
      <span class="hljs-attr">Timeout:</span> <span class="hljs-number">900</span>

      <span class="hljs-attr">Events:</span>
        <span class="hljs-attr">DailyTrigger:</span>
          <span class="hljs-attr">Type:</span> <span class="hljs-string">Schedule</span>
          <span class="hljs-attr">Properties:</span>
            <span class="hljs-attr">Schedule:</span> <span class="hljs-string">cron(0</span> <span class="hljs-number">10</span> <span class="hljs-string">*</span> <span class="hljs-string">*</span> <span class="hljs-string">?</span> <span class="hljs-string">*)</span>
            <span class="hljs-attr">Enabled:</span> <span class="hljs-literal">true</span>
            <span class="hljs-attr">Description:</span> <span class="hljs-string">Runs</span> <span class="hljs-string">every</span> <span class="hljs-string">day</span> <span class="hljs-string">at</span> <span class="hljs-number">10</span><span class="hljs-string">:00</span> <span class="hljs-string">AM</span> <span class="hljs-string">UTC</span>
</code></pre>
<p>The cron expression <code>0 10 * * ? *</code> will run our function every day at 10:00 AM UTC. Here's the breakdown of the expression:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Minute</td><td>Hour</td><td>Day of Month</td><td>Month</td><td>Day of Week</td><td>Year (optional)</td></tr>
</thead>
<tbody>
<tr>
<td>0</td><td>10</td><td>*</td><td>*</td><td>?</td><td>*</td></tr>
</tbody>
</table>
</div><p>Additionally, for the template to work, we need to configure some additional resources. First, we'll create the parameters in AWS Systems Manager Parameter Store (SSM):</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Create parameters in SSM</span>
aws ssm put-parameter \
    --name <span class="hljs-string">"/services/shared/CRUNCHYROLL_RSS_URL"</span> \
    --value <span class="hljs-string">"https://www.crunchyroll.com/newsrss"</span> \
    --<span class="hljs-built_in">type</span> <span class="hljs-string">"String"</span>

aws ssm put-parameter \
    --name <span class="hljs-string">"/services/shared/SLACK_WEBHOOK_URL"</span> \
    --value <span class="hljs-string">"your-slack-webhook-url"</span> \
    --<span class="hljs-built_in">type</span> <span class="hljs-string">"SecureString"</span>
</code></pre>
<p>We also need a <code>samconfig.toml</code> file for deployment configuration:</p>
<pre><code class="lang-toml"><span class="hljs-attr">version</span> = <span class="hljs-number">0.1</span>
<span class="hljs-section">[dev]</span>
<span class="hljs-section">[dev.deploy]</span>
<span class="hljs-section">[dev.deploy.parameters]</span>
<span class="hljs-attr">stack_name</span> = <span class="hljs-string">"eventbridge-with-sam"</span>
<span class="hljs-attr">s3_bucket</span> = <span class="hljs-string">"your-deployment-bucket"</span>
<span class="hljs-attr">s3_prefix</span> = <span class="hljs-string">"eventbridge-with-sam"</span>
<span class="hljs-attr">region</span> = <span class="hljs-string">"us-west-2"</span>
<span class="hljs-attr">confirm_changeset</span> = <span class="hljs-literal">true</span>
<span class="hljs-attr">capabilities</span> = <span class="hljs-string">"CAPABILITY_IAM"</span>
<span class="hljs-attr">parameter_overrides</span> = <span class="hljs-string">"Env=dev"</span>
<span class="hljs-attr">image_repositories</span> = []
</code></pre>
<h3 id="heading-3-slack-configuration">3. Slack Configuration</h3>
<p>Now comes the fun part - we'll configure Slack to receive our news. Whether you're familiar with creating Slack apps or not, here's a step-by-step guide to get you started:</p>
<ol>
<li>First, go to <a target="_blank" href="https://api.slack.com/apps">api.slack.com/apps</a> and click on "Create New App":</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739834171852/c86f606e-41d3-4cb0-9d66-cf56eb5ac05f.png" alt="Create new app" class="image--center mx-auto" /></p>
<ol start="2">
<li>See that green "Create New App" button? Click it and select "From Scratch":</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739834182046/ff7e13be-1d01-4339-aeb9-d4f280cde002.png" alt="Scratch" class="image--center mx-auto" /></p>
<ol start="3">
<li>Now you need to give your app a name - I called mine "AnimeNewsBot" and added it to my "Codeanding" workspace:</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739834225282/1a9ec795-2764-4d6c-8158-cf3118d9b692.png" alt="workspace" class="image--center mx-auto" /></p>
<ol start="4">
<li><p>Once the app is created, go to "Incoming Webhooks" in the side menu and activate the option:</p>
<ul>
<li><p>Click on "Add New Webhook to Workspace"</p>
</li>
<li><p>Select the channel where you want to receive the news</p>
</li>
<li><p>Save the webhook URL that Slack provides, we'll need it later!</p>
</li>
</ul>
</li>
</ol>
<p>Your configured webhook should look something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739834767799/5bc756db-b463-46ce-bd79-9aec2a2ada8b.png" alt="Configured webhook" /></p>
<h3 id="heading-4-deployment">4. Deployment</h3>
<p>Now comes the exciting part. Let's deploy our application step by step:</p>
<ol>
<li>First, make sure you have all dependencies installed:</li>
</ol>
<pre><code class="lang-bash">yarn install
</code></pre>
<ol start="2">
<li>Build the project (this transpiles TypeScript to JavaScript):</li>
</ol>
<pre><code class="lang-bash">yarn build
</code></pre>
<ol start="3">
<li>Deploy the application:</li>
</ol>
<pre><code class="lang-bash">yarn deploy
</code></pre>
<p>During deployment, SAM will:</p>
<ul>
<li><p>Create an S3 bucket if it doesn't exist</p>
</li>
<li><p>Package your code</p>
</li>
<li><p>Create/update resources in AWS</p>
</li>
<li><p>Show you a summary of changes</p>
</li>
</ul>
<p>If everything goes well, you should see something like this in the terminal:</p>
<pre><code class="lang-bash">Successfully created/updated stack - eventbridge-with-sam
</code></pre>
<p>To verify that everything works, wait until the next scheduled time (10:00 AM UTC), and you should see the news appear in your Slack channel:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739845457924/002fa6d7-85c0-421e-a28e-901b10deb8c2.png" alt="News example in Slack" /></p>
<h3 id="heading-5-resource-cleanup">5. Resource Cleanup</h3>
<p>When you want to remove everything created (to avoid charges or just clean up), run these commands:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Delete the CloudFormation stack</span>
sam delete --stack-name eventbridge-with-sam

<span class="hljs-comment"># Delete SSM parameters</span>
aws ssm delete-parameter --name <span class="hljs-string">"/services/shared/CRUNCHYROLL_RSS_URL"</span>
aws ssm delete-parameter --name <span class="hljs-string">"/services/shared/SLACK_WEBHOOK_URL"</span>
</code></pre>
<h2 id="heading-ideas-for-improvement">Ideas for Improvement</h2>
<p>Liked the project? Great! But there's always room for improvement. Some ideas if you want to keep practicing:</p>
<ul>
<li><p><strong>More messaging platforms</strong>: Why stick with just Slack? You could add support for Discord or Telegram. Each platform has its own API and would be an excellent abstraction exercise.</p>
</li>
<li><p><strong>Better messages</strong>: Current messages are functional, but you could make them more attractive. How about adding news preview images or using Slack blocks for a more elaborate format?</p>
</li>
<li><p><strong>Custom filters</strong>: Interested in only certain types of news? You could add filters by keyword or categories. You could even allow each user to configure their own filters.</p>
</li>
<li><p><strong>On-demand commands</strong>: Sometimes you don't want to wait for the daily update. How about adding a <code>/news</code> command to get the latest news whenever you want?</p>
</li>
</ul>
<p>If you implement any of these improvements or come up with another interesting idea, don't hesitate to make a PR to the repo! It would be interesting to see what happens.</p>
<h2 id="heading-source-code">Source Code</h2>
<p>Want to see the complete code, or contribute? Find it on GitHub! <a target="_blank" href="https://github.com/codeanding/eventbridge-with-sam">EventBridge with SAM</a></p>
<h2 id="heading-common-troubleshooting">Common Troubleshooting</h2>
<ol>
<li><p><strong>Error: "Cannot find webhook URL"</strong></p>
<ul>
<li><p>Verify that you've correctly configured the SLACK_WEBHOOK_URL environment variable</p>
</li>
<li><p>Make sure the webhook is active in Slack</p>
</li>
</ul>
</li>
<li><p><strong>Not receiving messages in Slack</strong></p>
<ul>
<li><p>Verify that the webhook has permissions to post in the channel</p>
</li>
<li><p>Check CloudWatch logs for errors</p>
</li>
</ul>
</li>
</ol>
<p>I hope you found this guide helpful! If you have any questions or suggestions, please leave your comments below - I'd love to hear your thoughts and experiences.</p>
<p>Until the next post, let's keep coding and learning together!</p>
]]></content:encoded></item><item><title><![CDATA[How to Use Prisma as a Layer in AWS Lambda with AWS SAM]]></title><description><![CDATA[Hello everyone!
Are you using AWS SAM and haven't tried Prisma yet? After working with Prisma for a while, I can't imagine going back to working without its type safety. If you're interested in adding it to your Lambda functions, I'll show you how to...]]></description><link>https://codeanding.com/how-to-use-prisma-as-a-layer-in-aws-lambda-with-aws-sam</link><guid isPermaLink="true">https://codeanding.com/how-to-use-prisma-as-a-layer-in-aws-lambda-with-aws-sam</guid><category><![CDATA[AWS]]></category><category><![CDATA[aws sam]]></category><category><![CDATA[prisma]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Sat, 01 Feb 2025 05:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738558098707/8643e545-e9bb-46af-95da-1254d6cd89ad.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello everyone!</p>
<p>Are you using AWS SAM and haven't tried Prisma yet? After working with Prisma for a while, I can't imagine going back to working without its type safety. If you're interested in adding it to your Lambda functions, I'll show you how to integrate it using layers - it's simpler than you might think.</p>
<p>To begin, let's look at what we'll learn in this post:</p>
<ul>
<li><p>What is AWS SAM?</p>
</li>
<li><p>What is AWS Lambda?</p>
</li>
<li><p>What is Prisma?</p>
</li>
<li><p>What is a Layer?</p>
</li>
<li><p>Why use Prisma as a layer?</p>
</li>
</ul>
<h2 id="heading-what-is-aws-sam">What is AWS SAM?</h2>
<p>Looking at AWS documentation, we'll find that AWS SAM is a framework for building serverless applications. It supports various programming languages and significantly simplifies the serverless development process.</p>
<h2 id="heading-what-is-aws-lambda">What is AWS Lambda?</h2>
<p>In AWS documentation, it's described as a serverless computing service that runs code in response to various events. It's perfect for APIs, data processing, and task automation.</p>
<h2 id="heading-what-is-prisma">What is Prisma?</h2>
<p>It's an open-source ORM that has 3 fundamental parts:</p>
<ul>
<li><p>Prisma Client (auto-generated for Node.js and TypeScript)</p>
</li>
<li><p>Prisma Migrate (migration system)</p>
</li>
<li><p>Prisma Studio (GUI for viewing and editing data in your database)</p>
</li>
</ul>
<h2 id="heading-what-is-a-layer">What is a Layer?</h2>
<p>Layers are a means by which we can optimize our AWS Lambda functions. It's an excellent strategy for sharing code, libraries, and other resources across lambda functions.</p>
<h2 id="heading-why-use-prisma-as-a-layer">Why use Prisma as a layer?</h2>
<p>Using Prisma as a layer in AWS Lambda offers several key benefits:</p>
<ol>
<li><p>Resource optimization: By sharing the Prisma library across multiple functions, you significantly reduce the size of each individual function.</p>
</li>
<li><p>Consistency: You ensure that all your functions use the same version of Prisma and the same configuration.</p>
</li>
<li><p>Maintainability: Prisma updates can be managed centrally in the layer.</p>
</li>
<li><p>Better performance: Being in a layer, Prisma can be cached between function invocations.</p>
</li>
</ol>
<h2 id="heading-what-do-we-need-to-achieve-this">What do we need to achieve this?</h2>
<p>To reproduce this, we need:</p>
<ul>
<li><p>An AWS account</p>
</li>
<li><p>A basic project for testing</p>
</li>
<li><p>AWS CLI installed and configured</p>
</li>
<li><p>Node.js and npm/yarn installed</p>
</li>
</ul>
<h2 id="heading-lets-get-started">Let's Get Started</h2>
<h3 id="heading-initial-aws-configuration">Initial AWS Configuration</h3>
<p>First, let's create a new profile on our machine (if you already have one, you can skip this step). Using AWS CLI, we'll use the following command, which will ask for your AWS Secret Key, AWS Secret Access Key, Default AWS Region, and output format.</p>
<pre><code class="lang-bash">aws configure --profile codeanding
</code></pre>
<h3 id="heading-project-structure">Project Structure</h3>
<p>Once our AWS profile is configured, the next step will be to start the project with a simple structure:</p>
<pre><code class="lang-bash">prisma-lambda-layer/
├── layers/          <span class="hljs-comment"># where we'll include our new layer</span>
├── scripts/         <span class="hljs-comment"># where we'll include deployment scripts</span>
└── src/            <span class="hljs-comment"># where we'll include handlers to use prisma</span>
    ├── handlers/
    └── services/
</code></pre>
<h3 id="heading-installing-dependencies">Installing Dependencies</h3>
<p>Let's install the necessary dependencies for the project:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Dependencies</td><td>Development Dependencies</td></tr>
</thead>
<tbody>
<tr>
<td>@prisma/client</td><td>@types/aws-lambda</td></tr>
<tr>
<td>aws-lambda</td><td>@types/node</td></tr>
<tr>
<td></td><td>prisma</td></tr>
<tr>
<td></td><td>typescript</td></tr>
</tbody>
</table>
</div><h3 id="heading-prisma-configuration">Prisma Configuration</h3>
<p>When we add Prisma, it will generate a new folder called <code>prisma</code> with a <code>schema.prisma</code> file inside. Here are the changes we'll make:</p>
<pre><code class="lang-bash">generator client {
  provider      = <span class="hljs-string">"prisma-client-js"</span>
  binaryTargets = [<span class="hljs-string">"native"</span>, <span class="hljs-string">"rhel-openssl-1.0.x"</span>, <span class="hljs-string">"linux-arm64-openssl-1.0.x"</span>]
}

datasource db {
  provider = <span class="hljs-string">"postgresql"</span>
  url      = env(<span class="hljs-string">"DATABASE_URL"</span>)
}

model Country {
  id        Int      @id @default(autoincrement())
  name      String   @unique
  dishes    Dish[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model Dish {
  id          Int          @id @default(autoincrement())
  name        String
  description String
  countryId   Int
  country     Country      @relation(fields: [countryId], references: [id])
  ingredients Ingredient[]
  createdAt   DateTime     @default(now())
  updatedAt   DateTime     @updatedAt
}

model Ingredient {
  id        Int      @id @default(autoincrement())
  name      String
  dishes    Dish[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
</code></pre>
<h3 id="heading-services-implementation">Services Implementation</h3>
<p>In our <code>services</code> folder, we'll add a class to expose Prisma:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@prisma/client'</span>;

<span class="hljs-keyword">let</span> prisma: PrismaClient | <span class="hljs-literal">undefined</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPrismaClient</span>(<span class="hljs-params"></span>): <span class="hljs-title">PrismaClient</span> </span>{
    <span class="hljs-keyword">if</span> (!prisma) {
        <span class="hljs-keyword">try</span> {
            prisma = <span class="hljs-keyword">new</span> PrismaClient({
                log: [<span class="hljs-string">'query'</span>, <span class="hljs-string">'error'</span>, <span class="hljs-string">'warn'</span>],
                errorFormat: <span class="hljs-string">'minimal'</span>,
            });
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error initializing Prisma:'</span>, error);
            <span class="hljs-keyword">throw</span> error;
        }
    }
    <span class="hljs-keyword">return</span> prisma;
}
</code></pre>
<p>Next, we'll add a class to handle operations related to the country model:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { getPrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'./prisma'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CountryService {
    <span class="hljs-keyword">async</span> findAll() {
        <span class="hljs-keyword">return</span> getPrismaClient().country.findMany();
    }

    <span class="hljs-keyword">async</span> findById(id: <span class="hljs-built_in">number</span>) {
        <span class="hljs-keyword">return</span> getPrismaClient().country.findUnique({ where: { id } });
    }

    <span class="hljs-keyword">async</span> create(data: { name: <span class="hljs-built_in">string</span> }) {
        <span class="hljs-keyword">return</span> getPrismaClient().country.create({ data });
    }

    <span class="hljs-keyword">async</span> update(id: <span class="hljs-built_in">number</span>, data: { name: <span class="hljs-built_in">string</span> }) {
        <span class="hljs-keyword">return</span> getPrismaClient().country.update({ where: { id }, data });
    }

    <span class="hljs-keyword">async</span> <span class="hljs-keyword">delete</span>(id: <span class="hljs-built_in">number</span>) {
        <span class="hljs-keyword">return</span> getPrismaClient().country.delete({ where: { id } });
    }
}
</code></pre>
<h3 id="heading-handlers-implementation">Handlers Implementation</h3>
<p>In the <code>handlers</code> folder, we'll add the class that exposes the country-related handlers:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { APIGatewayProxyEvent, APIGatewayProxyResult } <span class="hljs-keyword">from</span> <span class="hljs-string">'aws-lambda'</span>;
<span class="hljs-keyword">import</span> {
    badRequest,
    formatHttpResponse,
    internalServerError,
    notFound,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'../helper/response'</span>;
<span class="hljs-keyword">import</span> {
    CreateCountryDTO,
    UpdateCountryDTO,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'../interfaces/country.interface'</span>;
<span class="hljs-keyword">import</span> { CountryService } <span class="hljs-keyword">from</span> <span class="hljs-string">'../services/country'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CountriesHandler {
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> getAllCountries(
        event: APIGatewayProxyEvent
    ): <span class="hljs-built_in">Promise</span>&lt;APIGatewayProxyResult&gt; {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">const</span> service = <span class="hljs-keyword">new</span> CountryService();
            <span class="hljs-keyword">const</span> countries = <span class="hljs-keyword">await</span> service.findAll();
            <span class="hljs-keyword">return</span> formatHttpResponse(<span class="hljs-number">200</span>, countries, event);
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(error);
            <span class="hljs-keyword">return</span> internalServerError(event);
        }
    }

    <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> getCountryById(
        event: APIGatewayProxyEvent
    ): <span class="hljs-built_in">Promise</span>&lt;APIGatewayProxyResult&gt; {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">const</span> service = <span class="hljs-keyword">new</span> CountryService();

            <span class="hljs-keyword">const</span> id = <span class="hljs-built_in">parseInt</span>(event.pathParameters?.id || <span class="hljs-string">''</span>);
            <span class="hljs-keyword">if</span> (<span class="hljs-built_in">isNaN</span>(id)) <span class="hljs-keyword">return</span> badRequest(event, <span class="hljs-string">'Invalid ID'</span>);

            <span class="hljs-keyword">const</span> country = <span class="hljs-keyword">await</span> service.findById(id);
            <span class="hljs-keyword">return</span> country
                ? formatHttpResponse(<span class="hljs-number">200</span>, country, event)
                : notFound(event, <span class="hljs-string">'Country not found'</span>);
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-keyword">return</span> internalServerError(event);
        }
    }

    <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> createCountry(
        event: APIGatewayProxyEvent
    ): <span class="hljs-built_in">Promise</span>&lt;APIGatewayProxyResult&gt; {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">const</span> service = <span class="hljs-keyword">new</span> CountryService();

            <span class="hljs-keyword">const</span> body: CreateCountryDTO = <span class="hljs-built_in">JSON</span>.parse(event.body || <span class="hljs-string">'{}'</span>);
            <span class="hljs-keyword">if</span> (!body.name) <span class="hljs-keyword">return</span> badRequest(event, <span class="hljs-string">'Name is required'</span>);

            <span class="hljs-keyword">const</span> newCountry = <span class="hljs-keyword">await</span> service.create({ name: body.name });
            <span class="hljs-keyword">return</span> formatHttpResponse(<span class="hljs-number">201</span>, newCountry, event);
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-keyword">return</span> internalServerError(event);
        }
    }

    <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> updateCountry(
        event: APIGatewayProxyEvent
    ): <span class="hljs-built_in">Promise</span>&lt;APIGatewayProxyResult&gt; {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">const</span> service = <span class="hljs-keyword">new</span> CountryService();

            <span class="hljs-keyword">const</span> id = <span class="hljs-built_in">parseInt</span>(event.pathParameters?.id || <span class="hljs-string">''</span>);
            <span class="hljs-keyword">const</span> body: UpdateCountryDTO = <span class="hljs-built_in">JSON</span>.parse(event.body || <span class="hljs-string">'{}'</span>);

            <span class="hljs-keyword">if</span> (<span class="hljs-built_in">isNaN</span>(id) || !body.name) <span class="hljs-keyword">return</span> badRequest(event, <span class="hljs-string">'Invalid data'</span>);

            <span class="hljs-keyword">const</span> updatedCountry = <span class="hljs-keyword">await</span> service.update(id, { name: body.name });
            <span class="hljs-keyword">return</span> formatHttpResponse(<span class="hljs-number">200</span>, updatedCountry, event);
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-keyword">return</span> internalServerError(event);
        }
    }

    <span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> deleteCountry(
        event: APIGatewayProxyEvent
    ): <span class="hljs-built_in">Promise</span>&lt;APIGatewayProxyResult&gt; {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">const</span> service = <span class="hljs-keyword">new</span> CountryService();

            <span class="hljs-keyword">const</span> id = <span class="hljs-built_in">parseInt</span>(event.pathParameters?.id || <span class="hljs-string">''</span>);
            <span class="hljs-keyword">if</span> (<span class="hljs-built_in">isNaN</span>(id)) <span class="hljs-keyword">return</span> badRequest(event, <span class="hljs-string">'Invalid ID'</span>);

            <span class="hljs-keyword">await</span> service.delete(id);
            <span class="hljs-keyword">return</span> formatHttpResponse(<span class="hljs-number">204</span>, {}, event);
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-keyword">return</span> internalServerError(event);
        }
    }
}
</code></pre>
<h3 id="heading-deployment-scripts">Deployment Scripts</h3>
<p>In the <code>scripts</code> folder, we'll add the following files to facilitate deployment:</p>
<p><code>prisma-layer.sh</code>:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/sh</span>

<span class="hljs-built_in">set</span> -e
LAYERS_DIR=<span class="hljs-string">"layers"</span>
PRISMA_LAYER=<span class="hljs-string">"<span class="hljs-variable">$LAYERS_DIR</span>/prisma-layer"</span>
NODEJS_PATH=<span class="hljs-string">"<span class="hljs-variable">$PRISMA_LAYER</span>/nodejs"</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"🧹 Cleaning previous layer directory..."</span>
rm -rf <span class="hljs-string">"<span class="hljs-variable">$PRISMA_LAYER</span>"</span>
mkdir -p <span class="hljs-string">"<span class="hljs-variable">$NODEJS_PATH</span>/prisma"</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"📋 Creating specific package.json for layer..."</span>
cat &gt; <span class="hljs-string">"<span class="hljs-variable">$NODEJS_PATH</span>/package.json"</span> &lt;&lt; EOF
{
  <span class="hljs-string">"name"</span>: <span class="hljs-string">"prisma-layer"</span>,
  <span class="hljs-string">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-string">"dependencies"</span>: {
    <span class="hljs-string">"@prisma/client"</span>: <span class="hljs-string">"6.3.0"</span>
  },
  <span class="hljs-string">"devDependencies"</span>: {
    <span class="hljs-string">"prisma"</span>: <span class="hljs-string">"6.3.0"</span>
  }
}
EOF

<span class="hljs-built_in">echo</span> <span class="hljs-string">"📝 Copying schema.prisma to layer..."</span>
cp prisma/schema.prisma <span class="hljs-string">"<span class="hljs-variable">$NODEJS_PATH</span>/prisma/"</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"📦 Installing dependencies in layer..."</span>
<span class="hljs-built_in">cd</span> <span class="hljs-string">"<span class="hljs-variable">$NODEJS_PATH</span>"</span>

<span class="hljs-comment"># install dependencies</span>
yarn install
<span class="hljs-built_in">echo</span> <span class="hljs-string">"⚙️ Generating Prisma client in layer..."</span>
NODE_ENV=development yarn prisma generate

<span class="hljs-built_in">echo</span> <span class="hljs-string">"🧹 Cleaning devDependencies..."</span>
yarn install --production

<span class="hljs-built_in">echo</span> <span class="hljs-string">"📁 Verifying directory structure..."</span>
mkdir -p node_modules/.prisma/client

<span class="hljs-built_in">echo</span> <span class="hljs-string">"🗜️ Creating layer ZIP file..."</span>
<span class="hljs-built_in">cd</span> ..
zip -r <span class="hljs-string">"../prisma-layer.zip"</span> nodejs/

<span class="hljs-built_in">echo</span> <span class="hljs-string">"↩️ Returning to main directory..."</span>
<span class="hljs-built_in">cd</span> ../../

<span class="hljs-built_in">echo</span> <span class="hljs-string">"✅ Prisma layer successfully prepared"</span>
</code></pre>
<p><code>deploy.sh</code>:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/sh</span>

<span class="hljs-built_in">set</span> -e  <span class="hljs-comment"># Stop script if there's an error</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"🧹 Cleaning previous directories..."</span>
rm -rf dist
rm -rf layers/prisma-layer/nodejs/node_modules

<span class="hljs-built_in">echo</span> <span class="hljs-string">"📦 Installing project dependencies..."</span>
yarn install

<span class="hljs-built_in">echo</span> <span class="hljs-string">"🔄 Running prisma generate for main project..."</span>
npx prisma generate

<span class="hljs-built_in">echo</span> <span class="hljs-string">"🔄 Preparing Layers..."</span>
sh $(dirname <span class="hljs-string">"<span class="hljs-variable">$0</span>"</span>)/prisma-layers.sh

<span class="hljs-built_in">echo</span> <span class="hljs-string">"🔨 Compiling TypeScript code..."</span>
yarn build

<span class="hljs-built_in">echo</span> <span class="hljs-string">"📦 Building with AWS SAM..."</span>
sam build --use-container

<span class="hljs-built_in">echo</span> <span class="hljs-string">"🚀 Deploying to AWS..."</span>
sam deploy --profile codeanding \
  --template-file template.yml \
  --s3-bucket codeanding \
  --stack-name sample-api \
  --capabilities CAPABILITY_IAM \
  --no-confirm-changeset

<span class="hljs-built_in">echo</span> <span class="hljs-string">"✅ Deployment successfully completed."</span>
</code></pre>
<h3 id="heading-required-permissions">Required Permissions</h3>
<p>Before proceeding, we need to ensure that the user we're using has the following permissions:</p>
<ul>
<li><p>S3</p>
</li>
<li><p>Secrets Manager</p>
</li>
<li><p>API Gateway</p>
</li>
<li><p>IAM</p>
</li>
<li><p>CloudFormation</p>
</li>
<li><p>Lambda</p>
</li>
</ul>
<p>A quick disclaimer here: the recommendation is to start with basic permissions, following the "least privilege" principle.</p>
<h3 id="heading-testing-the-api">Testing the API</h3>
<p>Now, let's verify that our API works correctly. We'll use Postman to test each of the endpoints.</p>
<p>First, we'll test creating a country using the POST method on the <code>/v1/countries</code> resource:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738549111850/a6f692b6-ce12-40b8-9a36-243767c77e21.png" alt="Creating a country using POST" /></p>
<p>Then, we'll verify that we can retrieve all countries using the GET endpoint:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738549547920/069d634c-3839-464d-b5b7-cbe0ba407b6c.png" alt="Getting all countries" /></p>
<p>Finally, we'll check that we can retrieve a specific country using its ID:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738549718560/bbc9ff8e-ff01-406f-a1ad-eb1f65571da6.png" alt="Getting country by ID" /></p>
<h3 id="heading-next-steps">Next Steps</h3>
<p>For production projects, consider:</p>
<ul>
<li><p>Adding authentication and authorization</p>
</li>
<li><p>Implementing cache to optimize performance</p>
</li>
<li><p>Setting up CI/CD to automate deployments</p>
</li>
</ul>
<p>Remember to evaluate the use case for which you need to use lambdas, considering aspects such as cold start and other performance factors.</p>
<h3 id="heading-resource-cleanup">Resource Cleanup</h3>
<p>If you've been following along with this tutorial, don't forget to clean up your resources to avoid unnecessary charges. You can remove all the resources using:</p>
<pre><code class="lang-bash">sam delete --stack-name sample-api --profile codeanding
</code></pre>
<h3 id="heading-get-involved">Get Involved</h3>
<p>Want to explore the complete code? You can find the entire project in this repository: <a target="_blank" href="https://github.com/codeanding/prisma-lambda-layer">GitHub - AWS Lambda Prisma Layer</a></p>
<p>I hope you found this guide helpful! If you have any questions or suggestions, please leave your comments below - I'd love to hear your thoughts and experiences.</p>
<p>Until the next post, let's keep coding and learning together!</p>
]]></content:encoded></item><item><title><![CDATA[Why can a mentor help your tech career?]]></title><description><![CDATA[Hi everyone!
Have you ever wondered how to accelerate your professional growth in tech? Whether you're starting in technology or already have experience, you've probably heard the word mentor at some point. You might have even received or given mento...]]></description><link>https://codeanding.com/why-can-a-mentor-help-your-tech-career</link><guid isPermaLink="true">https://codeanding.com/why-can-a-mentor-help-your-tech-career</guid><category><![CDATA[mentorship]]></category><category><![CDATA[career path]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Sat, 25 Jan 2025 15:00:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737330505624/21f3b408-f53c-49d1-8c89-24b7d5975949.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hi everyone!</p>
<p>Have you ever wondered how to accelerate your professional growth in tech? Whether you're starting in technology or already have experience, you've probably heard the word <em>mentor</em> at some point. You might have even received or given mentorship. If you'd like to know how to get started (either as a mentor or mentee), this post is for you. We'll cover basic concepts and tips to make the most of mentorship.</p>
<p>In my case, when I started my tech career, I was fortunate to meet people who were key to my personal and professional growth. Although I didn't have formal mentorship initially, interactions with these people served as guidance that added tremendous value, helping me direct my efforts and advance in my career.</p>
<h2 id="heading-what-is-mentorship">What is mentorship?</h2>
<p>Mentorship is a space to learn and get guidance from an expert in a particular field. The main roles are:</p>
<ul>
<li><p><strong>The mentor</strong>: responsible for guiding the session and sharing their experience</p>
</li>
<li><p><strong>The mentee</strong>: who receives and benefits from the mentorship</p>
</li>
</ul>
<p>Common activities include:</p>
<ul>
<li><p>Portfolio and CV review</p>
</li>
<li><p>Interview preparation</p>
</li>
<li><p>Career planning and goal setting</p>
</li>
</ul>
<p>Each mentorship is unique and adapts to the mentee's needs.</p>
<h2 id="heading-whats-the-difference-between-a-mentor-coach-and-sponsor">What's the difference between a mentor, coach, and sponsor?</h2>
<p>Although these roles are often confused, each has a distinct purpose:</p>
<ul>
<li><p><strong>Mentor</strong>: Shares experience and knowledge to guide your professional development</p>
</li>
<li><p><strong>Coach</strong>: Helps you find your own answers through questions and reflection. Doesn't necessarily have direct experience in your field</p>
</li>
<li><p><strong>Sponsor</strong>: Uses their position of influence to advocate for you and create concrete opportunities in spaces where you're not present</p>
</li>
</ul>
<p>For example:</p>
<ul>
<li><p>A mentor might help improve your portfolio</p>
</li>
<li><p>A coach would guide you to identify your strengths</p>
</li>
<li><p>A sponsor could recommend you for a key position</p>
</li>
</ul>
<h2 id="heading-do-all-mentors-follow-the-same-path">Do all mentors follow the same path?</h2>
<p>Not at all! Some people become mentors after leading teams, facing unique challenges, or simply learning directly from experience. What's valuable about these mentors is that they perfectly understand the challenges of learning without formal guidance and can share practical strategies that really work.</p>
<h2 id="heading-why-is-it-a-game-changer">Why is it a game-changer?</h2>
<p>In my experience, mentorship can make a significant difference in your career by helping you:</p>
<ul>
<li><p>Avoid common mistakes others have faced</p>
</li>
<li><p>Focus your time and energy on truly beneficial areas for your goals</p>
</li>
<li><p>Accelerate your professional development with experience-based advice</p>
</li>
</ul>
<h2 id="heading-where-can-i-find-a-mentor">Where can I find a mentor?</h2>
<p>There are several ways to find mentors in technology:</p>
<ol>
<li><p><strong>LinkedIn</strong>: Contact professionals politely and respectfully. Introduce yourself, your goals, and why you think they can help you</p>
</li>
<li><p><strong>Tech communities</strong>: Connect with people passionate about sharing knowledge at meetups, annual events like DevFest, International Women's Day, AWS Community Day, and others</p>
</li>
<li><p><strong>Specialized platforms</strong>: <a target="_blank" href="https://www.adplist.org">ADPList</a> or <a target="_blank" href="https://topmate.io">Topmate</a></p>
</li>
</ol>
<p>If you know others, share them in the comments to help others!</p>
<h2 id="heading-what-are-the-next-steps">What are the next steps?</h2>
<p>Working on your personal plan can help you get more out of mentorship:</p>
<ol>
<li><p><strong>Define your specialization area.</strong> If you're not sure yet, check platforms like <a target="_blank" href="https://roadmap.sh">roadmap.sh</a>, where you'll find different paths with relevant topics. If this doesn't help clarify, don't worry, a nice project is coming to help you discover what someone does in specific roles!</p>
</li>
<li><p><strong>Set clear and measurable objectives.</strong> For example, if you want to get into Data Science, start by learning Python, studying basic algorithms, finding interesting challenge repositories, and participating in Kaggle competitions</p>
</li>
<li><p><strong>Prepare specific questions.</strong> Having clarity about what you want to learn will make sessions more productive</p>
</li>
<li><p><strong>Keep track of your progress.</strong> Use GitHub, note apps, or even a physical notebook to document your progress. Remember, everyone's progress is unique, so go at your own pace and enjoy the process</p>
</li>
</ol>
<h2 id="heading-what-if-i-think-im-ready-to-mentor-others">What if I think I'm ready to mentor others?</h2>
<p>First, congratulations on making this decision! Being a mentor is a great opportunity to give back to the community and continue learning. Some recommendations:</p>
<ul>
<li><p><strong>Review feedback techniques</strong>, such as:</p>
<ul>
<li><p><a target="_blank" href="https://www.radicalcandor.com/">Radical Candor</a>: balance showing you personally care with directly challenging</p>
</li>
<li><p><a target="_blank" href="https://dr-younes-henni.medium.com/how-to-criticise-someone-politely-using-the-hamburger-technique-4f6d817c66a2">Hamburger Technique</a>: start with something positive, then constructive criticism, and end with another positive aspect</p>
</li>
</ul>
</li>
<li><p><strong>Learn to ask the right questions</strong> to guide the mentee and encourage reflection</p>
</li>
<li><p><strong>Ask for feedback regularly</strong> to identify areas for improvement and know your strengths as a mentor</p>
</li>
</ul>
<h2 id="heading-resources">Resources</h2>
<ul>
<li><p><a target="_blank" href="https://hbr.org/2024/01/a-guide-to-mentors-sponsors-and-coaches">Mentors vs Coaches vs Sponsors</a></p>
</li>
<li><p><a target="_blank" href="https://www.radicalcandor.com/">Radical Candor</a></p>
</li>
<li><p><a target="_blank" href="https://dr-younes-henni.medium.com/how-to-criticise-someone-politely-using-the-hamburger-technique-4f6d817c66a2">Hamburger Technique</a></p>
</li>
</ul>
<p>If you have any additional tips, share them in the comments! I'd love to hear about your experiences and learn from them.</p>
<p><strong>Until the next post, let's keep coding and learning together!</strong></p>
]]></content:encoded></item><item><title><![CDATA[Tagging, Optimizing, and Managing Docker Images in Amazon ECR]]></title><description><![CDATA[Hello everyone!
Are images piling up in your ECR repositories? Is storage reaching numbers you're not comfortable with? Don't worry! Let's look at some tips that can help us keep our Docker images under control. This post is aimed at people who are s...]]></description><link>https://codeanding.com/tagging-optimizing-and-managing-docker-images-in-amazon-ecr</link><guid isPermaLink="true">https://codeanding.com/tagging-optimizing-and-managing-docker-images-in-amazon-ecr</guid><category><![CDATA[AWS]]></category><category><![CDATA[AWS ECR]]></category><category><![CDATA[Docker]]></category><category><![CDATA[docker image]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Sat, 18 Jan 2025 05:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736869332682/cbdbf8ed-7701-4e07-81f7-c7b4a6e7c8d6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello everyone!</p>
<p>Are images piling up in your ECR repositories? Is storage reaching numbers you're not comfortable with? Don't worry! Let's look at some tips that can help us keep our Docker images under control. This post is aimed at people who are starting with Docker around image generation and AWS's great service, ECR. If you're already experienced, you probably know much of what you'll read here.</p>
<h2 id="heading-what-is-docker">What is Docker?</h2>
<p>Docker presents itself as a platform designed to help developers build, share, and run containerized applications. Basically, it helps mitigate that famous phrase we've all heard at some point: "It works on my machine" - sounds familiar?</p>
<p><img src="https://external-preview.redd.it/kPQ__at4fKKgnYwxUE1Y50bSW7dMyypwpCgPUmFRg04.jpg?auto=webp&amp;s=f3b7d41ce149fcc8074a02bd90f6d82f59c9544b" alt="It works on my machine... : r/ProgrammerHumor" class="image--center mx-auto" /></p>
<h2 id="heading-what-is-ecr">What is ECR?</h2>
<p>Amazon presents ECR as a secure, scalable, and reliable container image registry service managed by AWS. The best part is that it supports both public and private repositories and supports Docker images, Open Container Initiative, and OCI-compatible artifacts. It's like having your own DockerHub but with AWS's security and scalability!</p>
<h2 id="heading-why-is-this-important">Why is this important?</h2>
<p>When using cloud services, we must be aware of their costs (nobody wants surprises in their bill!). In Amazon ECR's case, <a target="_blank" href="https://aws.amazon.com/ecr/pricing/">the cost</a> is associated with incoming and outgoing image transfers, as well as their size. Therefore, it's important to consider this in the projection and planning of our projects.</p>
<p>And this is where optimization plays a super important role. Let's see how we can do it!</p>
<h2 id="heading-optimization-tips">Optimization Tips</h2>
<ul>
<li><p>Let's use lightweight and specific base images, minimalist versions like alpine or slim to reduce image size. Always making sure they are official images.</p>
</li>
<li><p>Minimize the number of layers whenever possible:</p>
<ul>
<li><p>Combine instructions to reduce the number of layers created:</p>
<pre><code class="lang-bash">  RUN apt-get update &amp;&amp; apt-get install -y \
      curl
</code></pre>
</li>
<li><p>Avoid separating redundant instructions:</p>
<pre><code class="lang-bash">  RUN apt-get update
  RUN apt-get install -y curl
</code></pre>
<p>  Instead of the above, combine them into a single line.</p>
</li>
</ul>
</li>
<li><p>Use <code>.dockerignore</code> to reduce the build context, speeding up builds and excluding unnecessary files:</p>
<pre><code class="lang-bash">  .git
  node_modules
</code></pre>
</li>
<li><p>Don't forget to set the working directory to avoid problems with relative paths:</p>
<pre><code class="lang-bash">  WORKDIR /app
</code></pre>
</li>
<li><p>Use <code>COPY</code> instructions instead of <code>ADD</code>, as it is more predictable and secure. Only use <code>ADD</code> if you need to extract a compressed file or download something from a URL:</p>
<pre><code class="lang-bash">  COPY . .
</code></pre>
</li>
<li><p>Remove unnecessary dependencies. Install and remove packages within the same layer to avoid incorporating them in the final image.</p>
</li>
<li><p>Properly tag the image, using <code>latest</code> for the most recent version along with semantic versioning (<a target="_blank" href="https://semver.org/">Learn more here</a>).</p>
</li>
<li><p>Only expose what's necessary (e.g., expose only the ports you need):</p>
<pre><code class="lang-bash">  EXPOSE 4002
</code></pre>
</li>
<li><p>Use tools like <code>trivy</code>, <code>snyk</code>, and the <code>docker scan</code> command to detect security issues. You can also leverage AWS:</p>
<pre><code class="lang-bash">  aws ecr start-image-scan \
      --repository-name my-ecr-repo \
      --image-id imageDigest=sha256:5a587965e4428d4fe318113e402d25145db6c261eb3a64ec13dbe186367ebf8b
</code></pre>
<p>  The output should look something like:</p>
<pre><code class="lang-json">  {
      <span class="hljs-attr">"registryId"</span>: <span class="hljs-string">"012345678910"</span>,
      <span class="hljs-attr">"repositoryName"</span>: <span class="hljs-string">"my-ecr-repo"</span>,
      <span class="hljs-attr">"imageId"</span>: {
          <span class="hljs-attr">"imageDigest"</span>: <span class="hljs-string">"sha256:5a587965e4428d4fe318113e402d25145db6c261eb3a64ec13dbe186367ebf8b"</span>
      },
      <span class="hljs-attr">"imageScanStatus"</span>: {
          <span class="hljs-attr">"status"</span>: <span class="hljs-string">"IN_PROGRESS"</span>
      }
  }
</code></pre>
<p>  Then check the results with:</p>
<pre><code class="lang-bash">  aws ecr describe-image-scan-findings \
      --repository-name my-ecr-repo \
      --image-id imageDigest=sha256:5a587965e4428d4fe318113e402d25145db6c261eb3a64ec13dbe186367ebf8b
</code></pre>
<p>  This will provide detailed security analysis results, including detected vulnerabilities, severity, and recommendations.</p>
</li>
</ul>
<h3 id="heading-what-to-do-with-the-scan-results">What to do with the scan results?</h3>
<p>The security scan results are pure gold for keeping our images secure. Here's what to do with them:</p>
<ul>
<li><p>Identify critical vulnerabilities and prioritize their solution.</p>
</li>
<li><p>Update your Dockerfile dependencies to secure versions.</p>
</li>
<li><p>Integrate scanning into your CI/CD pipeline to prevent deployments with vulnerabilities.</p>
</li>
</ul>
<h2 id="heading-lets-automate-tagging">Let's Automate Tagging!</h2>
<p>Now, we mentioned tagging, what else can we do? As I always say: why not invest a bit more time in automating something that would take us less than a minute? It's not a very complex script, but by including it in our continuous deployment pipelines, we can tag our images without worries. Automation is your friend!</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/sh</span>

<span class="hljs-comment"># Exit immediately if a command exits with a non-zero status</span>
<span class="hljs-built_in">set</span> -e

<span class="hljs-comment"># Trap errors for better debugging</span>
<span class="hljs-built_in">trap</span> <span class="hljs-string">'echo "Error occurred at line $LINENO. Aborting."; exit 1;'</span> ERR

<span class="hljs-comment"># Ensure required tools are available</span>
<span class="hljs-built_in">command</span> -v jq &gt;/dev/null 2&gt;&amp;1 || { <span class="hljs-built_in">echo</span> <span class="hljs-string">"jq is required but not installed. Aborting."</span> &gt;&amp;2; <span class="hljs-built_in">exit</span> 1; }
<span class="hljs-built_in">command</span> -v aws &gt;/dev/null 2&gt;&amp;1 || { <span class="hljs-built_in">echo</span> <span class="hljs-string">"AWS CLI is required but not installed. Aborting."</span> &gt;&amp;2; <span class="hljs-built_in">exit</span> 1; }
<span class="hljs-built_in">command</span> -v docker &gt;/dev/null 2&gt;&amp;1 || { <span class="hljs-built_in">echo</span> <span class="hljs-string">"Docker is required but not installed. Aborting."</span> &gt;&amp;2; <span class="hljs-built_in">exit</span> 1; }

<span class="hljs-comment"># Read the version property from package.json</span>
VERSION=$(jq -r <span class="hljs-string">'.version'</span> package.json)
[ -z <span class="hljs-string">"<span class="hljs-variable">$VERSION</span>"</span> ] &amp;&amp; { <span class="hljs-built_in">echo</span> <span class="hljs-string">"Version could not be retrieved from package.json. Aborting."</span>; <span class="hljs-built_in">exit</span> 1; }

<span class="hljs-comment"># Define environment variable (change this to match your deployment environment)</span>
ENVIRONMENT=<span class="hljs-string">"staging"</span>

<span class="hljs-comment"># Declare variables for tagging the image</span>
REGION=<span class="hljs-string">"my-region"</span>
ECR_REGISTRY=<span class="hljs-string">"111111111.dkr.ecr.<span class="hljs-variable">$REGION</span>.amazonaws.com"</span>
IMAGE_NAME=<span class="hljs-string">"my-ecr-image"</span>

<span class="hljs-comment"># Log in to Amazon ECR</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Logging in to Amazon ECR..."</span>
aws ecr get-login-password --region <span class="hljs-string">"<span class="hljs-variable">$REGION</span>"</span> | docker login --username AWS --password-stdin <span class="hljs-string">"<span class="hljs-variable">$ECR_REGISTRY</span>"</span>

<span class="hljs-comment"># Build the Docker image</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Building Docker image..."</span>
docker build -t <span class="hljs-string">"<span class="hljs-variable">$IMAGE_NAME</span>"</span> .

<span class="hljs-comment"># Tag and push the Docker image with all tags</span>
<span class="hljs-keyword">for</span> TAG <span class="hljs-keyword">in</span> latest <span class="hljs-string">"<span class="hljs-variable">$ENVIRONMENT</span>"</span> <span class="hljs-string">"<span class="hljs-variable">$VERSION</span>"</span>; <span class="hljs-keyword">do</span>
  FULL_TAG=<span class="hljs-string">"<span class="hljs-variable">$ECR_REGISTRY</span>/<span class="hljs-variable">$IMAGE_NAME</span>:<span class="hljs-variable">$TAG</span>"</span>
  <span class="hljs-built_in">echo</span> <span class="hljs-string">"Tagging image as <span class="hljs-variable">$FULL_TAG</span>"</span>
  docker tag <span class="hljs-string">"<span class="hljs-variable">$IMAGE_NAME</span>"</span> <span class="hljs-string">"<span class="hljs-variable">$FULL_TAG</span>"</span>

  <span class="hljs-built_in">echo</span> <span class="hljs-string">"Pushing image <span class="hljs-variable">$FULL_TAG</span> to ECR..."</span>
  docker push <span class="hljs-string">"<span class="hljs-variable">$FULL_TAG</span>"</span>
<span class="hljs-keyword">done</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Docker image successfully pushed to ECR."</span>
</code></pre>
<h2 id="heading-version-control-and-lifecycle">Version Control and Lifecycle</h2>
<p>Now, let's imagine the following scenario (quite common, by the way):</p>
<p>Given our current git flow, when we incorporate changes to our develop branches, the images will be tagged and uploaded to ECR. And so on... the result? If we don't have adequate policies, our repository will have n versions of our project (versions that have probably gone through breaking changes or maybe not).</p>
<p>But don't worry! Implementing a lifecycle for images in Amazon ECR is easier than it seems. Let's see how to do it with Terraform:</p>
<pre><code class="lang-bash">resource <span class="hljs-string">"aws_ecr_repository"</span> <span class="hljs-string">"api"</span> {
  name = <span class="hljs-string">"<span class="hljs-variable">${var.app_name}</span>"</span>
}

resource <span class="hljs-string">"aws_ecr_lifecycle_policy"</span> <span class="hljs-string">"api_lifecycle_policy"</span> {
  repository = aws_ecr_repository.api.name

  policy = jsonencode({
    rules = [
      {
        rulePriority = 1
        description  = <span class="hljs-string">"Retain only last 5 images"</span>
        selection = {
          tagStatus     = <span class="hljs-string">"tagged"</span>
          countType     = <span class="hljs-string">"imageCountMoreThan"</span>
          countNumber   = 5
        }
        action = {
          <span class="hljs-built_in">type</span> = <span class="hljs-string">"expire"</span>
        }
      }
    ]
  })
}
</code></pre>
<p>Note: While this part only shows how to create a new resource, we can import existing resources using Terraform from version v1.5.0 or using the terraform CLI.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>We've reached the end! Optimizing Docker images in ECR is not just a good practice, it's a necessity to keep our services efficient and costs under control. With the tips we saw today, we can:</p>
<ul>
<li><p>Significantly reduce storage and transfer costs.</p>
</li>
<li><p>Improve the security of our images (super important!).</p>
</li>
<li><p>Automate those repetitive processes that bore us so much.</p>
</li>
<li><p>Maintain a clean and organized repository (your future self will thank you).</p>
</li>
</ul>
<h2 id="heading-additional-resources">Additional Resources</h2>
<p>Want to dive deeper? Here are some super useful resources!</p>
<ul>
<li><p><a target="_blank" href="https://docs.docker.com/">Official Docker Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://docs.docker.com/develop/develop-images/dockerfile_best-practices/">Docker Best Practices Guide</a></p>
</li>
<li><p><a target="_blank" href="https://docs.aws.amazon.com/AmazonECR/latest/userguide/what-is-ecr.html">Amazon ECR User Guide</a></p>
</li>
<li><p><a target="_blank" href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository">Terraform AWS Provider - ECR</a></p>
</li>
<li><p><a target="_blank" href="https://docs.docker.com/engine/scan/">Docker Security Scanning</a></p>
</li>
<li><p><a target="_blank" href="https://semver.org/">Semantic Versioning</a></p>
</li>
</ul>
<p>Have you tried any of these tips before? Do you have any other tricks up your sleeve you'd like to share?</p>
<p>Share it in the comments! I'd love to hear about your experiences and learn from them.</p>
<p><strong>Until the next post, let's keep coding and learning together!</strong></p>
]]></content:encoded></item><item><title><![CDATA[Docker Desktop Alternative: Migrating to OrbStack on macOS]]></title><description><![CDATA[Hello everyone!
Is Docker Desktop being detected as malware on macOS? If this has happened to you, join me in this post where I'll document the migration process to OrbStack, a tool that promises to be lighter and more efficient. This post will be up...]]></description><link>https://codeanding.com/docker-desktop-alternative-migrating-to-orbstack-on-macos</link><guid isPermaLink="true">https://codeanding.com/docker-desktop-alternative-migrating-to-orbstack-on-macos</guid><category><![CDATA[docker desktop]]></category><category><![CDATA[orbstack]]></category><category><![CDATA[codeanding]]></category><category><![CDATA[macOS]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Sat, 11 Jan 2025 21:40:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736631551793/d748357b-38b3-48c5-ae13-942bddf2c75f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello everyone!</p>
<p>Is Docker Desktop being detected as malware on macOS? If this has happened to you, join me in this post where I'll document the migration process to OrbStack, a tool that promises to be lighter and more efficient. This post will be updated with new findings as I continue using it.</p>
<h3 id="heading-how-did-this-start"><strong>How did this start?</strong></h3>
<p>On January 7th, 2025, reports began to emerge about malware detected on macOS (You can read more about it <a target="_blank" href="https://forums.docker.com/t/malware-blocked-com-docker-vmnetd-was-not-opened-because-it-contains-malware/145930">here</a>). Docker Desktop started being reported as malware, affecting various users, including members of my team (M1, M2, and M3 users). Due to recent macOS updates, some didn't experience this issue, but it was eventually documented in the Docker forum.</p>
<p>In search of alternatives, we discovered <strong>OrbStack</strong> and decided to try it.</p>
<h3 id="heading-what-is-orbstack"><strong>What is OrbStack?</strong></h3>
<p>OrbStack isn't just presented as an alternative to Docker Desktop, but as a more versatile solution, allowing you to run Linux in different environments, similar to what WSL offers on Windows.</p>
<h3 id="heading-why-consider-orbstack">Why Consider OrbStack?</h3>
<p>While you can find a detailed comparison in the resources section, the key benefits that made me switch include:</p>
<ul>
<li><p>Significantly lower resource usage (my MacBook's fans finally stopped spinning)</p>
</li>
<li><p>Faster container startup times</p>
</li>
<li><p>Better integration with Apple Silicon</p>
</li>
<li><p>A more modern and responsive interface</p>
</li>
</ul>
<h3 id="heading-what-is-wsl"><strong>What is WSL?</strong></h3>
<p>While it's not the focus of this post, it's worth mentioning. For Windows users, Windows Subsystem for Linux (WSL) is an excellent alternative for using Linux tools within Windows.</p>
<h3 id="heading-installing-orbstack-on-mac"><strong>Installing OrbStack on Mac</strong></h3>
<p>There are two main installation methods:</p>
<ol>
<li><p>Using homebrew</p>
<pre><code class="lang-bash"> brew install orbstack
</code></pre>
</li>
<li><p>Downloading the installer directly from <a target="_blank" href="https://orbstack.dev/download">orbstack.dev/download</a> (make sure to select the correct installer for your processor)</p>
</li>
</ol>
<h3 id="heading-installation-process">Installation Process</h3>
<p>Once installed, you'll follow these steps:</p>
<ol>
<li><p>Welcome screen</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736618730970/bfec4623-119f-4206-b084-3a3d46fb4f05.png" alt class="image--center mx-auto" /></p>
<p> Tool selection: we'll choose Docker (for now), but you can add K8s or Linux later</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736618760529/7f76b6f6-fba8-4a52-9a1d-791375e18393.png" alt class="image--center mx-auto" /></p>
<p> You'll see the following screen</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736618842618/40eef7de-4ee9-4668-b3ba-4d3b2f15bc41.png" alt class="image--center mx-auto" /></p>
<p> To migrate existing Docker Desktop data:</p>
<ul>
<li><p>Go to the File menu</p>
</li>
<li><p>Select "Migrate docker data"</p>
</li>
</ul>
</li>
</ol>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736618956915/1f72db5e-d0ee-42b9-a9bc-399a1b859458.png" alt class="image--center mx-auto" /></p>
<p>    The "Migrate Docker Data" option simplifies the transition, ensuring all your containers, images, and volumes are ready to use in OrbStack without data loss.</p>
<ol start="5">
<li><p>The migration process will take a few minutes depending on the amount of data</p>
</li>
<li><p>Docker Desktop will stop during the process</p>
</li>
<li><p>When everything is finished, we'll see all containers, volumes, and images successfully migrated</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736619749511/e42c293d-500e-4b93-9824-bc76c83277af.png" alt class="image--center mx-auto" /></p>
<ol start="8">
<li>Now, let's run a (test) project to confirm everything is working normally</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736621498968/616c84fd-5254-4be0-b926-0be959e72bce.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-first-impressions"><strong>First Impressions</strong></h3>
<ul>
<li><p>I was able to run projects normally, without needing to change anything.</p>
</li>
<li><p>The interface is intuitive, and the migration process was quite smooth.</p>
</li>
<li><p>Although I've been using it for a short time, I've noticed that memory and CPU consumption is lower compared to Docker Desktop, especially when working with multiple containers.</p>
</li>
<li><p>Integration with existing development tools (VS Code, terminal) works quite well.</p>
</li>
</ul>
<h3 id="heading-technical-considerations"><strong>Technical Considerations</strong></h3>
<ul>
<li><p>OrbStack's architecture differs from Docker Desktop in its virtualization approach, which explains the performance improvement. (See more at <a target="_blank" href="https://docs.orbstack.dev/architecture">https://docs.orbstack.dev/architecture</a>)</p>
</li>
<li><p>It's important to mention that environment variables and network configuration remain consistent after migration.</p>
</li>
<li><p>Volumes and bind mounts work similarly, maintaining compatibility with existing docker-compose files.</p>
</li>
</ul>
<h3 id="heading-useful-resources"><strong>Useful Resources</strong></h3>
<ul>
<li><p><a target="_blank" href="https://docs.orbstack.dev/">Official OrbStack Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://docs.orbstack.dev/compare/docker-desktop">Orbstack vs Docker Desktop</a></p>
</li>
<li><p><a target="_blank" href="https://discord.com/invite/Tfjyd5N5Eq">OrbStack Community on Discord</a></p>
</li>
</ul>
<p>Have you tried OrbStack or are you considering the switch? What do you think about this tool?</p>
<p>Share your experience in the comments, I'd love to learn from your findings!</p>
<p><strong>Until the next post, let's keep coding and learning together!</strong></p>
]]></content:encoded></item><item><title><![CDATA[DevFest Lima 2024: Desplegando APIs Serverless con Terraform en Google Cloud Functions]]></title><description><![CDATA[¡Hola!
Bienvenidos a esta nueva entrada donde compartiré los recursos y detalles de mi charla en el DevFest Lima 2024 sobre "Desplegando APIs Serverless con Terraform en Google Cloud Functions".
Sobre la charla
En esta sesión exploramos la poderosa c...]]></description><link>https://codeanding.com/devfest-lima-2024-desplegando-apis-serverless-con-terraform-en-google-cloud-functions</link><guid isPermaLink="true">https://codeanding.com/devfest-lima-2024-desplegando-apis-serverless-con-terraform-en-google-cloud-functions</guid><category><![CDATA[codeanding]]></category><category><![CDATA[Google]]></category><category><![CDATA[devfest]]></category><category><![CDATA[Terraform]]></category><category><![CDATA[google cloud functions]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Thu, 28 Nov 2024 05:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735885067997/94cb5320-2c63-4a13-a888-b4c43373191b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>¡Hola!</p>
<p>Bienvenidos a esta nueva entrada donde compartiré los recursos y detalles de mi charla en el DevFest Lima 2024 sobre "Desplegando APIs Serverless con Terraform en Google Cloud Functions".</p>
<h2 id="heading-sobre-la-charla">Sobre la charla</h2>
<p>En esta sesión exploramos la poderosa combinación de Terraform y Google Cloud Functions para desplegar APIs de manera serverless. Cubrimos conceptos fundamentales como:</p>
<ul>
<li><p>Introducción a Serverless y sus beneficios</p>
</li>
<li><p>Fundamentos de Terraform para Infrastructure as Code (IaC)</p>
</li>
<li><p>Implementación práctica usando Google Cloud Functions</p>
</li>
<li><p>Demostración en vivo de un despliegue automatizado</p>
</li>
</ul>
<h2 id="heading-recursos">📚 Recursos</h2>
<h3 id="heading-presentacion">Presentación</h3>
<p>La presentación completa está disponible <a target="_blank" href="https://docs.google.com/presentation/d/1Uh6lJER38Hzj7fyqdnHtMCUudW6-J8srBbexBj2_0pU/edit?usp=sharing">aquí</a>. En ella encontrarás:</p>
<ul>
<li><p>Conceptos básicos de serverless</p>
</li>
<li><p>Ventajas y casos de uso ideales</p>
</li>
<li><p>Introducción a Terraform</p>
</li>
<li><p>Workflow básico de implementación</p>
</li>
<li><p>Arquitectura de la solución</p>
</li>
</ul>
<h3 id="heading-codigo-fuente">Código fuente</h3>
<p>Todo el código demostrado durante la sesión está disponible en GitHub: <a target="_blank" href="https://github.com/julissarparco/demo-devfest-2024">https://github.com/julissarparco/demo-devfest-2024</a></p>
<h2 id="heading-proximos-pasos">Próximos pasos</h2>
<p>Si quieres comenzar con Terraform y Google Cloud Functions, te recomiendo:</p>
<ol>
<li><p>Revisar la documentación oficial de ambas tecnologías</p>
</li>
<li><p>Empezar con proyectos pequeños</p>
</li>
<li><p>Practicar los comandos básicos de Terraform mostrados en la demo</p>
</li>
</ol>
<h2 id="heading-preguntas-o-comentarios">¿Preguntas o comentarios?</h2>
<p>No dudes en dejar tus preguntas en los comentarios o contactarme a través de mis redes sociales @codeanding.</p>
<p>¡Gracias por tu interés en el tema y espero que estos recursos te sean útiles en tu viaje de aprendizaje! 🚀</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735885351585/e7c16532-37e2-4255-8a3f-8c0e8134c8fd.jpeg" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[GitHub Pages + Tu Dominio: Guía Rápida y Sencilla]]></title><description><![CDATA[¡Hola a todos!
Bienvenidos a una nueva entrada, donde aprenderemos paso a paso cómo configurar un dominio con un repositorio en Github. Si alguna vez te has preguntado cómo darle un toque más profesional a tu sitio web, ¡estás en el lugar correcto!
¿...]]></description><link>https://codeanding.com/github-pages-tu-dominio-guia-rapida-y-sencilla</link><guid isPermaLink="true">https://codeanding.com/github-pages-tu-dominio-guia-rapida-y-sencilla</guid><category><![CDATA[codeanding]]></category><category><![CDATA[godaddy]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[GitHubPages]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Wed, 23 Oct 2024 05:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735885677855/9c28a1db-0b57-49a9-81f1-56cc66cfeb42.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>¡Hola a todos!</p>
<p>Bienvenidos a una nueva entrada, donde aprenderemos paso a paso cómo configurar un dominio con un repositorio en Github. Si alguna vez te has preguntado cómo darle un toque más profesional a tu sitio web, ¡estás en el lugar correcto!</p>
<p>¿Qué aprenderemos a lo largo de este post?</p>
<ul>
<li><p>Entenderemos los conceptos básicos de: GitHub, GitHub Pages, GoDaddy y DNS.</p>
</li>
<li><p>Manos a la Obra</p>
</li>
</ul>
<p>¿Qué necesitaremos?</p>
<ul>
<li><p>Una cuenta de GitHub</p>
</li>
<li><p>Un dominio, en este caso usaremos GoDaddy</p>
</li>
</ul>
<h2 id="heading-que-es-github"><strong>¿Qué es GitHub?</strong></h2>
<p>Es una plataforma de desarrollo colaborativo basada en la nube que permite a los desarrolladores almacenar, gestionar y compartir código. Funciona como un sistema de control de versiones, facilitando la colaboración en proyectos de software al permitir que múltiples personas trabajen en el mismo código y hagan un seguimiento detallado de los cambios a lo largo del tiempo.</p>
<h2 id="heading-que-es-github-pages"><strong>¿Qué es GitHub Pages?</strong></h2>
<p>Es parte de GitHub y nos permite alojar sitios web estáticos directamente desde un repositorio en GitHub. Podemos usar GitHub Pages para crear sitios personales, de proyectos, o de organizaciones, y se integra fácilmente con Git para automatizar el despliegue de los cambios a tus proyectos. No requiere servidores externos, ya que GitHub se encarga del alojamiento y la entrega de contenido.</p>
<h2 id="heading-que-es-godaddy"><strong>¿Qué es GoDaddy?</strong></h2>
<p>Es una de las empresas más grandes y conocidas en el mundo del registro de dominios y alojamiento web. Imagina que tener un dominio es como tener una dirección en internet para tu casa o negocio. GoDaddy te permite comprar y administrar esa dirección.</p>
<h2 id="heading-que-es-un-dns"><strong>¿Qué es un DNS?</strong></h2>
<p>DNS viene de las siglas en inglés de “Domain Name System”, que significa “Sistema de nombres de dominio”. Es un directorio que traduce los nombres de dominio, como “<a target="_blank" href="http://www.google.com">www.google.com</a>”, en direcciones IP, como “74.125.19.147”.</p>
<p>Habiendo repasado esta información vamos a poner manos a la obra y empezar con la configuración.</p>
<h2 id="heading-manos-a-la-obra"><strong>Manos a la Obra</strong></h2>
<p>Empecemos con el repositorio en GitHub. Si ya tienes uno, ¡genial! Puedes saltar al siguiente paso. Si no, vamos a crearlo:</p>
<h3 id="heading-paso-1-preparando-nuestro-repositorio"><strong>Paso 1: Preparando nuestro repositorio</strong></h3>
<p>Seleccionamos el owner correspondiente, colocamos el nombre que se ajuste a lo que busquemos y la visibilidad.</p>
<ul>
<li><p>Nombre: <strong>Portfolio</strong></p>
</li>
<li><p>Visibilidad: <strong>Público</strong></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735885718057/b613704b-23a4-4935-8fae-fbe59cd87746.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-paso-2-agregando-archivos-base"><strong>Paso 2: Agregando archivos base</strong></h3>
<p>En caso partamos de cero, agregaremos archivos como: index.html (para definir una estructura inicial) y styles.css (para agregar estilos relacionados con la temática). <em>El index.html de este proyecto contiene un mensaje que indica que el sitio está en construcción, ya que iremos iterando sobre este proyecto en siguientes entradas</em> 👾</p>
<p>¡En mi caso agregué un Psyduck porque me encanta Pokémon! 😀 No teman personalizar sus proyectos con cosas que les gusten.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735885750216/802f0586-d2b1-4bb0-95ec-8669e0a90255.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-paso-3-configurando-github-pages"><strong>Paso 3: Configurando GitHub Pages</strong></h3>
<p>Vamos a la pestaña “Settings” o “Configuración” para habilitar Github Pages.</p>
<blockquote>
<p><strong>⚠️ En caso hayas creado el repositorio como privado, antes de continuar no olvides cambiar la visibilidad del repositorio, ya que es necesario para GitHub Pages</strong></p>
</blockquote>
<p>Por ahora usaremos el despliegue clásico de GitHub Pages, (¡dejaremos GitHub Actions para otra aventura! 👀)</p>
<ul>
<li><p>En <strong>Source</strong>, seleccionamos “<strong>Deploy from a branch</strong>” o “<strong>Desplegar desde una rama</strong>“</p>
</li>
<li><p>En <strong>Branch</strong>, seleccionamos la rama que queramos usar, en este caso <strong>main</strong> y en el folder elegimos <strong>root</strong>.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735885797780/96a0f655-5e40-4564-8f8a-da29f5f50bda.png" alt class="image--center mx-auto" /></p>
<p>GitHub generará una URL muy similar a: https://<strong>@nombreUsuario</strong>.github.io/<strong>@nombreRepositorio</strong>, para efectos del ejemplo tenemos: <a target="_blank" href="https://julissarparco.github.io/portfolio/">https://julissarparco.github.io/portfolio/</a></p>
<h3 id="heading-paso-4-configurando-nuestro-dominio"><strong>Paso 4: Configurando nuestro dominio</strong></h3>
<p>Ahora viene la parte emocionante. Vamos a agregar las siguientes IPs en GoDaddy como registros tipo A:</p>
<ul>
<li><p>185.199.108.153</p>
</li>
<li><p>185.199.109.153</p>
</li>
<li><p>185.199.110.153</p>
</li>
<li><p>185.199.111.153</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735885850901/9696256f-2d0e-465a-95c4-27137bbaae8e.png" alt class="image--center mx-auto" /></p>
<p>Luego agregaremos un record del tipo CNAME del nombre www con el valor de <a target="_blank" href="http://nombreUsuario.github.io"><strong>nombreUsuario.github.io</strong></a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735885859750/c32731f9-9fcc-4c28-b244-04e3306ce07d.png" alt class="image--center mx-auto" /></p>
<p>Cuando esté listo, confirmamos los cambios y se verá un mensaje muy parecido a este:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735885898284/482e4144-6f2a-4856-9eba-5314ebfb6ecb.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-paso-5-conectando-todo"><strong>Paso 5: Conectando todo</strong></h3>
<p>Volvamos a nuestro repositorio en GitHub para configurar el <strong>Custom domain</strong> y agregamos nuestro dominio. En el ejemplo tenemos a <a target="_blank" href="http://julissa.dev">julissa.dev</a>, un nuevo dominio para mostrar un portafolio más allá del blog actual <a target="_blank" href="https://instagram.com/codeanding">@codeandi</a><a target="_blank" href="https://instagram.com/codeanding">ng</a>. Hacemos clic en “<strong>Save</strong>” o “<strong>Guardar</strong>“.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735885977012/cc761e2f-33a3-47e3-a9c8-f341640ed8ca.png" alt class="image--center mx-auto" /></p>
<p>Esto agregará el archivo CNAME al repositorio automáticamente. Y deberías ver algo muy parecido a esto:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735886007040/a7b3845e-c322-4f62-8e2b-e4725ab1ac8d.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735886014362/7dac0ff1-362f-4648-a0ca-77adcc83005c.png" alt class="image--center mx-auto" /></p>
<p>Cuando el chequeo del DNS termine, deberías ver el mensaje “<strong>DNS check successful</strong>” o “<strong>Chequeo exitoso de DNS</strong>”.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735886057761/cb57f1fd-c7f1-4592-9642-7e200e745fd8.png" alt class="image--center mx-auto" /></p>
<p>Puedes verificar que todo esté funcionando usando herramientas como <a target="_blank" href="https://www.whatsmydns.net/"><strong>DNS propagation checker</strong></a>.</p>
<p>¡Y listo! 🎉 – deberíamos ver el nuevo dominio apuntando a tu repositorio en GitHub.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735886076992/54a0561e-6aeb-428f-ab63-52aaa74f6234.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-referencias"><strong>Referencias</strong></h3>
<ul>
<li><p><a target="_blank" href="https://docs.github.com/en/get-started/start-your-journey/about-github-and-git">Acerca de Git y GitHub</a></p>
</li>
<li><p><a target="_blank" href="https://www.godaddy.com/es/company/about">Acerca de GoDaddy</a></p>
</li>
<li><p><a target="_blank" href="https://aws.amazon.com/es/route53/what-is-dns/">¿Qué es DNS?</a></p>
</li>
</ul>
<hr />
<p>¿Qué te pareció? ¿Te resultó útil? ¡Cuéntamelo en los comentarios!</p>
<p><strong>Hasta la próxima entrada, ¡sigamos codeando y aprendiendo juntos!</strong></p>
]]></content:encoded></item><item><title><![CDATA[AWS Community Day, Argentina]]></title><description><![CDATA[¡Hola a todos!
Bienvenidos a esta nueva entrada donde compartiré mi experiencia durante el AWS Community Day Argentina edición 2024 en la ciudad de Buenos Aires.
A lo largo de este post, compartiré:

Una breve explicación de qué es AWS Community Day
...]]></description><link>https://codeanding.com/aws-community-day-argentina</link><guid isPermaLink="true">https://codeanding.com/aws-community-day-argentina</guid><category><![CDATA[AWS]]></category><category><![CDATA[AWS Community Day]]></category><category><![CDATA[TechEvents]]></category><category><![CDATA[codeanding]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Thu, 17 Oct 2024 05:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735882940703/4c3ea642-3943-449a-b975-b9e9cde05233.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>¡Hola a todos!</p>
<p>Bienvenidos a esta nueva entrada donde compartiré mi experiencia durante el AWS Community Day Argentina edición 2024 en la ciudad de Buenos Aires.</p>
<p>A lo largo de este post, compartiré:</p>
<ul>
<li><p>Una breve explicación de qué es AWS Community Day</p>
</li>
<li><p>Mi experiencia asistiendo al evento</p>
</li>
<li><p>Mi experiencia como speaker</p>
</li>
<li><p>Reflexiones finales</p>
</li>
</ul>
<p>Así que, ¡prepárate para un viaje lleno de tecnología, aprendizaje y comunidad!</p>
<h3 id="heading-que-es-aws-community-day"><strong>¿Qué es AWS Community Day?</strong></h3>
<p>El AWS Community Day es un evento anual que se organiza en colaboración con distintas comunidades locales de AWS, en la que se discuten temas relacionados con los servicios de AWS. Los eventos son gratuitos y están dirigidos a cualquier persona interesada en aprender sobre AWS.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735882999223/19a262dd-6f22-426c-b133-d1897d68176c.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-como-fue-asistir-al-evento"><strong>¿Cómo fue asistir al evento?</strong></h3>
<p>El evento se llevó a cabo el sábado 14 de septiembre en la <a target="_blank" href="https://www.uade.edu.ar/"><strong>UADE (</strong></a><strong>Universidad Argentina de l</strong><a target="_blank" href="https://www.uade.edu.ar/"><strong>a em</strong></a><strong>presa)</strong> y fue organizado por distintas comunidades de Argentina como: <strong>AWS User Group Patagonía, AWS User Group Buenos Aires</strong>, <strong>AWS User Group Córdoba</strong> y <strong>AWS Girls Argentina</strong>.</p>
<p>Al llegar al evento procedí con el registro para recoger las credenciales y recibir algunos <a target="_blank" href="https://www.uade.edu.ar/">sti</a>ckers de la comunidad (¡sí, aquí amamos el swag!). Al ingresar nos encontramos con desayuno gratis para todos los asistentes (también amamos la comida 👾), así como la exhibición de distintas empresas que brindaban desde swag hasta ofertas laborales. Este espacio fue bastante valioso, no solo para divertirse, sino para conectar con otros entusiastas.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735883104211/8c8ddaaf-71d1-4686-b5ff-74947e1761d4.jpeg" alt class="image--center mx-auto" /></p>
<p>La jornada comenzó con una inspiradora Keynote a cargo de <a target="_blank" href="https://www.linkedin.com/in/jeffbarr/"><strong>Jeff Barr</strong></a>, titulada <strong>“Create Your Own Luck”</strong>. Su presentación fue memorable no solo por el contenido (donde compartió su fascinante trayectoria desde sus inicios hasta su rol actual en AWS), sino por algo que me pareció especialmente significativo: su manera de presentarse. A diferencia del típico “soy [cargo] en [empresa]” que solemos escuchar, Jeff comenzó identificándose con sus roles más personales y duraderos: esposo, padre y abuelo, dejando para el final su título de “<strong>Vice President &amp; Chief Evangelist</strong>”. Este pequeño detalle, aparentemente simple, transmitió un mensaje poderoso sobre la importancia de reconocernos primero como personas antes que como profesionales. Si te interesa experimentar esta inspiradora charla por ti mismo, gracias al excelente trabajo del <strong>equipo organizador</strong>, puedes encontrar la grabación completa <a target="_blank" href="https://www.youtube.com/live/QN4S-YxLgZw?si=9Iv7u0t0pxk-e_vp&amp;t=2377">aquí</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735883204878/7e8d4448-8705-48c7-970b-e3377f142c40.jpeg" alt class="image--center mx-auto" /></p>
<p>Después las charlas en sus respectivos tracks iniciaron: <strong>Main Stage – Track 1, Main Stage – Track 2, DevOps &amp; SRE, Security &amp; Compliance, The Zone</strong> y <strong>Empleabilidad</strong>.</p>
<p>Permanecí en el Main Stage (Track 1 y Track 2) donde <a target="_blank" href="https://www.linkedin.com/in/farrahcampbell/"><strong>Farrah Campbell</strong></a> compartió la charla “<strong>Unlocking Cloud Career Success: Embrace Bravery, Positivity, and Connections</strong>“, una presentación llena de inspiración. Y algunos de los aprendizajes que me gustaría compartir son:</p>
<ul>
<li><p><strong>Superar las dudas sobre uno mismo</strong>: No se trata de pretender que no tenemos miedo, sino de reconocer nuestros miedos y elegir actuar a pesar de ellos. Este enfoque nos permite avanzar y crecer.</p>
</li>
<li><p><strong>Salir de la zona de confort</strong>: Las investigaciones han demostrado que los profesionales que asumen riesgos calculados tienen un 32% más de probabilidades de ser reconocidos y avanzar en sus carreras. Tomar riesgos no solo es necesario, sino que es una oportunidad para ser más visibles y aportar más valor.</p>
</li>
<li><p><strong>Practicar la valentía</strong>: Enfrentar los miedos, practicar la autocompasión, celebrar pequeñas victorias y buscar apoyo son cuatro pilares fundamentales para cultivar la valentía en nuestra vida personal y profesional.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735883339587/09ac399f-42a8-4d3a-af92-e93d81f93c01.jpeg" alt class="image--center mx-auto" /></p>
<ul>
<li><p><strong>Los desafíos como oportunidades</strong>: Cada reto que enfrentamos puede ser una oportunidad de crecimiento. En lugar de ver los obstáculos como barreras, debemos adoptarlos como momentos para aprender y mejorar.</p>
</li>
<li><p><strong>Mentalidad de crecimiento</strong>: Adoptar una mentalidad de crecimiento significa creer que nuestras habilidades se pueden desarrollar con dedicación y esfuerzo. Es fundamental desafiarnos a salir de nuestra zona de confort, persistir ante los obstáculos, aprender de la retroalimentación y encontrar inspiración en los demás.</p>
</li>
<li><p><strong>El poder de las conexiones</strong>: El <strong>85%</strong> de los trabajos se consiguen a través de networking. Farrah subrayó la importancia de construir una red de confianza, rodeándonos de personas que nos apoyen y eleven.</p>
</li>
<li><p><strong>Puntos clave para llevarnos</strong>: Tomar riesgos, creer en nuestras habilidades, responder a los obstáculos con resiliencia, enfocarnos en ser resistentes y construir una red de confianza son acciones fundamentales que nos ayudarán a avanzar tanto en lo personal como en lo profesional.</p>
</li>
</ul>
<p>Finalmente, si quieres revivir la charla, puedes verla <a target="_blank" href="https://www.youtube.com/live/QN4S-YxLgZw?si=b5I-4ige7cR8Goa6&amp;t=7121">aquí</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735883373555/a38545dd-3719-4fbd-b901-3adf607f2c04.jpeg" alt class="image--center mx-auto" /></p>
<p>Las horas transcurrieron y a la hora del almuerzo pude aprovechar en encontrarme con <a target="_blank" href="https://www.linkedin.com/in/vani-moreno-compagnucci-04549720/">Vani Moreno, también e</a>mbajadora del programa <a target="_blank" href="https://developers.google.com/womentechmakers">Women Techmakers</a> <a target="_blank" href="https://developers.google.com/womentechmakers">de Google con q</a>uien pude compartir un momento bastante agradable. Contamos historias, actividades en las que estamos y como siempre, aprovechando la oportunidad para realizar sinergias en futuros proyectos. Vani fue demasiado amable y linda, ¡no solo por darme recomendaciones sobre la ciudad de Buenos Aires, sino por acompañarme durante la charla y darme ánimos!</p>
<h3 id="heading-el-momento-de-subir-al-escenario"><strong>El momento de subir al escenario</strong></h3>
<p>Esta fue la primera charla presencial que daba fuera de Perú, anteriormente lo había hecho de forma virtual a través de LATAM y en algunas ciudades fuera de Lima de forma presencial. Sin embargo, debo decir que fue fantástica. ¡Principalmente por el apoyo de personas como <strong>Vani</strong> y personas de la comunidad de <strong>AWS Argentina</strong>, que me guiaron en el setup de micrófonos, transmisión vía streamyard para grabar la charla y recomendaciones, ya que, estuve en el <strong>main stage</strong> y el escenario fue compartido!</p>
<p>Sí, era la primera vez que participaba en un escenario compartido y aunque al iniciar fue un tanto complicado porque me costó concentrarme con la voz del speaker de al lado 🤭, a medida que fuimos avanzando la comodidad nos encontró y pudimos fluir.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735883436091/306299f5-31fa-4087-80be-671103f9d512.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735883443473/df0ca3cf-e29b-49df-88b9-5b6b95256fbe.jpeg" alt class="image--center mx-auto" /></p>
<p>Los recursos de la charla los dejo en <a target="_blank" href="https://codeanding.com/recursos-de-la-presentacion-la-ia-a-tu-servicio-en-la-salud-con-aws-healthscribe/">este post</a> que creé previamente para hacer más sencillo el compartir referencias y papers que pueden resultar interesantes para quien quiere profundizar.</p>
<h3 id="heading-reflexiones-finales"><strong>Reflexiones finales</strong></h3>
<p>Ser parte del AWS Community Day Argentina 2024 ha sido una aventura que comenzó mucho antes del evento en sí. Todo empezó con ese momento de “<strong>¿y si…?</strong>“, cuando vi la convocatoria para speakers. Postular una charla para un evento internacional parecía intimidante, pero decidí atreverme – <strong>¡y debo decir que lo valió 100%!</strong></p>
<p>Esta experiencia me enseñó que las mejores oportunidades suelen estar del otro lado de nuestra <strong>zona de confort.</strong> No solo me lancé a dar una charla internacional, sino que me animé a explorar una nueva ciudad, conocer personas increíbles y sumergirme en una comunidad tech vibrante y acogedora.</p>
<p>Y hablando de comunidad… <strong>¡Wow!</strong> Ver la sinergia entre todos los user groups de Argentina fue simplemente inspirador. La manera en que estos grupos se unieron para crear un evento de tal magnitud demuestra el verdadero poder de la colaboración. Cada detalle estaba cuidadosamente pensado: desde el registro hasta las sesiones técnicas, desde el networking hasta el swag – ¡todo fluía y esto es algo que solo se logra cuando hay pasión + dedicación detrás!</p>
<p>Me llevo de esta experiencia varios aprendizajes clave:</p>
<ul>
<li><p>El poder de decir “sí” a nuevas oportunidades, aunque den un poquito de miedo.</p>
</li>
<li><p>La magia que sucede cuando diferentes comunidades unen fuerzas.</p>
</li>
<li><p>La importancia de rodearnos de personas que nos impulsan a crecer.</p>
</li>
<li><p>Que los mejores eventos tech no solo son sobre tecnología, sino sobre las conexiones humanas que creamos</p>
</li>
</ul>
<p>Esta experiencia me ha dejado no solo con nuevos conocimientos técnicos, sino también con amistades valiosas, momentos memorables y una renovada motivación para seguir contribuyendo a la comunidad tech. Como dice el dicho, <strong>“si quieres ir rápido, ve solo; si quieres llegar lejos, ve acompañado”</strong> – y después de este AWS Community Day, puedo dar fe de que el camino en comunidad es mucho más enriquecedor.</p>
<p>¡Gracias AWS Community Day Argentina por una experiencia inolvidable! Y a todos los que están leyendo esto: no duden en participar en eventos de comunidad, ya sea como asistentes o speakers. A veces, todo lo que necesitamos es dar ese primer paso valiente, y las oportunidades empiezan a fluir.</p>
<p>¡Gracias al equipo, se tienen muchas de las charlas grabadas! Por lo que te invito a visitar la lista de reproducción en <a target="_blank" href="https://youtube.com/playlist?list=PLQ1M3apmTbgPl1aCViRNuEzoMU8bxMYnq&amp;si=TuaDA4z_R1tlZ9Ac">youtube</a>.</p>
<p><strong>Hasta la próxima entrada, ¡sigamos codeando y aprendiendo juntos!</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735883521459/55793c75-0c15-483b-a9c1-4dbac0135b40.jpeg" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Reflexiones de Google I/O: Transformando Experiencias en Historias para Compartir]]></title><description><![CDATA[¡Hola a todos!
Bienvenidos a esta nueva entrada donde compartiré mi experiencia personal como asistente al Google I/O 2024 y mi participación como speaker en el Google I/O Extended organizado por la comunidad Google Developer Groups (GDG) Cloud Lima ...]]></description><link>https://codeanding.com/reflexiones-de-google-io-transformando-experiencias-en-historias-para-compartir</link><guid isPermaLink="true">https://codeanding.com/reflexiones-de-google-io-transformando-experiencias-en-historias-para-compartir</guid><category><![CDATA[codeanding]]></category><category><![CDATA[Blogging]]></category><category><![CDATA[google io]]></category><category><![CDATA[technology]]></category><category><![CDATA[TechEvents]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Thu, 03 Oct 2024 05:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735879851161/eaa21c87-4a7a-4ffa-a1a0-7a58ea1aa8a1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>¡Hola a todos!</p>
<p>Bienvenidos a esta nueva entrada donde compartiré mi experiencia personal como asistente al <strong>Google I/O 2024</strong> y mi participación como speaker en el Google I/O Extended organizado por la comunidad <a target="_blank" href="https://www.instagram.com/gdgcloudlima"><strong>Google Developer Groups (GDG) Cloud Lima</strong></a> en julio. Aunque el evento principal se llevó a cabo en mayo, no quería dejar pasar la oportunidad de compartir con ustedes cómo fue vivirlo en primera persona.</p>
<p>A lo largo de este post, compartiré:</p>
<ul>
<li><p>Una breve explicación de qué es Google I/O</p>
</li>
<li><p>Mi experiencia personal asistiendo al evento, incluyendo detalles de las actividades previas y durante el evento</p>
</li>
<li><p>Un resumen de los anuncios más destacados del Google I/O 2024</p>
</li>
<li><p>Mi experiencia como speaker en el Google I/O Extended en Lima</p>
</li>
<li><p>Reflexiones sobre la importancia de participar en comunidades tech locales</p>
</li>
</ul>
<p>Así que, ¡prepárate para un viaje lleno de tecnología, aprendizaje y comunidad!</p>
<h3 id="heading-que-es-el-google-io"><strong>¿Qué es el Google I/O?</strong></h3>
<p>Para quienes no estén familiarizados, Google I/O es la conferencia anual que organiza Google para presentar los últimos anuncios y actualizaciones en tecnología, tanto para desarrolladores como para entusiastas del ecosistema Google. Es como la Navidad para los amantes de la tecnología, ¡pero en mayo!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735880678098/5af599eb-7405-452c-a3f2-7c45150b830c.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-mi-experiencia-en-google-io-2024"><strong>Mi experiencia en Google I/O 2024</strong></h3>
<p>Este año, la conferencia tuvo lugar en el Shoreline Amphitheatre en Mountain View, California, durante los días 14 y 15 de mayo. ¡Y déjenme decirles, fue una experiencia increíblemente inspiradora!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735880703823/cea6cc6d-4ce8-4b18-8d9b-98fb032a0e63.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-actividades-previas-y-registro">Actividades previas y registro</h3>
<p>El evento oficialmente comenzó el 14 de mayo, pero las actividades arrancaron desde el día anterior. El lunes 13 de mayo, se organizaron dos cenas en paralelo: una para el programa Women Techmakers y otra para los Google Developer Experts. Como embajadora de Women Techmakers, estaba invitada a la cena, pero lamentablemente no pude asistir porque aún estaba en vuelo hacia California.</p>
<p>El día 14 por la mañana, comenzamos con el proceso de registro. Fue emocionante ir a buscar nuestras credenciales para ingresar al evento. Y por supuesto, ¡no podía faltar el swag tech! Recibimos algunos obsequios geniales que hicieron la experiencia aún más especial.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735881299663/81a2ade0-4933-490e-ac9f-4ba451256ad0.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-durante-el-evento"><strong>Durante el evento</strong></h3>
<p>No solo fue mi primera vez asistiendo en persona, sino que también tuve la oportunidad de conectar con profesionales talentosos y probar los lanzamientos más recientes a través de workshops. Compartí esta experiencia con mi gran amiga <a target="_blank" href="https://linkedin.com/in/katherinechauca"><strong>Katherine Chauca</strong></a>, también embajadora del programa <a target="_blank" href="https://developers.google.com/womentechmakers"><strong>Women Techmakers</strong></a>.</p>
<p>El evento arrancó con una apertura divertidísima a cargo de Marc Rebillet, quien no solo hizo un pre-show entretenido, sino que también presentó MusicFX AI, demostrando cómo la IA está transformando incluso el mundo de la música.</p>
<center>
  <iframe width="560" height="315" src="https://www.youtube.com/embed/V3gAde-gawE"></iframe>
</center>

<h3 id="heading-highlights-del-google-io-2024"><strong>Highlights del Google I/O 2024</strong></h3>
<p>Aquí les dejo un resumen rápido de los anuncios más emocionantes:</p>
<ol>
<li><p><strong>Gemini 1.5</strong>: Google anunció la nueva versión de su modelo de IA Gemini, con mejoras significativas en rendimiento y capacidades.</p>
</li>
<li><p><strong>Gemini API</strong>: Se lanzó oficialmente la API de Gemini, permitiendo a los desarrolladores integrar las capacidades de Gemini en sus aplicaciones.</p>
</li>
<li><p><strong>Google AI Studio</strong>: Una nueva plataforma para desarrolladores que facilita la creación y prueba de aplicaciones de IA.</p>
</li>
<li><p><strong>Avances en Project Starline</strong>: Google mostró los últimos avances en su tecnología de telepresencia 3D.</p>
</li>
</ol>
<h3 id="heading-recaps-recomendados"><strong>Recaps recomendados</strong></h3>
<p>Si quieren revivir el evento o profundizar en los anuncios, aquí les dejo algunos excelentes recaps:</p>
<ol>
<li><p><a target="_blank" href="https://developers.googleblog.com/es/google-io-2024-recap-making-ai-accessible-and-helpful-for-every-developer/">Google Developers Blog: Resumen oficial de Google I/O 2024</a></p>
</li>
<li><p><a target="_blank" href="https://www.theverge.com/google-io">The Verge: Google I/O 2024 – Todo lo que necesitas saber</a></p>
</li>
<li><p><a target="_blank" href="https://techcrunch.com/2024/05/15/google-i-o-2024-everything-announced-so-far/">TechCrunch: Google I/O 2024 – Here’s everything Google just announced</a></p>
</li>
</ol>
<h2 id="heading-compartiendo-la-experiencia-google-io-extended-en-lima"><strong>Compartiendo la experiencia: Google I/O Extended en Lima</strong></h2>
<p>Mi última charla presencial había sido con <a target="_blank" href="https://www.instagram.com/perunetdev">Perú .Net Development</a> en marzo y ahora en julio, tuve la oportunidad de compa<a target="_blank" href="https://www.instagram.com/perunetdev">rtir mi experiencia e</a>n el I/O Extended organizado por GDG Cloud Lima. Fue emocionante regresar a un escenario local y conectar con la nueva generación de la comunidad tech en Lima.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735882355345/bdf88437-3426-4190-9c46-5b299c9259b6.png" alt class="image--center mx-auto" /></p>
<p>Durante la charla, surgieron preguntas interesantes que me gustaría compartir con ustedes:</p>
<ul>
<li><p><strong>¿Qué es el programa Women Techmakers de Google?</strong></p>
<p>  Es un programa organizado por Google para dar visibilidad, generar y aportar comunidad, así como recursos a las mujeres en tecnología. Todos los años este programa abre convocatorias nuevas para recibir nuevas embajadoras. Sí, te gustaría ser parte regístrate como miembro <a target="_blank" href="https://developers.google.com/womentechmakers/ambassadors">aquí</a> y mantente atenta para la convocatoria del próximo año. También, puedes buscar embajadores locales en tu ciudad para buscar mentoría y consejos para aplicar al siguiente año.</p>
</li>
<li><p><strong>¿Qué es un Google Developer Group?</strong></p>
<p>  Son comunidades que con el apoyo de Google están presentes en muchos países con el objetivo de conectar desarrolladores locales para adquirir nuevas habilidades en eventos, ya sean presenciales o virtuales, aquí en Perú tenemos distintos capítulos, por mencionar algunos aquí en Lima: <a target="_blank" href="https://gdg.community.dev/gdg-open/"><strong>GDG Open</strong></a>, <a target="_blank" href="https://gdg.community.dev/gdg-lima/"><strong>GDG Lima</strong></a> y <a target="_blank" href="https://gdg.community.dev/gdg-cloud-lima/"><strong>GDG Cloud Lima</strong></a>. Si quieres encontrar el más cercano a ti, puedes buscarlos <a target="_blank" href="https://gdg.community.dev/">aquí</a>.</p>
</li>
<li><p><strong>¿Cómo puedo asistir al evento?</strong></p>
<p>  La transmisión en vivo está abierta a todos a través del canal de YouTube de Google. Sin embargo, para asistir al evento presencialmente, debes estar atento a ciertas invitaciones. Este año, por ejemplo, se invitó a Women Techmakers Ambassadors, organizadores de Google Developers Group (GDG), Google Developer Experts (GDE), y algunos partners de Google.</p>
</li>
</ul>
<h4 id="heading-reflexiones-finales"><strong>Reflexiones finales</strong></h4>
<p>Participar en el Google I/O y luego compartir esa experiencia con mi comunidad local ha sido increíblemente enriquecedor. Me ha recordado la importancia de mantenerse actualizado en tecnología, pero también de compartir el conocimiento y construir comunidad.</p>
<p>Los animo a todos a que se involucren en comunidades tech locales. Ya sea asistiendo a eventos, compartiendo sus conocimientos o incluso organizando meetups, cada aporte cuenta y ayuda a crear un ecosistema tecnológico más fuerte y diverso.</p>
<p><strong>Referencias</strong>:</p>
<ol>
<li><p><a target="_blank" href="https://deepmind.google/technologies/gemini/">https://deepmind.google/technologies/gemini/</a></p>
</li>
<li><p><a target="_blank" href="https://ai.google.dev/gemini-api?hl=es-419">https://ai.google.dev/gemini-api?hl=es-419</a></p>
</li>
<li><p><a target="_blank" href="https://aistudio.google.com/">https://aistudio.google.com/</a></p>
</li>
<li><p><a target="_blank" href="https://starline.google/">https://starline.google/</a></p>
</li>
<li><p><a target="_blank" href="https://sustainability.google/">https://sustainability.google/</a></p>
</li>
<li><p><a target="_blank" href="https://developers.google.com/womentechmakers">https://developers.google.com/womentechmakers</a></p>
</li>
<li><p><a target="_blank" href="https://io.google/2024/">https://io.google/2024/</a></p>
</li>
</ol>
<hr />
<p><strong>¿Has asistido alguna vez a un evento tech? ¿Qué te pareció? ¿O tal vez estás pensando en unirte a una comunidad local? ¡Puedes dejar tus ideas/aportes en los comentarios!</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735882471659/241d0242-d8f6-4483-baf0-d2b628c1ccd8.png" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Recursos de la Presentación: La IA a tu Servicio en la Salud con AWS HealthScribe]]></title><description><![CDATA[¡Hola a todos!
Bienvenidos a esta nueva entrada, donde compartiré todos los recursos y enlaces mencionados durante mi presentación “La IA a tu Servicio: Mejorando la Salud con AWS HealthScribe”.
El objetivo es proporcionar un acceso fácil y organizad...]]></description><link>https://codeanding.com/recursos-de-la-presentacion-la-ia-a-tu-servicio-en-la-salud-con-aws-healthscribe</link><guid isPermaLink="true">https://codeanding.com/recursos-de-la-presentacion-la-ia-a-tu-servicio-en-la-salud-con-aws-healthscribe</guid><category><![CDATA[healthscribe]]></category><category><![CDATA[codeanding]]></category><category><![CDATA[AWS]]></category><category><![CDATA[healthtech]]></category><category><![CDATA[resources]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Thu, 05 Sep 2024 05:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735884417860/aaf80229-54e9-4c0c-a9a1-4160da316b32.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>¡Hola a todos!</p>
<p>Bienvenidos a esta nueva entrada, donde compartiré todos los recursos y enlaces mencionados durante mi presentación <strong>“La IA a tu Servicio: Mejorando la Salud con AWS HealthScribe”</strong>.</p>
<p>El objetivo es proporcionar un acceso fácil y organizado a la información que puede ayudar a entender mejor cómo la inteligencia artificial (IA) y las tecnologías de AWS están revolucionando el sector de la salud.</p>
<h3 id="heading-recursos-organizados-por-seccion"><strong>📚 Recursos organizados por sección:</strong></h3>
<ol>
<li><p><strong>¿Por qué la IA puede ser tu nuevo mejor amigo en la salud?</strong></p>
<ul>
<li><p><strong>Estudio sobre la precisión diagnóstica de la IA</strong>: <a target="_blank" href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6616181/">Artificial Intelligence in Healthcare: Past, Present and Future – PubMed Central (PMC)</a>.</p>
</li>
<li><p><strong>Informe de ahorro en costos con IA</strong>: <a target="_blank" href="https://www.accenture.com/us-en/services/health/intelligent-health-payer">Accenture Report on AI in Healthcare</a>.</p>
</li>
<li><p><strong>Revisión sobre precisión diagnóstica de la IA en enfermedades oculares</strong>: <a target="_blank" href="https://www.thelancet.com/journals/landig/article/PIIS2589-7500\(19\)30123-2/fulltext">Artificial intelligence versus clinicians: systematic review – The Lancet Digital Health</a>.</p>
</li>
</ul>
</li>
<li><p><strong>Problemas médicos que necesitan soluciones épicas</strong></p>
<ul>
<li><p><a target="_blank" href="https://www.sciencedirect.com/science/article/pii/S2666990024000132">AI in diagnostic imaging: Revolutionising accuracy and efficiency</a></p>
</li>
<li><p><a target="_blank" href="https://arxiv.org/abs/2405.18346">Intelligent Clinical Documentation: Harnessing Generative AI for Patient-Centric Clinical Note Generation</a></p>
</li>
<li><p><a target="_blank" href="https://jamanetwork.com/journals/jamanetworkopen/fullarticle/2801918">Assessment of Natural Language Processing of Electronic Health Records to Measure Goals-of-Care Discussions as a Clinical Trial Outcome</a></p>
</li>
</ul>
</li>
<li><p><strong>Material de Referencia</strong></p>
<ul>
<li><p><a target="_blank" href="https://community.aws/">Aws Community</a></p>
</li>
<li><p><a target="_blank" href="https://docs.aws.amazon.com/transcribe/latest/dg/health-scribe.html">Aws Documentation: HealthScribe</a></p>
</li>
<li><p>Libros recomendados:</p>
<ul>
<li><a target="_blank" href="https://www.amazon.com/Healthcare-Comprehensive-Dr-Phipps-PhD/dp/B0DB38CW6G">AI and Healthcare: A Comprehensive Guide</a></li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Material Complementario</strong></p>
<ul>
<li><p>Accede a la presentación completa <a target="_blank" href="https://docs.google.com/presentation/d/1OsE9-p-sr8kwQ7KJtdMFRAP291XM80xPpIrKDuZ0Yqc/edit?usp=sharing">aquí</a></p>
</li>
<li><p>Accede al repositorio de la demo – <a target="_blank" href="https://github.com/aws-samples/aws-healthscribe-demo">https://github.com/aws-samples/aws-healthscribe-demo</a></p>
</li>
</ul>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735884465619/b84d0f38-f0b9-45d6-b5e2-209f902dbc94.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-quieres-contribuir"><strong>🤝 ¿Quieres Contribuir?</strong></h3>
<p>¡Tu feedback es valioso! Si tienes preguntas o quieres compartir tu experiencia con AWS HealthScribe, déjame un comentario abajo.</p>
<h3 id="heading-proximos-pasos"><strong>📅 Próximos Pasos</strong></h3>
<p>Estaré actualizando este post con nuevos recursos y casos de uso. ¡No olvides seguirme para estar al tanto!</p>
<p><strong>Hasta la próxima entrada, ¡sigamos codeando y aprendiendo juntos!</strong></p>
]]></content:encoded></item><item><title><![CDATA[Nuevas Aventuras en @codeanding]]></title><description><![CDATA[¡Hola!
¡Bienvenidos a @codeanding!
Estoy emocionada de compartir este espacio con ustedes, donde iré publicando entradas sobre mis aventuras en mi camino ninja en tecnología.
¿Qué puedes esperar aquí?
Este blog nació durante la pandemia y, aunque tuv...]]></description><link>https://codeanding.com/nuevas-aventuras-en-codeanding</link><guid isPermaLink="true">https://codeanding.com/nuevas-aventuras-en-codeanding</guid><category><![CDATA[Blogging]]></category><dc:creator><![CDATA[Julissa Rodriguez]]></dc:creator><pubDate>Tue, 03 Sep 2024 05:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735877728688/46e5251d-fcad-4945-880a-f1c07e16c57b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>¡Hola!</strong></p>
<p>¡Bienvenidos a <a target="_blank" href="https://instagram.com/codeanding"><strong>@codeanding</strong></a>!</p>
<p>Estoy emocionada de compartir este espacio con ustedes, donde iré publicando entradas sobre mis aventuras en mi camino ninja en tecnología.</p>
<p><strong>¿Qué puedes esperar aquí?</strong></p>
<p>Este blog nació durante la pandemia y, aunque tuvo una pequeña pausa debido a algunas decisiones un poco <em>"peculiares"</em>, las entradas anteriores a 2024 se han perdido. Pero ¿sabes qué? Veámoslo como una oportunidad para empezar de nuevo, actualizar el contenido y explorar nuevos temas juntos.</p>
<p>Aquí encontrarás desde tutoriales y proyectos, hasta reflexiones sobre los retos y logros que se presentan en este fascinante mundo de la tecnología. Me comprometo a compartir al menos un post mensual, para mantener este espacio activo y en constante crecimiento.</p>
<p>Quiero que este sea un espacio para aprender y compartir en conjunto. ¿Qué temas te gustaría explorar? ¿Hay alguna área específica de la tecnología que te intrigue especialmente? ¡Me encantaría conocer tus ideas en los comentarios!</p>
<p>¡Gracias por estar aquí y ser parte de esto!</p>
<p><strong>¡Nos leemos pronto!</strong></p>
]]></content:encoded></item></channel></rss>