<?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[TechInsight.dev – Software Development, Tech Tutorials & Industry Insights, Tech Blogs]]></title><description><![CDATA[Stay ahead in technology with TechInsight.dev. Explore expert tutorials, software development guides, coding tips, and the latest tech industry insights to boost your skills and knowledge.]]></description><link>https://techinsight.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1760276252008/0edec4c4-747d-49dc-806c-fabdb38f29a2.png</url><title>TechInsight.dev – Software Development, Tech Tutorials &amp; Industry Insights, Tech Blogs</title><link>https://techinsight.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 09 Apr 2026 13:16:38 GMT</lastBuildDate><atom:link href="https://techinsight.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Understanding ACID Properties: The Pillars of Database Reliability]]></title><description><![CDATA[ACID is one of the most fundamental concepts in database management, serving as the bedrock for reliable data storage and transaction processing. If you rely on your data being accurate and consistent—whether you're running an e-commerce platform, a ...]]></description><link>https://techinsight.dev/understanding-acid-properties-the-pillars-of-database-reliability</link><guid isPermaLink="true">https://techinsight.dev/understanding-acid-properties-the-pillars-of-database-reliability</guid><category><![CDATA[ACID Transactions]]></category><category><![CDATA[Databases]]></category><dc:creator><![CDATA[Arjun Saud]]></dc:creator><pubDate>Fri, 21 Nov 2025 04:24:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1763699262233/d6c98ff9-7e6d-4bb1-867a-888ba38143aa.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>ACID</strong> is one of the most fundamental concepts in database management, serving as the bedrock for reliable data storage and transaction processing. If you rely on your data being accurate and consistent—whether you're running an e-commerce platform, a financial application, or managing customer records—you are relying on ACID.</p>
<p>This article dives into the four properties, why they matter, and provides a clear, running example to make the concepts tangible.</p>
<hr />
<h3 id="heading-why-database-transactions-need-acid">Why Database Transactions Need ACID</h3>
<p>In a modern application, a single user action (a "transaction") might involve multiple steps. For instance, buying a product online requires checking inventory, charging the credit card, and updating the order status. If the system fails halfway through, the resulting data could be disastrous: the customer is charged, but no order exists.</p>
<p>The ACID properties exist to prevent exactly this kind of inconsistent state, ensuring that data integrity is always maintained.</p>
<h3 id="heading-1-atomicity-the-all-or-nothing-rule">1. Atomicity: The "All or Nothing" Rule</h3>
<p>Atomicity (from the Greek word <em>atomos</em>, meaning "indivisible") ensures that a transaction is treated as a single, indivisible unit of work.</p>
<ul>
<li><strong>Rule:</strong> Either all changes within the transaction are successfully completed and recorded (committed), or none of them are (rolled back).</li>
</ul>
<blockquote>
<h4 id="heading-example-the-bank-transfer">Example: The Bank Transfer</h4>
<p>A customer, Alice, transfers $100 to another customer, Bob. This transaction has two steps:</p>
<ol>
<li><p>Debit $100 from Alice's account: $A_{\text{balance}} = A_{\text{balance}} - 100$</p>
</li>
<li><p>Credit $100 to Bob's account: $B_{\text{balance}} = B_{\text{balance}} + 100$</p>
<p> If the system crashes after step 1 but before step 2, Atomicity dictates that the entire transaction must be undone, or rolled back. Alice's account balance is restored to its original state, ensuring that $100 is not lost forever.</p>
</li>
</ol>
</blockquote>
<h3 id="heading-2-consistency-maintaining-valid-states">2. Consistency: Maintaining Valid States</h3>
<p>Consistency guarantees that a transaction moves the database from one valid state to another valid state. It ensures that any data written abides by all defined rules and constraints.</p>
<ul>
<li><strong>Rule:</strong> The database must adhere to pre-defined constraints (e.g., uniqueness, data type checks, foreign key relationships) before and after the transaction.</li>
</ul>
<blockquote>
<h4 id="heading-example-the-bank-transfer-1">Example: The Bank Transfer</h4>
<p>The bank has a rule that accounts must never have a negative balance (a business constraint).</p>
<p>If Alice only has $50 in her account, a transaction attempting to debit $100 would be immediately aborted because committing it would violate the consistency rule (Alice's balance would be -$50), preventing the database from moving into an invalid state.</p>
</blockquote>
<h3 id="heading-3-isolation-protecting-concurrent-operations">3. Isolation: Protecting Concurrent Operations</h3>
<p>Isolation ensures that concurrent transactions operate independently without interference from one another. To an observer, it appears as though the transactions are being executed sequentially, even if they are processed simultaneously.</p>
<ul>
<li><strong>Rule:</strong> The partial effects of one running transaction are hidden from other concurrent transactions.</li>
</ul>
<blockquote>
<h4 id="heading-example-the-bank-transfer-2">Example: The Bank Transfer</h4>
<p>While Alice is transferring $100 to Bob (Transaction $T_1$), Bob's employer attempts to deposit his paycheck of $500 (Transaction $T_2$).</p>
<p>Isolation prevents $T_2$ from seeing Alice's balance in an unstable, midway state (after the debit but before the credit). $T_2$ either sees the balance before $T_1$ started or after $T_1$ fully committed, thus ensuring that the total balance calculation is correct and not skewed by temporary, partial changes.</p>
</blockquote>
<h3 id="heading-4-durability-permanent-record-keeping">4. Durability: Permanent Record Keeping</h3>
<p>Durability guarantees that once a transaction has been successfully committed, the changes are permanent and will survive any subsequent system failure, such as a power outage or a server crash.</p>
<ul>
<li><strong>Rule:</strong> Committed changes are permanently written to non-volatile storage (like a hard disk) and secured, often through the use of a transaction log.</li>
</ul>
<blockquote>
<h4 id="heading-example-the-bank-transfer-3">Example: The Bank Transfer</h4>
<p>Alice’s $100 transfer to Bob is successfully committed. Immediately afterward, a sudden power surge takes the bank's server offline.</p>
<p>When the system is rebooted, Durability ensures that the database uses its transaction logs and persistent storage to confirm that the transfer was completed. Both Alice’s debit and Bob’s credit are guaranteed to be present and accurate.</p>
</blockquote>
<h3 id="heading-summary-table">Summary Table</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Property</strong></td><td><strong>What it Guarantees</strong></td><td><strong>Key Concept</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>A</strong>tomicity</td><td>All operations in a transaction either succeed or fail entirely.</td><td>All or Nothing</td></tr>
<tr>
<td><strong>C</strong>onsistency</td><td>Transactions move the database from one valid state to another.</td><td>Valid States &amp; Rules</td></tr>
<tr>
<td><strong>I</strong>solation</td><td>Concurrent transactions do not interfere with each other.</td><td>Hidden Changes</td></tr>
<tr>
<td><strong>D</strong>urability</td><td>Committed changes are permanent, even after a system failure.</td><td>Permanent Record</td></tr>
</tbody>
</table>
</div><h3 id="heading-final-thought">Final Thought</h3>
<p>The ACID properties are essential for any system requiring high integrity and reliability. Understanding these concepts is key to designing resilient applications and selecting the right database technology (often an RDBMS like PostgreSQL or MySQL) that ensures your data is safe and trustworthy.</p>
<hr />
]]></content:encoded></item><item><title><![CDATA[A Clear Guide to Encryption, Encoding, and Hashing]]></title><description><![CDATA[1. Encoding: Making Data Usable and Compatible
What it is: Encoding is the process of converting data from one format into another. Its primary goal is to ensure data can be correctly interpreted, stored, or transmitted across different systems or me...]]></description><link>https://techinsight.dev/a-clear-guide-to-encryption-encoding-and-hashing</link><guid isPermaLink="true">https://techinsight.dev/a-clear-guide-to-encryption-encoding-and-hashing</guid><category><![CDATA[decoding]]></category><category><![CDATA[encryption]]></category><category><![CDATA[encoding]]></category><category><![CDATA[Hashing]]></category><category><![CDATA[Cryptography]]></category><category><![CDATA[Cryptography, Hash, MbedTLS, Python, Sha256, TLS]]></category><dc:creator><![CDATA[Arjun Saud]]></dc:creator><pubDate>Sun, 12 Oct 2025 13:59:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1760276917357/5507d385-5dc7-4218-9299-882dd553bf3e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-1-encoding-making-data-usable-and-compatible">1. Encoding: Making Data Usable and Compatible</h3>
<p><strong>What it is:</strong> Encoding is the process of converting data from one format into another. Its primary goal is to ensure data can be correctly interpreted, stored, or transmitted across different systems or mediums. It’s about structuring data for functionality, not security.</p>
<ul>
<li><p><strong>Purpose:</strong> To enable data to be read, processed, or displayed correctly by various applications or systems. Think of it like translating a word into a universally understood symbol.</p>
</li>
<li><p><strong>Mechanism:</strong> It uses publicly known algorithms or standards. No secret key is involved.</p>
</li>
<li><p><strong>Reversibility:</strong> Encoding is <strong>always reversible</strong>. The original data can be recovered precisely through a corresponding decoding process.</p>
</li>
<li><p><strong>Security Implication:</strong> Provides virtually <em>no security</em>. An encoded message is easily decoded by anyone familiar with the encoding scheme.</p>
</li>
</ul>
<p><strong>Visual Example: Base64 Encoding for Web Data</strong></p>
<p>Imagine you want to include an image directly within a web page's HTML or send binary data (like an image file) through a text-based email system. Base64 encoding transforms this binary data into a string of ASCII characters (A-Z, a-z, 0-9, +, /), making it safe for text-only environments.</p>
<p>If you encode the simple text "Cat" using Base64, you get "Q2F0". The process involves converting characters to their binary form, grouping these bits into 6-bit chunks, and mapping each chunk to a specific Base64 character.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760277349753/4af7102c-a206-4498-989b-fa34c3b365d2.png" alt class="image--center mx-auto" /></p>
<p>The primary benefit here is compatibility and error-free transmission, not hiding the content. Anyone receiving "Q2F0" can easily decode it back to "Cat."</p>
<hr />
<h3 id="heading-2-encryption-safeguarding-confidentiality">2. Encryption: Safeguarding Confidentiality</h3>
<p><strong>What it is:</strong> Encryption is the cornerstone of data security, designed to protect the <em>confidentiality</em> of information. It converts readable data (plaintext) into an unreadable, scrambled form (ciphertext), ensuring that only authorized individuals can access the original content.</p>
<ul>
<li><p><strong>Purpose:</strong> To secure data against unauthorized access, making it unintelligible to anyone without the correct decryption key.</p>
</li>
<li><p><strong>Mechanism:</strong> An <strong>encryption algorithm</strong> (or cipher) uses a <strong>cryptographic key</strong> to transform plaintext into ciphertext.</p>
</li>
<li><p><strong>Reversibility:</strong> Encryption is <strong>reversible</strong>, but <em>only</em> with the correct decryption key.</p>
</li>
<li><p><strong>Security Implication:</strong> Provides strong security for confidentiality. The strength depends on the algorithm and key length.</p>
</li>
</ul>
<p><strong>Visual Example: Symmetric vs. Asymmetric Encryption</strong></p>
<p>Imagine Alice wants to send a secret message "MEET ME AT NOON" to Bob.</p>
<ol>
<li><p><strong>Symmetric Encryption (e.g., AES):</strong> Alice and Bob agree on a <strong>single secret key</strong> beforehand. Alice uses this key to encrypt her message ("MEET ME AT NOON" becomes "PHHW PH DW QRRQ" using a simple Caesar cipher example). She sends the ciphertext to Bob, who uses the <em>exact same key</em> to decrypt it back to the original message. This method is fast but requires a secure way to share the secret key.</p>
</li>
<li><p><strong>Asymmetric Encryption (e.g., RSA):</strong> Bob generates a pair of keys: a <strong>public key</strong> (which he shares with everyone, including Alice) and a <strong>private key</strong> (which he keeps secret). Alice uses Bob's <strong>public key</strong> to encrypt her message. She sends the ciphertext to Bob. Only Bob's unique <strong>private key</strong> can decrypt the message back into "MEET ME AT NOON." This eliminates the need for prior secret key exchange but is computationally more intensive.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760277366124/35b494b7-fffc-498c-af4c-68abdd35c066.png" alt class="image--center mx-auto" /></p>
<p>Encryption is fundamental to secure communications (like HTTPS for websites), protected data storage, and ensuring privacy in transit.</p>
<hr />
<h3 id="heading-3-hashing-verifying-integrity-and-creating-unique-fingerprints">3. Hashing: Verifying Integrity and Creating Unique Fingerprints ☝️</h3>
<p><strong>What it is:</strong> Hashing is a one-way mathematical function that transforms an input of any size (a file, a password, a message) into a fixed-length string of characters, called a <strong>hash value</strong> or <strong>message digest</strong>.</p>
<ul>
<li><p><strong>Purpose:</strong> Primarily used to verify the <em>integrity</em> of data (detecting if it has been altered) and for secure password storage.</p>
</li>
<li><p><strong>Mechanism:</strong> A <strong>hash function</strong> (e.g., SHA-256) processes the input data to produce a unique, deterministic output. The same input <em>always</em> produces the same hash.</p>
</li>
<li><p><strong>Reversibility:</strong> Hashing is designed to be <strong>irreversible</strong>. It's computationally infeasible to reconstruct the original input from its hash value. This "one-way" property is critical for its security applications.</p>
</li>
<li><p><strong>Security Implication:</strong> Provides strong integrity checks. Any modification to the original data, even a single character, will result in a completely different hash value.</p>
</li>
</ul>
<p><strong>Visual Example: Checking File Integrity with SHA-256</strong></p>
<p>Imagine you download a software update (<a target="_blank" href="http://SoftwareUpdate.zip"><code>SoftwareUpdate.zip</code></a>) and want to ensure it hasn't been corrupted or maliciously tampered with during transfer.</p>
<ol>
<li><p>The software publisher calculates the SHA-256 hash of their original, untampered <a target="_blank" href="http://SoftwareUpdate.zip"><code>SoftwareUpdate.zip</code></a> file and publishes it on their website (e.g., <code>d7a8fbb307d...</code>).</p>
</li>
<li><p>After downloading the file, you run a hashing tool on your copy to generate its SHA-256 hash.</p>
</li>
<li><p>You then compare your calculated hash with the publisher's official hash.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1760277391570/3eee943a-faa9-40c5-8016-004986478e17.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p><strong>Match:</strong> If the hashes are identical, you can be highly confident that your downloaded file is exactly as the publisher intended – its integrity is verified.</p>
</li>
<li><p><strong>Mismatch:</strong> If even a single bit in your downloaded file is different, the generated hash will be drastically different (the "avalanche effect"). This immediately tells you the file has been altered or corrupted, and you should not trust it.</p>
</li>
</ul>
<p>Hashing is also crucial for secure password management. Instead of storing your actual password, websites store its hash. When you log in, your entered password is hashed and compared to the stored hash. This way, even if a hacker gains access to the database, they only have the irreversible hashes, not your original password.</p>
<hr />
<h3 id="heading-conclusion-three-pillars-of-digital-data-management">Conclusion: Three Pillars of Digital Data Management</h3>
<p>While distinct in their function, encoding, encryption, and hashing are all indispensable tools in our digital toolkit:</p>
<ul>
<li><p><strong>Encoding</strong> ensures data <strong>usability</strong> and <strong>interoperability</strong>.</p>
</li>
<li><p><strong>Encryption</strong> guarantees data <strong>confidentiality</strong>.</p>
</li>
<li><p><strong>Hashing</strong> provides data <strong>integrity</strong> and <strong>authenticity</strong> verification.</p>
</li>
</ul>
<p>Understanding these differences is key to appreciating the robust mechanisms that keep our online interactions and data secure, functional, and reliable in an ever-evolving digital landscape.</p>
]]></content:encoded></item><item><title><![CDATA[Create a Full Authentication System Using NestJS and Next.js with JWT and Refresh Tokens]]></title><description><![CDATA[In this article, we’ll build a complete authentication system using NestJS (backend) and Next.js (frontend) — implementing both Access Tokens and Refresh Tokens for secure session management.
What You’ll Learn
By the end of this tutorial, you’ll unde...]]></description><link>https://techinsight.dev/create-a-full-authentication-system-using-nestjs-and-nextjs-with-jwt-and-refresh-tokens</link><guid isPermaLink="true">https://techinsight.dev/create-a-full-authentication-system-using-nestjs-and-nextjs-with-jwt-and-refresh-tokens</guid><category><![CDATA[JWT token,JSON Web,Token,Token authentication,Access token,JSON token,JWT security,JWT authentication,Token-based authentication,JWT decoding,JWT implementation]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[nestjs]]></category><category><![CDATA[nextauth.js]]></category><category><![CDATA[authentication]]></category><dc:creator><![CDATA[Babita Bhatt]]></dc:creator><pubDate>Tue, 07 Oct 2025 14:50:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/OqtafYT5kTw/upload/df7f08ab6d4570f45d1895bdc86cc8cb.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, we’ll build a <strong>complete authentication system</strong> using <strong>NestJS (backend)</strong> and <strong>Next.js (frontend)</strong> — implementing both <strong>Access Tokens</strong> and <strong>Refresh Tokens</strong> for secure session management.</p>
<h2 id="heading-what-youll-learn">What You’ll Learn</h2>
<p>By the end of this tutorial, you’ll understand how to:</p>
<ul>
<li><p>Build a <strong>NestJS Auth API</strong> with JWT and Refresh Tokens</p>
</li>
<li><p>Secure routes using <strong>Guards and Decorators</strong></p>
</li>
<li><p>Store and validate tokens in <strong>HTTP-only cookies</strong></p>
</li>
<li><p>Handle authentication on the <strong>Next.js frontend</strong></p>
</li>
<li><p>Automatically refresh expired tokens</p>
</li>
</ul>
<h2 id="heading-tech-stack">Tech Stack</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Layer</td><td>Technology</td></tr>
</thead>
<tbody>
<tr>
<td>Backend</td><td>NestJS, TypeScript, Passport.js, JWT</td></tr>
<tr>
<td>Frontend</td><td>Next.js 14 (App Router), React Hook Form, Axios</td></tr>
<tr>
<td>Database</td><td>PostgreSQL (with Prisma ORM)</td></tr>
<tr>
<td>Auth</td><td>Access Token + Refresh Token (JWT)</td></tr>
<tr>
<td>Deployment-ready</td><td>Works with any REST setup</td></tr>
</tbody>
</table>
</div><h2 id="heading-step-1-setting-up-the-nestjs-backend">Step 1 — Setting up the NestJS Backend</h2>
<pre><code class="lang-bash">npm i -g @nestjs/cli
nest new auth-backend
</code></pre>
<h3 id="heading-2-install-dependencies">2. Install Dependencies</h3>
<pre><code class="lang-bash">npm install @nestjs/jwt @nestjs/passport passport passport-jwt bcrypt prisma @prisma/client cookie-parser
</code></pre>
<h2 id="heading-step-2-configure-prisma-database-layer">Step 2 — Configure Prisma (Database Layer)</h2>
<p>Initialize Prisma:</p>
<pre><code class="lang-bash">npx prisma init
</code></pre>
<p>Then update your <code>schema.prisma</code> file:</p>
<pre><code class="lang-bash">model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  password  String
  refreshToken String?
  createdAt DateTime @default(now())
}
</code></pre>
<p>Run migration:</p>
<pre><code class="lang-bash">npx prisma migrate dev --name init
</code></pre>
<h2 id="heading-step-3-implement-jwt-authentication-in-nestjs">Step 3 — Implement JWT Authentication in NestJS</h2>
<h3 id="heading-generate-auth-module">Generate Auth Module</h3>
<pre><code class="lang-bash">nest g module auth
nest g service auth
nest g controller auth
</code></pre>
<h3 id="heading-authservice-handle-signup-login-tokens">AuthService — Handle Signup, Login, Tokens</h3>
<pre><code class="lang-typescript"><span class="hljs-comment">// auth.service.ts</span>
<span class="hljs-keyword">import</span> { Injectable, UnauthorizedException } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { JwtService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/jwt'</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> bcrypt <span class="hljs-keyword">from</span> <span class="hljs-string">'bcrypt'</span>;
<span class="hljs-keyword">import</span> { PrismaService } <span class="hljs-keyword">from</span> <span class="hljs-string">'../prisma/prisma.service'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AuthService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> prisma: PrismaService, <span class="hljs-keyword">private</span> jwt: JwtService</span>) {}

  <span class="hljs-keyword">async</span> signup(email: <span class="hljs-built_in">string</span>, password: <span class="hljs-built_in">string</span>) {
    <span class="hljs-keyword">const</span> hash = <span class="hljs-keyword">await</span> bcrypt.hash(password, <span class="hljs-number">10</span>);
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.prisma.user.create({
      data: { email, password: hash },
    });
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.generateTokens(user.id, user.email);
  }

  <span class="hljs-keyword">async</span> login(email: <span class="hljs-built_in">string</span>, password: <span class="hljs-built_in">string</span>) {
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.prisma.user.findUnique({ where: { email } });
    <span class="hljs-keyword">if</span> (!user || !(<span class="hljs-keyword">await</span> bcrypt.compare(password, user.password))) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnauthorizedException(<span class="hljs-string">'Invalid credentials'</span>);
    }
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.generateTokens(user.id, user.email);
  }

  <span class="hljs-keyword">async</span> generateTokens(userId: <span class="hljs-built_in">number</span>, email: <span class="hljs-built_in">string</span>) {
    <span class="hljs-keyword">const</span> accessToken = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.jwt.signAsync(
      { sub: userId, email },
      { secret: process.env.JWT_SECRET, expiresIn: <span class="hljs-string">'15m'</span> },
    );
    <span class="hljs-keyword">const</span> refreshToken = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.jwt.signAsync(
      { sub: userId },
      { secret: process.env.JWT_REFRESH_SECRET, expiresIn: <span class="hljs-string">'7d'</span> },
    );
    <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.prisma.user.update({
      where: { id: userId },
      data: { refreshToken },
    });
    <span class="hljs-keyword">return</span> { accessToken, refreshToken };
  }
}
</code></pre>
<h2 id="heading-step-4-auth-controller">Step 4 — Auth Controller</h2>
<pre><code class="lang-typescript"><span class="hljs-comment">// auth.controller.ts</span>
<span class="hljs-keyword">import</span> { Body, Controller, Post, Res } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { AuthService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./auth.service'</span>;
<span class="hljs-keyword">import</span> { Response } <span class="hljs-keyword">from</span> <span class="hljs-string">'express'</span>;

<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'auth'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AuthController {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> authService: AuthService</span>) {}

  <span class="hljs-meta">@Post</span>(<span class="hljs-string">'signup'</span>)
  <span class="hljs-keyword">async</span> signup(<span class="hljs-meta">@Body</span>() body: <span class="hljs-built_in">any</span>, <span class="hljs-meta">@Res</span>() res: Response) {
    <span class="hljs-keyword">const</span> tokens = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.authService.signup(body.email, body.password);
    res.cookie(<span class="hljs-string">'refreshToken'</span>, tokens.refreshToken, { httpOnly: <span class="hljs-literal">true</span> });
    <span class="hljs-keyword">return</span> res.json({ accessToken: tokens.accessToken });
  }

  <span class="hljs-meta">@Post</span>(<span class="hljs-string">'login'</span>)
  <span class="hljs-keyword">async</span> login(<span class="hljs-meta">@Body</span>() body: <span class="hljs-built_in">any</span>, <span class="hljs-meta">@Res</span>() res: Response) {
    <span class="hljs-keyword">const</span> tokens = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.authService.login(body.email, body.password);
    res.cookie(<span class="hljs-string">'refreshToken'</span>, tokens.refreshToken, { httpOnly: <span class="hljs-literal">true</span> });
    <span class="hljs-keyword">return</span> res.json({ accessToken: tokens.accessToken });
  }
}
</code></pre>
<h2 id="heading-step-5-refresh-token-endpoint">Step 5 — Refresh Token Endpoint</h2>
<pre><code class="lang-typescript"><span class="hljs-meta">@Post</span>(<span class="hljs-string">'refresh'</span>)
<span class="hljs-keyword">async</span> refresh(<span class="hljs-meta">@Req</span>() req: Request, <span class="hljs-meta">@Res</span>() res: Response) {
  <span class="hljs-keyword">const</span> token = req.cookies[<span class="hljs-string">'refreshToken'</span>];
  <span class="hljs-keyword">if</span> (!token) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnauthorizedException(<span class="hljs-string">'No refresh token'</span>);

  <span class="hljs-keyword">const</span> payload = <span class="hljs-built_in">this</span>.jwt.verify(token, { secret: process.env.JWT_REFRESH_SECRET });
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.prisma.user.findUnique({ where: { id: payload.sub } });

  <span class="hljs-keyword">if</span> (!user || user.refreshToken !== token) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnauthorizedException(<span class="hljs-string">'Invalid token'</span>);

  <span class="hljs-keyword">const</span> newTokens = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.generateTokens(user.id, user.email);
  res.cookie(<span class="hljs-string">'refreshToken'</span>, newTokens.refreshToken, { httpOnly: <span class="hljs-literal">true</span> });
  <span class="hljs-keyword">return</span> res.json({ accessToken: newTokens.accessToken });
}
</code></pre>
<h2 id="heading-step-6-nextjs-frontend-setup">Step 6 — Next.js Frontend Setup</h2>
<h3 id="heading-1-create-a-nextjs-project">1. Create a Next.js project</h3>
<pre><code class="lang-bash">npx create-next-app@latest auth-frontend
</code></pre>
<h3 id="heading-2-setup-axios-instance">2. Setup Axios instance</h3>
<pre><code class="lang-typescript"><span class="hljs-comment">// lib/axios.ts</span>
<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">const</span> api = axios.create({
  baseURL: <span class="hljs-string">'http://localhost:3000/auth'</span>,
  withCredentials: <span class="hljs-literal">true</span>,
});
</code></pre>
<h3 id="heading-3-create-login-page">3. Create Login Page</h3>
<pre><code class="lang-typescript"><span class="hljs-string">"use client"</span>;

<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { api } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/lib/axios"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Login</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [email, setEmail] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [password, setPassword] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [token, setToken] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> handleLogin = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> api.post(<span class="hljs-string">"/login"</span>, { email, password });
    setToken(res.data.accessToken);
  };

  <span class="hljs-keyword">return</span> (
    &lt;div className=<span class="hljs-string">"max-w-sm mx-auto mt-20 space-y-4"</span>&gt;
      &lt;input className=<span class="hljs-string">"border p-2 w-full"</span> placeholder=<span class="hljs-string">"Email"</span> onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setEmail(e.target.value)} /&gt;
      &lt;input className=<span class="hljs-string">"border p-2 w-full"</span> <span class="hljs-keyword">type</span>=<span class="hljs-string">"password"</span> placeholder=<span class="hljs-string">"Password"</span> onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setPassword(e.target.value)} /&gt;
      &lt;button onClick={handleLogin} className=<span class="hljs-string">"bg-red-600 text-white w-full p-2 rounded"</span>&gt;Login&lt;/button&gt;
      {token &amp;&amp; &lt;p className=<span class="hljs-string">"text-green-600 break-all"</span>&gt;Access Token: {token}&lt;/p&gt;}
    &lt;/div&gt;
  );
}
</code></pre>
<h2 id="heading-step-7-auto-refresh-token-frontend">Step 7 — Auto Refresh Token (Frontend)</h2>
<pre><code class="lang-typescript">api.interceptors.response.use(
  <span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response,
  <span class="hljs-keyword">async</span> (error) =&gt; {
    <span class="hljs-keyword">if</span> (error.response?.status === <span class="hljs-number">401</span>) {
      <span class="hljs-keyword">await</span> api.post(<span class="hljs-string">"/refresh"</span>);
      <span class="hljs-keyword">return</span> api(error.config);
    }
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(error);
  }
);
</code></pre>
<h2 id="heading-step-8-protecting-routes-in-nextjs">Step 8 — Protecting Routes in Next.js</h2>
<p>Create a custom hook:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// useAuth.ts</span>
<span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/navigation"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useAuth = <span class="hljs-function">(<span class="hljs-params">token: <span class="hljs-built_in">string</span> | <span class="hljs-literal">null</span></span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> router = useRouter();
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (!token) router.push(<span class="hljs-string">"/login"</span>);
  }, [token]);
};
</code></pre>
<p>Use it in protected pages:</p>
<pre><code class="lang-typescript"><span class="hljs-string">"use client"</span>;
<span class="hljs-keyword">import</span> { useAuth } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/hooks/useAuth"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Dashboard</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> token = <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">window</span> !== <span class="hljs-string">"undefined"</span> ? <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"accessToken"</span>) : <span class="hljs-literal">null</span>;
  useAuth(token);

  <span class="hljs-keyword">return</span> &lt;div className=<span class="hljs-string">"p-6"</span>&gt;Welcome to your dashboard 🚀&lt;/div&gt;;
}
</code></pre>
<h2 id="heading-step-9-testing-the-flow">Step 9 — Testing the Flow</h2>
<ol>
<li><p>Run your NestJS backend on port 3000</p>
</li>
<li><p>Start Next.js frontend on port 3001</p>
</li>
<li><p>Try signing up, logging in, and refreshing the page</p>
</li>
<li><p>Check that tokens are auto-refreshed and cookies are secure</p>
</li>
</ol>
<h2 id="heading-best-practices">Best Practices</h2>
<ul>
<li><p>Use <strong>HTTP-only cookies</strong> for refresh tokens</p>
</li>
<li><p>Keep <strong>short expiry</strong> for access tokens (15 min)</p>
</li>
<li><p>Rotate refresh tokens on every new login</p>
</li>
<li><p>Implement logout by deleting the refresh token in DB</p>
</li>
<li><p>In production, use <strong>HTTPS</strong> and <strong>CORS configuration</strong></p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You’ve just built a <strong>complete, secure authentication system</strong> combining the power of <strong>NestJS</strong> and <strong>Next.js</strong>.<br />This stack gives you a <strong>scalable backend</strong>, a <strong>fast frontend</strong>, and <strong>secure token-based authentication</strong> ready for production.</p>
<p>Whether you’re building a SaaS app, eCommerce site, or admin dashboard, this architecture provides a solid foundation.</p>
]]></content:encoded></item><item><title><![CDATA[Version Control and Deployment Workflow Across Development, Staging, and Production Environments]]></title><description><![CDATA[1. Environment Overview

Development (Dev):  Used by developers for active feature development and debugging. Frequent commits and experimental branches are common here.

Staging (Stg/UAT):  A replica of the production environment used for testing, Q...]]></description><link>https://techinsight.dev/version-control-and-deployment-workflow-across-development-staging-and-production-environments</link><guid isPermaLink="true">https://techinsight.dev/version-control-and-deployment-workflow-across-development-staging-and-production-environments</guid><category><![CDATA[GitHub]]></category><category><![CDATA[Git]]></category><category><![CDATA[Gitcommands]]></category><category><![CDATA[Git Version Control]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Arjun Saud]]></dc:creator><pubDate>Mon, 06 Oct 2025 17:16:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1759770864392/38f24b3c-c212-4c8c-8380-ddf483ff608d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-1-environment-overview"><strong>1. Environment Overview</strong></h3>
<ul>
<li><p><strong>Development (Dev):</strong><br />  Used by developers for active feature development and debugging. Frequent commits and experimental branches are common here.</p>
</li>
<li><p><strong>Staging (Stg/UAT):</strong><br />  A replica of the production environment used for testing, QA, and user acceptance. Only stable and reviewed code from development should be deployed here.</p>
</li>
<li><p><strong>Production (Prod):</strong><br />  The live environment accessed by end users. Only thoroughly tested and approved code should reach this stage.</p>
</li>
</ul>
<hr />
<h3 id="heading-2-git-branching-strategy"><strong>2. Git Branching Strategy</strong></h3>
<p>A common and effective branching model is <strong>Git Flow</strong> (or a simplified version of it):</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Branch</td><td>Purpose</td><td>Example</td></tr>
</thead>
<tbody>
<tr>
<td><code>main</code></td><td>Stable production-ready code</td><td>Tagged releases (e.g., <code>v1.0.0</code>)</td></tr>
<tr>
<td><code>develop</code></td><td>Ongoing development and integration branch</td><td>Features are merged here after review</td></tr>
<tr>
<td><code>feature/*</code></td><td>Individual features or fixes</td><td><code>feature/add-login</code>, <code>feature/update-api</code></td></tr>
<tr>
<td><code>release/*</code></td><td>Pre-production release candidates</td><td><code>release/1.0.0-rc</code></td></tr>
<tr>
<td><code>hotfix/*</code></td><td>Urgent fixes on production</td><td><code>hotfix/fix-login-bug</code></td></tr>
</tbody>
</table>
</div><hr />
<h3 id="heading-3-tagging-for-releases"><strong>3. Tagging for Releases</strong></h3>
<p>Use <strong>Git tags</strong> to mark stable points in history for deployment:</p>
<ul>
<li><p><strong>Development tags:</strong> <code>dev-v1.0.0</code></p>
</li>
<li><p><strong>Staging tags:</strong> <code>stg-v1.0.0</code></p>
</li>
<li><p><strong>Production tags:</strong> <code>v1.0.0</code></p>
</li>
</ul>
<p>Tags make rollbacks and deployment tracking easier.</p>
<hr />
<h3 id="heading-4-deployment-workflow"><strong>4. Deployment Workflow</strong></h3>
<p><strong>Step-by-step pipeline:</strong></p>
<ol>
<li><p><strong>Development Phase</strong></p>
<ul>
<li><p>Developers create or update feature branches.</p>
</li>
<li><p>After completion, feature branches are merged into <code>develop</code>.</p>
</li>
<li><p>Automated tests run (CI pipeline).</p>
</li>
</ul>
</li>
<li><p><strong>Staging Phase</strong></p>
<ul>
<li><p>When <code>develop</code> is stable, merge it into <code>staging</code> or create a <code>release/*</code> branch.</p>
</li>
<li><p>Apply a staging tag (<code>stg-vX.X.X</code>).</p>
</li>
<li><p>Deploy to staging environment for QA and UAT.</p>
</li>
<li><p>Fix bugs on the same branch and retag if needed.</p>
</li>
</ul>
</li>
<li><p><strong>Production Phase</strong></p>
<ul>
<li><p>Once approved, merge the release or staging branch into <code>main</code>.</p>
</li>
<li><p>Tag production release (<code>vX.X.X</code>).</p>
</li>
<li><p>Deploy to production environment using CI/CD.</p>
</li>
</ul>
</li>
<li><p><strong>Hotfix Handling</strong></p>
<ul>
<li><p>Create <code>hotfix/*</code> from <code>main</code> for urgent issues.</p>
</li>
<li><p>Merge back to both <code>main</code> and <code>develop</code> after deployment.</p>
</li>
</ul>
</li>
</ol>
<hr />
<h3 id="heading-5-cicd-integration"><strong>5. CI/CD Integration</strong></h3>
<p>Tools like <strong>GitHub Actions</strong>, <strong>GitLab CI</strong>, <strong>CircleCI</strong>, or <strong>Jenkins</strong> can automate:</p>
<ul>
<li><p>Build and test pipelines</p>
</li>
<li><p>Environment-specific deployments</p>
</li>
<li><p>Version tagging and release notes</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># Example: GitHub Actions (simplified)</span>
<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">tags:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">'v*'</span>  <span class="hljs-comment"># Deploy only on version tags</span>
<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">deploy:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">Production</span>
        <span class="hljs-attr">if:</span> <span class="hljs-string">startsWith(github.ref,</span> <span class="hljs-string">'refs/tags/v'</span><span class="hljs-string">)</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">./scripts/deploy-prod.sh</span>
</code></pre>
<hr />
<h2 id="heading-difference-between-github-tags-and-branches"><strong>Difference Between GitHub Tags and Branches</strong></h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Aspect</strong></td><td><strong>Git Branch</strong></td><td><strong>Git Tag</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Purpose</strong></td><td>A branch represents an active line of development — it moves as new commits are added.</td><td>A tag represents a fixed point in Git history — usually used to mark specific releases or milestones.</td></tr>
<tr>
<td><strong>Mutability</strong></td><td>Mutable — you can add new commits, rebase, or delete a branch.</td><td>Immutable — once created, it points to a specific commit (like a snapshot).</td></tr>
<tr>
<td><strong>Use Case</strong></td><td>Used for ongoing work such as features, bug fixes, or releases.</td><td>Used for versioning or marking releases (e.g., <code>v1.0.0</code>).</td></tr>
<tr>
<td><strong>Lifecycle</strong></td><td>Short-lived (feature branches) or long-lived (<code>main</code>, <code>develop</code>).</td><td>Permanent reference to a commit, does not change over time.</td></tr>
<tr>
<td><strong>Deployment Relevance</strong></td><td>Deployed automatically during active development (e.g., from <code>develop</code> or <code>staging</code> branches).</td><td>Used to deploy specific, stable versions (e.g., production release tags).</td></tr>
<tr>
<td><strong>Naming Convention</strong></td><td><code>main</code>, <code>develop</code>, <code>feature/add-login</code>, <code>release/1.0.0</code></td><td><code>v1.0.0</code>, <code>stg-v1.0.0</code>, <code>dev-v1.0.0-alpha</code></td></tr>
<tr>
<td><strong>Visibility</strong></td><td>Appears in branch lists and can be merged into other branches.</td><td>Appears in releases or tags list, not part of merge workflows.</td></tr>
<tr>
<td><strong>Typical Command</strong></td><td><code>git checkout -b feature/login</code></td><td><code>git tag v1.0.0</code></td></tr>
<tr>
<td><strong>Example Use in Workflow</strong></td><td>Work on new feature → merge to <code>develop</code> → test → merge to <code>main</code>.</td><td>After merging to <code>main</code>, create tag <code>v1.0.0</code> for production release.</td></tr>
</tbody>
</table>
</div><h3 id="heading-in-simple-terms"><strong>In Simple Terms</strong></h3>
<ul>
<li><p><strong>Branches = active workspaces.</strong><br />  You build and update features or fixes here.</p>
</li>
<li><p><strong>Tags = version markers.</strong><br />  You freeze and label code at a specific state — often for release, rollback, or audit purposes.</p>
</li>
</ul>
<hr />
<h3 id="heading-example-combined-use"><strong>Example: Combined Use</strong></h3>
<pre><code class="lang-yaml"><span class="hljs-comment"># Developer workflow</span>
<span class="hljs-string">git</span> <span class="hljs-string">checkout</span> <span class="hljs-string">-b</span> <span class="hljs-string">feature/login</span>
<span class="hljs-comment"># ...work, commit, merge to develop...</span>

<span class="hljs-comment"># Merge develop → main after testing</span>
<span class="hljs-string">git</span> <span class="hljs-string">checkout</span> <span class="hljs-string">main</span>
<span class="hljs-string">git</span> <span class="hljs-string">merge</span> <span class="hljs-string">develop</span>

<span class="hljs-comment"># Create a production release tag</span>
<span class="hljs-string">git</span> <span class="hljs-string">tag</span> <span class="hljs-string">-a</span> <span class="hljs-string">v1.0.0</span> <span class="hljs-string">-m</span> <span class="hljs-string">"Production release 1.0.0"</span>
<span class="hljs-string">git</span> <span class="hljs-string">push</span> <span class="hljs-string">origin</span> <span class="hljs-string">v1.0.0</span>
</code></pre>
<p>This marks the <strong>exact commit</strong> that was deployed to production — making version tracking and rollback easy.</p>
<hr />
<h2 id="heading-when-to-use-branches-vs-tags"><strong>When to Use Branches vs Tags</strong></h2>
<h3 id="heading-1-use-branches-when"><strong>1. Use Branches When…</strong></h3>
<p>Branches are for <strong>active, changeable work</strong> — anything that’s still being developed, tested, or reviewed.</p>
<h4 id="heading-typical-scenarios">✅ <strong>Typical Scenarios</strong></h4>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Situation</td><td>Example</td><td>Why a Branch</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Developing a new feature</strong></td><td><code>feature/add-payment-gateway</code></td><td>You’re still coding, may need reviews and commits.</td></tr>
<tr>
<td><strong>Fixing a bug</strong></td><td><code>bugfix/fix-login-error</code></td><td>You need a temporary workspace for changes.</td></tr>
<tr>
<td><strong>Preparing a new release</strong></td><td><code>release/1.2.0</code></td><td>You’re stabilizing a version before tagging it for production.</td></tr>
<tr>
<td><strong>Environment-specific deployment</strong></td><td></td></tr>
</tbody>
</table>
</div><h4 id="heading-tip">💡 <strong>Tip:</strong></h4>
<p>Branches are <em>living lines of development</em> — they evolve and are meant to be merged or deleted after use.</p>
<hr />
<h3 id="heading-2-use-tags-when"><strong>2. Use Tags When…</strong></h3>
<p>Tags are for <strong>marking stable, completed states</strong> of your repository — snapshots that should never change.</p>
<h4 id="heading-typical-scenarios-1">✅ <strong>Typical Scenarios</strong></h4>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Situation</td><td>Example</td><td>Why a Tag</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Marking a production release</strong></td><td><code>v1.0.0</code></td><td>You want to identify exactly what version went live.</td></tr>
<tr>
<td><strong>Marking a staging build</strong></td><td><code>stg-v1.0.0-beta</code></td><td>To record what was tested before production.</td></tr>
<tr>
<td><strong>Versioning historical milestones</strong></td><td><code>v0.9.0</code>, <code>v2.0.0</code></td><td>For rollback or audit purposes.</td></tr>
<tr>
<td><strong>Archiving old code states</strong></td><td><code>legacy-v0.5</code></td><td>To reference a specific snapshot that won’t change.</td></tr>
</tbody>
</table>
</div><h4 id="heading-tip-1">💡 <strong>Tip:</strong></h4>
<p>Tags are <em>immutable labels</em> — perfect for releases, audits, and deployments.</p>
<h3 id="heading-3-real-world-example-development-staging-production"><strong>3. Real-World Example: Development → Staging → Production</strong></h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Stage</td><td>Use Branch</td><td>Use Tag</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Development</strong></td><td>Work on <code>feature/*</code> → merge into <code>develop</code></td><td>Optional (e.g., <code>dev-v1.0.0</code> for internal test builds)</td></tr>
<tr>
<td><strong>Staging / UAT</strong></td><td>Merge <code>develop</code> → <code>staging</code></td><td>Tag as <code>stg-v1.0.0</code> after testing</td></tr>
<tr>
<td>Production</td><td>Merge <code>staging</code> → <code>main</code></td><td>Tag as <code>v1.0.0</code> for deployment and version record</td></tr>
</tbody>
</table>
</div><hr />
<h3 id="heading-4-in-summary"><strong>4. In Summary</strong></h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Purpose</td><td>Use</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>Ongoing development</td><td><strong>Branch</strong></td><td>To work on changes without affecting main code</td></tr>
<tr>
<td>Team collaboration</td><td><strong>Branch</strong></td><td>Each developer can work independently</td></tr>
<tr>
<td>Release or deployment version</td><td><strong>Tag</strong></td><td>To mark a commit as a fixed, released version</td></tr>
<tr>
<td>Rollback or audit</td><td><strong>Tag</strong></td><td>To know exactly what code was deployed</td></tr>
</tbody>
</table>
</div>]]></content:encoded></item></channel></rss>