<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shitanshu Jha</title>
    <description>The latest articles on DEV Community by Shitanshu Jha (@shitanshu686).</description>
    <link>https://dev.to/shitanshu686</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4089061%2Fdf0bb2f6-2ea8-4a39-acbf-b290296a5e68.jpg</url>
      <title>DEV Community: Shitanshu Jha</title>
      <link>https://dev.to/shitanshu686</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shitanshu686"/>
    <language>en</language>
    <item>
      <title>ShopEase — Module 32: Concurrency, Multithreading &amp; Database Locking</title>
      <dc:creator>Shitanshu Jha</dc:creator>
      <pubDate>Sun, 04 Oct 2026 02:58:16 +0000</pubDate>
      <link>https://dev.to/shitanshu686/shopease-module-32-concurrency-multithreading-database-locking-82g</link>
      <guid>https://dev.to/shitanshu686/shopease-module-32-concurrency-multithreading-database-locking-82g</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3jkwk2t3spc2vjj1yds2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3jkwk2t3spc2vjj1yds2.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;As ShopEase moved toward a more production-oriented backend, one important problem needed to be solved:&lt;/p&gt;

&lt;p&gt;What happens when multiple users try to purchase the same product at exactly the same time?&lt;/p&gt;

&lt;p&gt;In a normal single-user test, stock deduction looks simple. But in a real e-commerce system, multiple requests can reach the backend simultaneously and try to update the same inventory.&lt;/p&gt;

&lt;p&gt;That creates a serious problem: overselling.&lt;/p&gt;

&lt;p&gt;For Module 32, I focused on multithreading, concurrent stock updates, optimistic locking, pessimistic locking, and atomic stock deduction.&lt;/p&gt;

&lt;p&gt;⚡ The Problem: Concurrent Stock Updates&lt;/p&gt;

&lt;p&gt;Suppose a product has:&lt;/p&gt;

&lt;p&gt;Stock = 10&lt;/p&gt;

&lt;p&gt;Now imagine 50 users trying to purchase that product simultaneously.&lt;/p&gt;

&lt;p&gt;Without proper concurrency control, multiple threads could read the same stock value before any of them updates it.&lt;/p&gt;

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

&lt;p&gt;Thread 1 → reads stock = 1&lt;br&gt;
Thread 2 → reads stock = 1&lt;/p&gt;

&lt;p&gt;Thread 1 → deducts stock&lt;br&gt;
Thread 2 → deducts stock&lt;/p&gt;

&lt;p&gt;Both threads may believe that the product is available.&lt;/p&gt;

&lt;p&gt;This is a classic race condition, and in an e-commerce system it can result in selling more units than actually exist.&lt;/p&gt;

&lt;p&gt;🧵 Multithreading &amp;amp; Stress Testing&lt;/p&gt;

&lt;p&gt;To reproduce this situation instead of relying on normal sequential testing, I introduced concurrent stress testing.&lt;/p&gt;

&lt;p&gt;I used 50 concurrent threads attempting to perform stock-related operations.&lt;/p&gt;

&lt;p&gt;The purpose wasn't simply to make multiple threads run at once.&lt;/p&gt;

&lt;p&gt;The real objective was to verify whether the database and application could correctly handle simultaneous requests accessing the same inventory.&lt;/p&gt;

&lt;p&gt;This made the concurrency problem much easier to observe and debug.&lt;/p&gt;

&lt;p&gt;🔒 Pessimistic Locking&lt;/p&gt;

&lt;p&gt;For pessimistic locking, I implemented:&lt;/p&gt;

&lt;p&gt;LockModeType.PESSIMISTIC_WRITE&lt;/p&gt;

&lt;p&gt;in the ProductRepository.&lt;/p&gt;

&lt;p&gt;The idea is straightforward:&lt;/p&gt;

&lt;p&gt;When one transaction is modifying a product row, other transactions shouldn't be allowed to simultaneously modify that same row.&lt;/p&gt;

&lt;p&gt;I also configured the MariaDB dialect so Hibernate could generate the appropriate database-level row locking behavior using FOR UPDATE.&lt;/p&gt;

&lt;p&gt;Conceptually, the flow becomes:&lt;/p&gt;

&lt;p&gt;Transaction 1&lt;br&gt;
     ↓&lt;br&gt;
Lock Product Row&lt;br&gt;
     ↓&lt;br&gt;
Check Stock&lt;br&gt;
     ↓&lt;br&gt;
Deduct Stock&lt;br&gt;
     ↓&lt;br&gt;
Commit&lt;br&gt;
     ↓&lt;br&gt;
Release Lock&lt;/p&gt;

&lt;p&gt;Another transaction attempting to modify the same row has to wait until the existing lock is released.&lt;/p&gt;

&lt;p&gt;This provides strong protection for critical inventory updates.&lt;/p&gt;

&lt;p&gt;🧠 Optimistic Locking&lt;/p&gt;

&lt;p&gt;I also tested optimistic locking using JPA's:&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/version"&gt;@version&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of immediately locking the database row, optimistic locking assumes that conflicts are relatively uncommon.&lt;/p&gt;

&lt;p&gt;Each update checks whether the entity version is still the expected version.&lt;/p&gt;

&lt;p&gt;If another transaction has already modified the row, the version changes and the conflicting update can be detected.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;p&gt;Thread 1 → Version 5 → Update → Version 6 ✅&lt;/p&gt;

&lt;p&gt;Thread 2 → Version 5 → Update&lt;br&gt;
                    ↓&lt;br&gt;
              Version mismatch ❌&lt;/p&gt;

&lt;p&gt;This approach is useful when you want to detect concurrent modifications without holding database locks throughout the transaction.&lt;/p&gt;

&lt;p&gt;🛡️ Atomic Stock Deduction&lt;/p&gt;

&lt;p&gt;Locking alone isn't the complete solution.&lt;/p&gt;

&lt;p&gt;The actual stock operation also needs to be handled carefully so that the availability check and deduction happen safely within the transaction.&lt;/p&gt;

&lt;p&gt;The goal was:&lt;/p&gt;

&lt;p&gt;Check stock&lt;br&gt;
    ↓&lt;br&gt;
Stock available?&lt;br&gt;
    ↓&lt;br&gt;
Atomic deduction&lt;br&gt;
    ↓&lt;br&gt;
Commit&lt;/p&gt;

&lt;p&gt;If sufficient stock isn't available, the purchase must fail rather than allowing the stock value to become invalid.&lt;/p&gt;

&lt;p&gt;🧪 50-Thread Concurrent Testing&lt;/p&gt;

&lt;p&gt;After implementing both approaches, I performed concurrent testing with 50 threads.&lt;/p&gt;

&lt;p&gt;The tests were used to verify:&lt;/p&gt;

&lt;p&gt;Concurrent access to the same product&lt;br&gt;
Optimistic locking conflicts&lt;br&gt;
Pessimistic row locking&lt;br&gt;
Atomic stock deduction&lt;br&gt;
Collision handling&lt;br&gt;
Prevention of negative stock&lt;br&gt;
Prevention of overselling&lt;/p&gt;

&lt;p&gt;The final result was zero overselling during the concurrent stress tests.&lt;/p&gt;

&lt;p&gt;🔍 What I Learned&lt;/p&gt;

&lt;p&gt;This module changed the way I think about backend development.&lt;/p&gt;

&lt;p&gt;A piece of code can work perfectly when one request executes at a time and still fail when multiple requests execute simultaneously.&lt;/p&gt;

&lt;p&gt;Concurrency introduces problems such as:&lt;/p&gt;

&lt;p&gt;Race conditions&lt;br&gt;
Lost updates&lt;br&gt;
Concurrent modification conflicts&lt;br&gt;
Database locking&lt;br&gt;
Transaction boundaries&lt;br&gt;
Thread synchronization&lt;/p&gt;

&lt;p&gt;The important lesson was:&lt;/p&gt;

&lt;p&gt;Correctness in a backend isn't only about what happens during one request. It's also about what happens when many requests happen at the same time.&lt;/p&gt;

&lt;p&gt;Module 32 gave ShopEase practical protection against one of the most important problems in e-commerce systems: selling inventory that doesn't actually exist.&lt;/p&gt;

&lt;p&gt;Tech Stack&lt;/p&gt;

&lt;p&gt;Java • Spring Boot • Spring Data JPA • Hibernate • MariaDB • Multithreading • Optimistic Locking • Pessimistic Locking • Transactions&lt;/p&gt;

&lt;h1&gt;
  
  
  Java #SpringBoot #Concurrency #Multithreading #Database #Hibernate #MariaDB #JPA #OptimisticLocking #PessimisticLocking #BackendDevelopment #ShopEase
&lt;/h1&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>concurrency</category>
      <category>multithreading</category>
    </item>
    <item>
      <title>ShopEase: Advanced Backend Features with Webhooks, GraphQL, gRPC &amp; Load Balancing</title>
      <dc:creator>Shitanshu Jha</dc:creator>
      <pubDate>Sat, 03 Oct 2026 15:28:16 +0000</pubDate>
      <link>https://dev.to/shitanshu686/shopease-advanced-backend-features-with-webhooks-graphql-grpc-load-balancing-j4h</link>
      <guid>https://dev.to/shitanshu686/shopease-advanced-backend-features-with-webhooks-graphql-grpc-load-balancing-j4h</guid>
      <description>&lt;p&gt;In Modules 30.12–30.15, I worked on four advanced backend concepts:&lt;/p&gt;

&lt;p&gt;💳 Payment Webhooks&lt;br&gt;
🔎 GraphQL Integration&lt;br&gt;
⚡ gRPC Communication&lt;br&gt;
⚖️ Load Balancing&lt;/p&gt;

&lt;p&gt;These modules helped me understand how real-world backend systems handle payment events, flexible data fetching, high-performance service communication, and distributed traffic.&lt;/p&gt;

&lt;p&gt;💳 Module 30.12 — Payment Webhooks&lt;/p&gt;

&lt;p&gt;Payment processing doesn't end when a user completes a payment.&lt;/p&gt;

&lt;p&gt;A payment provider can send asynchronous updates about events such as payment success, failure, or other payment-status changes.&lt;/p&gt;

&lt;p&gt;For ShopEase, I implemented the payment webhook flow using Razorpay, including:&lt;/p&gt;

&lt;p&gt;Webhook endpoint&lt;br&gt;
Payment event handling&lt;br&gt;
Webhook signature verification&lt;br&gt;
Payment success/failure processing&lt;br&gt;
Idempotent webhook handling&lt;/p&gt;

&lt;p&gt;One of the important challenges here was avoiding duplicate processing.&lt;/p&gt;

&lt;p&gt;A webhook can potentially be delivered more than once, so the backend needs to make sure the same payment event doesn't accidentally update an order multiple times.&lt;/p&gt;

&lt;p&gt;This introduced an important production concept:&lt;/p&gt;

&lt;p&gt;Receiving an event is not enough — the system must process it safely.&lt;/p&gt;

&lt;p&gt;🔎 Module 30.13 — GraphQL Integration&lt;/p&gt;

&lt;p&gt;The next challenge was handling situations where clients don't always need the complete response returned by a traditional REST endpoint.&lt;/p&gt;

&lt;p&gt;I integrated GraphQL into ShopEase to understand a different approach to API communication.&lt;/p&gt;

&lt;p&gt;With GraphQL, the client can request the specific fields it needs instead of depending entirely on predefined response structures.&lt;/p&gt;

&lt;p&gt;This helped me understand concepts such as:&lt;/p&gt;

&lt;p&gt;Queries&lt;br&gt;
Mutations&lt;br&gt;
Schemas&lt;br&gt;
Resolvers&lt;br&gt;
Flexible data fetching&lt;/p&gt;

&lt;p&gt;The main learning was understanding the difference between simply creating an API and designing an API that gives the client more control over the requested data.&lt;/p&gt;

&lt;p&gt;⚡ Module 30.14 — gRPC Communication&lt;/p&gt;

&lt;p&gt;For service-to-service communication, I also explored gRPC.&lt;/p&gt;

&lt;p&gt;Unlike traditional REST communication, gRPC uses Protocol Buffers and is designed for efficient communication between distributed services.&lt;/p&gt;

&lt;p&gt;I worked with concepts including:&lt;/p&gt;

&lt;p&gt;gRPC services&lt;br&gt;
Protocol Buffers&lt;br&gt;
Service definitions&lt;br&gt;
Client-server communication&lt;br&gt;
Internal microservice communication&lt;/p&gt;

&lt;p&gt;One of the challenges was understanding the complete flow:&lt;/p&gt;

&lt;p&gt;Client → Stub → gRPC Service → Response&lt;/p&gt;

&lt;p&gt;This gave me a practical understanding of why technologies such as gRPC can be useful for communication between internal microservices.&lt;/p&gt;

&lt;p&gt;⚖️ Module 30.15 — Load Balancing&lt;/p&gt;

&lt;p&gt;As the number of services and requests increases, sending every request to a single instance can become a bottleneck.&lt;/p&gt;

&lt;p&gt;That's where load balancing becomes important.&lt;/p&gt;

&lt;p&gt;In this module, I worked with the concept of distributing incoming requests across multiple service instances.&lt;/p&gt;

&lt;p&gt;The basic flow becomes:&lt;/p&gt;

&lt;p&gt;Client → Load Balancer → Service Instance&lt;/p&gt;

&lt;p&gt;instead of:&lt;/p&gt;

&lt;p&gt;Client → Single Service Instance&lt;/p&gt;

&lt;p&gt;This introduced concepts around:&lt;/p&gt;

&lt;p&gt;Multiple service instances&lt;br&gt;
Request distribution&lt;br&gt;
Service discovery&lt;br&gt;
Scalability&lt;br&gt;
Handling increased traffic&lt;/p&gt;

&lt;p&gt;The biggest takeaway was that scalability isn't simply about making one server more powerful. A distributed system can instead use multiple instances and distribute the workload between them.&lt;/p&gt;

&lt;p&gt;🧠 What These Modules Taught Me&lt;/p&gt;

&lt;p&gt;Modules 30.12–30.15 moved ShopEase beyond basic backend development and into more advanced distributed-system concepts.&lt;/p&gt;

&lt;p&gt;I worked with four different problems:&lt;/p&gt;

&lt;p&gt;Problem Technology&lt;br&gt;
Handling asynchronous payment updates   Razorpay Webhooks&lt;br&gt;
Flexible API data fetching  GraphQL&lt;br&gt;
Efficient service communication gRPC&lt;br&gt;
Distributing traffic across instances   Load Balancing&lt;/p&gt;

&lt;p&gt;Each technology solved a different problem, but together they helped me understand an important part of backend engineering:&lt;/p&gt;

&lt;p&gt;A production-ready backend isn't just about making features work. It's also about how the system communicates, handles failures, processes events, and scales under load.&lt;/p&gt;

&lt;p&gt;There is still more to explore in ShopEase, particularly around deployment, concurrency, fault tolerance, monitoring, and production configuration.&lt;/p&gt;

&lt;p&gt;But completing these modules was another significant step in turning ShopEase from a simple e-commerce backend into a more scalable and distributed system.&lt;/p&gt;

&lt;p&gt;Tech Stack&lt;/p&gt;

&lt;p&gt;Java • Spring Boot • Microservices • Razorpay • GraphQL • gRPC • Protocol Buffers • Load Balancing&lt;/p&gt;

&lt;h1&gt;
  
  
  Java #SpringBoot #Microservices #GraphQL #gRPC #Razorpay #BackendDevelopment #ShopEase #DistributedSystems #Scalability
&lt;/h1&gt;

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

</description>
      <category>java</category>
      <category>springboot</category>
      <category>microservices</category>
      <category>graphql</category>
    </item>
    <item>
      <title>Module 30.11 — Microservices Integration &amp; Testing | ShopEase</title>
      <dc:creator>Shitanshu Jha</dc:creator>
      <pubDate>Sat, 03 Oct 2026 15:12:37 +0000</pubDate>
      <link>https://dev.to/shitanshu686/module-3011-microservices-integration-testing-shopease-5coc</link>
      <guid>https://dev.to/shitanshu686/module-3011-microservices-integration-testing-shopease-5coc</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqukw4daxv4y18qvawd6m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqukw4daxv4y18qvawd6m.png" alt=" " width="620" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>shopease</category>
      <category>microservices</category>
      <category>kafka</category>
      <category>springboot</category>
    </item>
    <item>
      <title>💳 Implementing Razorpay Webhooks in Spring Boot 🚀 Real Problems I Faced &amp; How I Solved Them</title>
      <dc:creator>Shitanshu Jha</dc:creator>
      <pubDate>Tue, 15 Sep 2026 04:53:59 +0000</pubDate>
      <link>https://dev.to/shitanshu686/implementing-razorpay-webhooks-in-spring-boot-real-problems-i-faced-how-i-solved-them-2gg8</link>
      <guid>https://dev.to/shitanshu686/implementing-razorpay-webhooks-in-spring-boot-real-problems-i-faced-how-i-solved-them-2gg8</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1gj4576n2nbdckpsg3vl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1gj4576n2nbdckpsg3vl.png" alt=" " width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Building a payment integration is easy in a tutorial.&lt;br&gt;
Making it actually work is where the real engineering begins. 😅&lt;/p&gt;

&lt;p&gt;While working on my ShopEase e-commerce project, I reached a point where payment creation and verification were already working. The next challenge was handling Razorpay Webhooks and processing payment events asynchronously.&lt;/p&gt;

&lt;p&gt;🏗️ My Payment Architecture&lt;/p&gt;

&lt;p&gt;ShopEase uses a microservices-based backend, with a separate payment-service running on port 8085.&lt;/p&gt;

&lt;p&gt;🔄 Before Webhooks&lt;br&gt;
🛒 Frontend&lt;br&gt;
     ↓&lt;br&gt;
🌐 API Gateway&lt;br&gt;
     ↓&lt;br&gt;
💳 Payment Service&lt;br&gt;
     ↓&lt;br&gt;
💰 Razorpay&lt;br&gt;
⚡ After Adding Webhooks&lt;br&gt;
💰 Razorpay&lt;br&gt;
     ↓&lt;br&gt;
🔔 Webhook&lt;br&gt;
     ↓&lt;br&gt;
💳 Payment Service&lt;br&gt;
     ↓&lt;br&gt;
🔐 Verify Signature&lt;br&gt;
     ↓&lt;br&gt;
🔎 Identify Event&lt;br&gt;
     ↓&lt;br&gt;
🗄️ Update Payment&lt;br&gt;
     ↓&lt;br&gt;
💾 Store Event ID&lt;br&gt;
😵‍💫 Challenge #1 — Duplicate Webhooks&lt;/p&gt;

&lt;p&gt;One of the first things I realized was that a webhook may be delivered more than once.&lt;/p&gt;

&lt;p&gt;If I process the same event twice, I could accidentally execute the same business logic multiple times.&lt;/p&gt;

&lt;p&gt;So I introduced a webhook_events table and stored the webhook's eventId.&lt;/p&gt;

&lt;p&gt;🔐 Why?&lt;br&gt;
Webhook received&lt;br&gt;
      ↓&lt;br&gt;
Already processed?&lt;br&gt;
   ↙       ↘&lt;br&gt;
 YES        NO&lt;br&gt;
  ↓          ↓&lt;br&gt;
Ignore     Process&lt;br&gt;
             ↓&lt;br&gt;
        Save Event ID&lt;/p&gt;

&lt;p&gt;This gave my webhook processing idempotency.&lt;/p&gt;

&lt;p&gt;🔑 Challenge #2 — Webhook Secret ≠ API Secret&lt;/p&gt;

&lt;p&gt;This one was important.&lt;/p&gt;

&lt;p&gt;I learned that the Razorpay Webhook Secret is different from the Razorpay API Key Secret.&lt;/p&gt;

&lt;p&gt;Instead of hardcoding the secret, I kept it in an environment variable:&lt;/p&gt;

&lt;p&gt;razorpay.webhook.secret=${RAZORPAY_WEBHOOK_SECRET}&lt;/p&gt;

&lt;p&gt;🔒 Never put actual secrets directly into your GitHub repository.&lt;/p&gt;

&lt;p&gt;🛡️ Challenge #3 — Verifying the Webhook Signature&lt;/p&gt;

&lt;p&gt;I couldn't simply trust every request that reached my endpoint.&lt;/p&gt;

&lt;p&gt;The request contains:&lt;/p&gt;

&lt;p&gt;X-Razorpay-Signature&lt;/p&gt;

&lt;p&gt;I used Razorpay's signature verification mechanism with the raw request payload and my webhook secret.&lt;/p&gt;

&lt;p&gt;📨 Incoming Request&lt;br&gt;
        ↓&lt;br&gt;
🔐 Extract Signature&lt;br&gt;
        ↓&lt;br&gt;
🧮 Generate/Verify HMAC&lt;br&gt;
        ↓&lt;br&gt;
   Valid? ────── No → ❌ Reject&lt;br&gt;
        ↓&lt;br&gt;
       Yes&lt;br&gt;
        ↓&lt;br&gt;
     ✅ Process&lt;br&gt;
🚫 Challenge #4 — The Mysterious 403 Forbidden&lt;/p&gt;

&lt;p&gt;This was one of those errors where I initially thought:&lt;/p&gt;

&lt;p&gt;"Controller mein hi kuch problem hai." 😅&lt;/p&gt;

&lt;p&gt;But the controller wasn't the problem.&lt;/p&gt;

&lt;p&gt;Spring Security was blocking the request.&lt;/p&gt;

&lt;p&gt;My normal APIs require authentication, but Razorpay's webhook doesn't have my application's JWT.&lt;/p&gt;

&lt;p&gt;So I specifically permitted:&lt;/p&gt;

&lt;p&gt;.requestMatchers("/payments/webhook").permitAll()&lt;/p&gt;

&lt;p&gt;and disabled CSRF for the API.&lt;/p&gt;

&lt;p&gt;💡 Lesson&lt;/p&gt;

&lt;p&gt;A perfectly written controller is useless if security blocks the request before it reaches the controller.&lt;/p&gt;

&lt;p&gt;🧪 Challenge #5 — Testing Without Razorpay&lt;/p&gt;

&lt;p&gt;While testing locally through Postman, I initially didn't have the real Razorpay signature.&lt;/p&gt;

&lt;p&gt;A fake signature such as:&lt;/p&gt;

&lt;p&gt;test-signature&lt;/p&gt;

&lt;p&gt;correctly resulted in:&lt;/p&gt;

&lt;p&gt;401 Unauthorized&lt;/p&gt;

&lt;p&gt;And honestly, that was good news. 😂&lt;/p&gt;

&lt;p&gt;It meant my signature verification was actually doing its job.&lt;/p&gt;

&lt;p&gt;So I created a Postman Pre-request Script to generate the HMAC-SHA256 signature automatically whenever I changed the webhook payload.&lt;/p&gt;

&lt;p&gt;🫠 Challenge #6 — "Payment Record Not Found"&lt;/p&gt;

&lt;p&gt;This was probably one of my most interesting debugging moments.&lt;/p&gt;

&lt;p&gt;The signature was valid ✅&lt;br&gt;
The event was recognized ✅&lt;/p&gt;

&lt;p&gt;But:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "success": false,&lt;br&gt;
  "message": "Payment record not found"&lt;br&gt;
}&lt;br&gt;
🔍 Root Cause&lt;/p&gt;

&lt;p&gt;The Razorpay Order ID didn't match the Order ID stored in my database.&lt;/p&gt;

&lt;p&gt;It was literally a tiny character difference. 😭&lt;/p&gt;

&lt;p&gt;Postman:&lt;br&gt;
order_TT9CFIQhKkyXwR&lt;/p&gt;

&lt;p&gt;Database:&lt;br&gt;
order_TT9CFlQkHkyXwR&lt;/p&gt;

&lt;p&gt;For humans, they look almost identical.&lt;/p&gt;

&lt;p&gt;For a database?&lt;/p&gt;

&lt;p&gt;Completely different values. 💀&lt;/p&gt;

&lt;p&gt;After correcting the Order ID, the webhook successfully found the payment.&lt;/p&gt;

&lt;p&gt;🐳 Challenge #7 — XAMPP vs Docker MySQL&lt;/p&gt;

&lt;p&gt;This one caused a lot of confusion.&lt;/p&gt;

&lt;p&gt;My application was using:&lt;/p&gt;

&lt;p&gt;localhost:3308&lt;/p&gt;

&lt;p&gt;while I was checking MySQL through XAMPP/phpMyAdmin on:&lt;/p&gt;

&lt;p&gt;localhost:3306&lt;/p&gt;

&lt;p&gt;I eventually discovered that port 3308 was actually mapped to my Docker MySQL container:&lt;/p&gt;

&lt;p&gt;Windows :3308&lt;br&gt;
      ↓&lt;br&gt;
🐳 Docker&lt;br&gt;
      ↓&lt;br&gt;
MySQL :3306&lt;/p&gt;

&lt;p&gt;The container was:&lt;/p&gt;

&lt;p&gt;shopease-mysql&lt;br&gt;
mysql:8.4&lt;br&gt;
0.0.0.0:3308 → 3306&lt;/p&gt;

&lt;p&gt;So instead of trying to move XAMPP to port 3308, I connected directly to the Docker MySQL container.&lt;/p&gt;

&lt;p&gt;🧠 Biggest Lesson Here&lt;/p&gt;

&lt;p&gt;Before changing a port, first find out which process is already using it.&lt;/p&gt;

&lt;p&gt;✅ Testing payment.captured&lt;/p&gt;

&lt;p&gt;After fixing the database issue, I tested:&lt;/p&gt;

&lt;p&gt;payment.captured&lt;/p&gt;

&lt;p&gt;The webhook returned:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "success": true,&lt;br&gt;
  "message": "Webhook signature verified",&lt;br&gt;
  "event": "payment.captured"&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;with:&lt;/p&gt;

&lt;p&gt;HTTP 200 OK&lt;/p&gt;

&lt;p&gt;More importantly, I didn't stop at the API response.&lt;/p&gt;

&lt;p&gt;I checked the database and confirmed:&lt;/p&gt;

&lt;p&gt;CREATED&lt;br&gt;
   ↓&lt;br&gt;
SUCCESS&lt;/p&gt;

&lt;p&gt;That confirmed the actual business logic worked, not just the HTTP response.&lt;/p&gt;

&lt;p&gt;🔁 Testing Idempotency&lt;/p&gt;

&lt;p&gt;Then came the real test.&lt;/p&gt;

&lt;p&gt;I sent the exact same webhook again using the same event ID.&lt;/p&gt;

&lt;p&gt;Instead of processing it again, the application returned:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "success": true,&lt;br&gt;
  "message": "Webhook already processed",&lt;br&gt;
  "event": "payment.captured"&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;🎯 Duplicate processing successfully prevented!&lt;/p&gt;

&lt;p&gt;❌ Testing payment.failed&lt;/p&gt;

&lt;p&gt;I also tested:&lt;/p&gt;

&lt;p&gt;payment.failed&lt;/p&gt;

&lt;p&gt;The webhook was successfully processed and the database payment status changed to:&lt;/p&gt;

&lt;p&gt;FAILED&lt;/p&gt;

&lt;p&gt;So both major payment events were working:&lt;/p&gt;

&lt;p&gt;Event   Result&lt;br&gt;
💰 payment.captured   ✅ SUCCESS&lt;br&gt;
❌ payment.failed  ✅ FAILED&lt;br&gt;
🔁 Duplicate event    ✅ Blocked&lt;br&gt;
🔐 Invalid signature  ✅ Rejected&lt;/p&gt;

&lt;p&gt;🏁 Final Architecture&lt;br&gt;
                    💰 Razorpay&lt;br&gt;
                         │&lt;br&gt;
                         │ 🔔 Webhook&lt;br&gt;
                         ↓&lt;br&gt;
                POST /payments/webhook&lt;br&gt;
                         │&lt;br&gt;
                         ↓&lt;br&gt;
                🛡️ Spring Security&lt;br&gt;
                         │&lt;br&gt;
                         ↓&lt;br&gt;
                🔐 Signature Check&lt;br&gt;
                         │&lt;br&gt;
                         ↓&lt;br&gt;
                 🔎 Event Detection&lt;br&gt;
                    ↙           ↘&lt;br&gt;
           payment.captured   payment.failed&lt;br&gt;
                  ↓                 ↓&lt;br&gt;
             Find Payment      Find Payment&lt;br&gt;
                  ↓                 ↓&lt;br&gt;
               SUCCESS           FAILED&lt;br&gt;
                    ↘           ↙&lt;br&gt;
                         ↓&lt;br&gt;
                  🔁 Check Event ID&lt;br&gt;
                         ↓&lt;br&gt;
                  Already Processed?&lt;br&gt;
                    ↙          ↘&lt;br&gt;
                  YES           NO&lt;br&gt;
                   ↓             ↓&lt;br&gt;
                Ignore       💾 Save Event&lt;br&gt;
                                 ↓&lt;br&gt;
                              ✅ 200 OK&lt;/p&gt;

&lt;p&gt;🧠 What This Actually Taught Me&lt;/p&gt;

&lt;p&gt;The biggest lesson wasn't just "how to implement Razorpay Webhooks."&lt;/p&gt;

&lt;p&gt;It was learning how to debug a complete backend system.&lt;/p&gt;

&lt;p&gt;🔐 1. Security matters&lt;/p&gt;

&lt;p&gt;A controller can't help if Spring Security blocks the request.&lt;/p&gt;

&lt;p&gt;🎯 2. IDs must match exactly&lt;/p&gt;

&lt;p&gt;A single character difference can break a database lookup.&lt;/p&gt;

&lt;p&gt;🐳 3. Understand your infrastructure&lt;/p&gt;

&lt;p&gt;Docker port mapping can completely change where your application is actually connecting.&lt;/p&gt;

&lt;p&gt;🔁 4. Webhooks must be idempotent&lt;/p&gt;

&lt;p&gt;The same event shouldn't execute your business logic multiple times.&lt;/p&gt;

&lt;p&gt;🗄️ 5. Verify the database&lt;/p&gt;

&lt;p&gt;200 OK doesn't necessarily mean your business logic worked.&lt;/p&gt;

&lt;p&gt;🐛 6. Debugging is part of development&lt;br&gt;
💻 Code&lt;br&gt;
   ↓&lt;br&gt;
🧪 Test&lt;br&gt;
   ↓&lt;br&gt;
❌ Error&lt;br&gt;
   ↓&lt;br&gt;
🔎 Find Root Cause&lt;br&gt;
   ↓&lt;br&gt;
🔧 Fix&lt;br&gt;
   ↓&lt;br&gt;
🧪 Test Again&lt;br&gt;
   ↓&lt;br&gt;
🗄️ Verify Database&lt;br&gt;
   ↓&lt;br&gt;
✅ Done&lt;/p&gt;

&lt;p&gt;🚀 Current Status&lt;/p&gt;

&lt;p&gt;My Razorpay Webhook implementation currently supports:&lt;/p&gt;

&lt;p&gt;✅ Webhook endpoint&lt;br&gt;
✅ Signature verification&lt;br&gt;
✅ payment.captured&lt;br&gt;
✅ payment.failed&lt;br&gt;
✅ Payment status updates&lt;br&gt;
✅ Duplicate webhook detection&lt;br&gt;
✅ Idempotent processing&lt;br&gt;
✅ Database verification&lt;/p&gt;

&lt;p&gt;The next step is to extend the webhook flow beyond payment status updates and connect it with the complete post-payment business logic, such as order confirmation and cart clearing.&lt;/p&gt;

&lt;p&gt;💡 Final Takeaway&lt;/p&gt;

&lt;p&gt;Implementing Razorpay Webhooks taught me something important:&lt;/p&gt;

&lt;p&gt;Real-world backend development isn't just about writing code. It's about understanding what happens when that code meets security, databases, infrastructure, external APIs, and unexpected errors.&lt;/p&gt;

&lt;p&gt;The most valuable part of this implementation wasn't simply making the webhook work.&lt;/p&gt;

&lt;p&gt;It was debugging:&lt;/p&gt;

&lt;p&gt;403 errors → invalid signatures → incorrect Order IDs → Docker/MySQL conflicts → duplicate events → database verification. 😎🔥&lt;/p&gt;

&lt;p&gt;And that's what made this feature much more realistic than simply following an integration tutorial.&lt;/p&gt;

&lt;p&gt;🛒 ShopEase — Payment Service&lt;br&gt;
💳 Razorpay Webhook Integration 🚀&lt;/p&gt;

&lt;p&gt;Learn → Build → Break → Debug → Fix → Improve. 💻🔥&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>backend</category>
      <category>webhook</category>
      <category>kafka</category>
    </item>
    <item>
      <title>From Monolith to Microservices: My ShopEase Backend Journey</title>
      <dc:creator>Shitanshu Jha</dc:creator>
      <pubDate>Wed, 09 Sep 2026 08:26:11 +0000</pubDate>
      <link>https://dev.to/shitanshu686/from-monolith-to-microservices-my-shopease-backend-journey-33hf</link>
      <guid>https://dev.to/shitanshu686/from-monolith-to-microservices-my-shopease-backend-journey-33hf</guid>
      <description>&lt;p&gt;From Monolith to Microservices: My ShopEase Backend Journey&lt;/p&gt;

&lt;p&gt;When I started building ShopEase, my main goal was to learn Java backend development by building a real e-commerce application instead of learning concepts only through small examples.&lt;/p&gt;

&lt;p&gt;As the project grew, the backend started containing multiple business responsibilities such as products, users, authentication, carts, orders, payments, and more.&lt;/p&gt;

&lt;p&gt;At that point, I started exploring an important question&lt;/p&gt;

&lt;p&gt;What happens when a growing monolithic application needs to become more scalable and maintainable?&lt;/p&gt;

&lt;p&gt;That led me to Microservices Architecture.&lt;/p&gt;

&lt;p&gt;What I Had Before&lt;/p&gt;

&lt;p&gt;ShopEase initially followed a monolithic backend architecture.&lt;/p&gt;

&lt;p&gt;Different business modules were part of the same Spring Boot application:&lt;/p&gt;

&lt;p&gt;ShopEase Backend &lt;/p&gt;

&lt;p&gt;│&lt;/p&gt;

&lt;p&gt;├── User &lt;/p&gt;

&lt;p&gt;├── Product &lt;/p&gt;

&lt;p&gt;├── Cart &lt;/p&gt;

&lt;p&gt;├── Order &lt;/p&gt;

&lt;p&gt;├── Authentication &lt;/p&gt;

&lt;p&gt;├── Payment &lt;/p&gt;

&lt;p&gt;└── Other Modules&lt;/p&gt;

&lt;p&gt;Everything was running inside one application.&lt;/p&gt;

&lt;p&gt;This architecture is perfectly useful while developing and learning, but as an application grows, managing every business domain inside one large codebase can become increasingly difficult.&lt;/p&gt;

&lt;p&gt;So I decided to start exploring a microservices-based architecture.&lt;/p&gt;

&lt;p&gt;Starting the Microservices Migration&lt;/p&gt;

&lt;p&gt;For Module 30, I started transforming ShopEase from a monolithic backend toward a Microservices Architecture.&lt;/p&gt;

&lt;p&gt;My current progress is:&lt;/p&gt;

&lt;p&gt;30.1 Microservices Architecture ✅&lt;/p&gt;

&lt;p&gt;30.2 Product Service ✅ &lt;/p&gt;

&lt;p&gt;30.3 User Service ⏳&lt;/p&gt;

&lt;p&gt;The first major step was separating the Product Service from the main backend.&lt;/p&gt;

&lt;p&gt;Product Service&lt;/p&gt;

&lt;p&gt;The Product Service is responsible for product-related functionality.&lt;/p&gt;

&lt;p&gt;Instead of keeping product functionality tightly coupled with every other business module, it can now be treated as an independent service.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        ShopEase
           │
  ┌────────┴────────┐
  │                 │
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Product Service     User Service&lt;br&gt;
      │&lt;br&gt;
   Product DB&lt;/p&gt;

&lt;p&gt;The idea is that each service should have a clearly defined responsibility.&lt;/p&gt;

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

&lt;p&gt;Product Service&lt;/p&gt;

&lt;p&gt;Products Categories Product Details Product Operations&lt;/p&gt;

&lt;p&gt;while the future User Service will handle responsibilities related to users.&lt;/p&gt;

&lt;p&gt;Why Microservices?&lt;/p&gt;

&lt;p&gt;The biggest thing I'm learning is that microservices are not simply about splitting one project into multiple folders.&lt;/p&gt;

&lt;p&gt;The architecture introduces completely different engineering considerations:&lt;/p&gt;

&lt;p&gt;Service boundaries&lt;/p&gt;

&lt;p&gt;Independent deployment&lt;/p&gt;

&lt;p&gt;Service-to-service communication&lt;/p&gt;

&lt;p&gt;Data ownership&lt;/p&gt;

&lt;p&gt;Failure handling&lt;/p&gt;

&lt;p&gt;Scalability&lt;/p&gt;

&lt;p&gt;API design&lt;/p&gt;

&lt;p&gt;Authentication between services&lt;/p&gt;

&lt;p&gt;Monitoring and debugging&lt;/p&gt;

&lt;p&gt;This is one of the reasons I wanted to implement the architecture inside ShopEase rather than learning it only theoretically.&lt;/p&gt;

&lt;p&gt;What I Learned So Far&lt;/p&gt;

&lt;p&gt;One important lesson from this module is that architecture changes introduce new problems.&lt;/p&gt;

&lt;p&gt;In a monolith, calling another module may simply mean calling a Java method.&lt;/p&gt;

&lt;p&gt;With microservices, that communication may happen through a network request.&lt;/p&gt;

&lt;p&gt;That changes the way we think about:&lt;/p&gt;

&lt;p&gt;Method Call &lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;HTTP/API Communication &lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;Another Service&lt;/p&gt;

&lt;p&gt;This introduces concepts that I am now starting to explore more deeply.&lt;/p&gt;

&lt;p&gt;What's Next?&lt;/p&gt;

&lt;p&gt;The next step in my ShopEase microservices journey is:&lt;/p&gt;

&lt;p&gt;Product Service ✅ &lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;User Service ⏳ &lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;Service Communication &lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;API Gateway &lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;Service Discovery &lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;Event-Driven Architecture &lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;Kafka / RabbitMQ&lt;/p&gt;

&lt;p&gt;These are the areas I want to explore as the architecture evolves.&lt;/p&gt;

&lt;p&gt;Why I'm Building This&lt;/p&gt;

&lt;p&gt;ShopEase started as a project to learn Java backend development.&lt;/p&gt;

&lt;p&gt;Now it has become a practical way for me to understand how real-world backend systems evolve.&lt;/p&gt;

&lt;p&gt;Instead of only learning:&lt;/p&gt;

&lt;p&gt;"What is Microservices Architecture?"&lt;/p&gt;

&lt;p&gt;I'm trying to understand:&lt;/p&gt;

&lt;p&gt;"How would I actually migrate an existing application toward microservices?"&lt;/p&gt;

&lt;p&gt;That difference is making the learning experience much more practical.&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;/p&gt;

&lt;p&gt;The biggest takeaway from this module is that building a system teaches you things that theory alone cannot fully explain.&lt;/p&gt;

&lt;p&gt;Every new architectural decision introduces new challenges, and solving those challenges is becoming part of my learning process.&lt;/p&gt;

&lt;p&gt;ShopEase is still evolving, and I am documenting the journey as I continue learning Java, Spring Boot, backend engineering, and system design.&lt;/p&gt;

&lt;p&gt;Learn → Build → Solve → Improve. 🚀&lt;/p&gt;

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

</description>
      <category>java</category>
      <category>microservices</category>
      <category>springboot</category>
      <category>backend</category>
    </item>
    <item>
      <title>🐳 Dockerizing ShopEase: From Local Development to a Containerized Application By Shitanshu Jha</title>
      <dc:creator>Shitanshu Jha</dc:creator>
      <pubDate>Thu, 03 Sep 2026 03:24:27 +0000</pubDate>
      <link>https://dev.to/shitanshu686/dockerizing-shopease-from-local-development-to-a-containerized-applicationby-shitanshu-jha-28j1</link>
      <guid>https://dev.to/shitanshu686/dockerizing-shopease-from-local-development-to-a-containerized-applicationby-shitanshu-jha-28j1</guid>
      <description>&lt;p&gt;Hi, I'm Shitanshu Jha, a BCA student and Java Backend Developer focused on building real-world applications using Java, Spring Boot, REST APIs, Spring Security, JPA/Hibernate, and MySQL.&lt;/p&gt;

&lt;p&gt;One of the major projects I am currently developing is ShopEase, a full-stack e-commerce application.&lt;/p&gt;

&lt;p&gt;ShopEase wasn't built in one go.&lt;/p&gt;

&lt;p&gt;I have been developing it step by step and module by module. With every new module, I have faced new problems, debugged issues, understood why they occurred, and then implemented better solutions.&lt;/p&gt;

&lt;p&gt;Throughout this journey, I have worked on different parts of an e-commerce system, including authentication, products, cart, wishlist, checkout, orders, validation, exception handling, security, and database integration.&lt;/p&gt;

&lt;p&gt;After getting the core application working, I reached another important question:&lt;/p&gt;

&lt;p&gt;How can I make ShopEase run consistently without depending entirely on the configuration of my local machine?&lt;/p&gt;

&lt;p&gt;This question led me to Docker.&lt;/p&gt;

&lt;p&gt;In Module 28, I successfully containerized ShopEase and tested the application with Spring Boot and MySQL running inside Docker containers.&lt;/p&gt;

&lt;p&gt;🚀 Why I Added Docker to ShopEase&lt;/p&gt;

&lt;p&gt;Before Docker, ShopEase depended heavily on my local development environment.&lt;/p&gt;

&lt;p&gt;I needed the correct:&lt;/p&gt;

&lt;p&gt;Java environment&lt;br&gt;
MySQL installation&lt;br&gt;
Database configuration&lt;br&gt;
Application configuration&lt;br&gt;
Ports&lt;br&gt;
Credentials and other environment-specific values&lt;/p&gt;

&lt;p&gt;My application might work perfectly on my computer, but that doesn't automatically mean it will behave exactly the same way on another machine.&lt;/p&gt;

&lt;p&gt;That is the classic:&lt;/p&gt;

&lt;p&gt;“It works on my machine.”&lt;/p&gt;

&lt;p&gt;problem.&lt;/p&gt;

&lt;p&gt;I wanted ShopEase to move beyond that kind of setup.&lt;/p&gt;

&lt;p&gt;Instead of thinking only about writing backend code, I wanted to understand how an actual application can be packaged, configured, and run as multiple services.&lt;/p&gt;

&lt;p&gt;That's why I decided to containerize it.&lt;/p&gt;

&lt;p&gt;🧱 Step 1 — Understanding What Needed to Be Containerized&lt;/p&gt;

&lt;p&gt;Before writing Docker configuration, I first looked at the basic ShopEase backend architecture.&lt;/p&gt;

&lt;p&gt;It was essentially:&lt;/p&gt;

&lt;p&gt;Frontend&lt;br&gt;
   │&lt;br&gt;
   ▼&lt;br&gt;
REST APIs&lt;br&gt;
   │&lt;br&gt;
   ▼&lt;br&gt;
Spring Boot Backend&lt;br&gt;
   │&lt;br&gt;
   ▼&lt;br&gt;
MySQL Database&lt;/p&gt;

&lt;p&gt;The backend depends on MySQL.&lt;/p&gt;

&lt;p&gt;So simply putting the Spring Boot application inside a container wasn't enough.&lt;/p&gt;

&lt;p&gt;I needed two main services:&lt;/p&gt;

&lt;p&gt;┌─────────────────────┐&lt;br&gt;
│ Spring Boot Backend │&lt;br&gt;
└──────────┬──────────┘&lt;br&gt;
           │&lt;br&gt;
           │ Database Connection&lt;br&gt;
           ▼&lt;br&gt;
┌─────────────────────┐&lt;br&gt;
│       MySQL         │&lt;br&gt;
└─────────────────────┘&lt;/p&gt;

&lt;p&gt;Both services needed to run independently while still being able to communicate.&lt;/p&gt;

&lt;p&gt;That became the foundation of my Docker implementation.&lt;/p&gt;

&lt;p&gt;🐳 Step 2 — Creating a Dockerfile for Spring Boot&lt;/p&gt;

&lt;p&gt;The next step was creating a Dockerfile for the ShopEase backend.&lt;/p&gt;

&lt;p&gt;A Dockerfile defines how Docker should create an image for an application.&lt;/p&gt;

&lt;p&gt;The basic flow became:&lt;/p&gt;

&lt;p&gt;ShopEase Backend&lt;br&gt;
       │&lt;br&gt;
       ▼&lt;br&gt;
   Build Project&lt;br&gt;
       │&lt;br&gt;
       ▼&lt;br&gt;
     JAR File&lt;br&gt;
       │&lt;br&gt;
       ▼&lt;br&gt;
  Docker Image&lt;br&gt;
       │&lt;br&gt;
       ▼&lt;br&gt;
Docker Container&lt;br&gt;
       │&lt;br&gt;
       ▼&lt;br&gt;
Spring Boot Running&lt;/p&gt;

&lt;p&gt;This was an important change in how I thought about the application.&lt;/p&gt;

&lt;p&gt;Previously, I was mainly thinking:&lt;/p&gt;

&lt;p&gt;Write Code → Run Spring Boot&lt;/p&gt;

&lt;p&gt;Now I had to think:&lt;/p&gt;

&lt;p&gt;Write Code&lt;br&gt;
   ↓&lt;br&gt;
Build Application&lt;br&gt;
   ↓&lt;br&gt;
Package Application&lt;br&gt;
   ↓&lt;br&gt;
Build Docker Image&lt;br&gt;
   ↓&lt;br&gt;
Create Container&lt;br&gt;
   ↓&lt;br&gt;
Run Application&lt;/p&gt;

&lt;p&gt;It gave me a better understanding of how backend applications move from development toward deployment.&lt;/p&gt;

&lt;p&gt;🗄️ Step 3 — Containerizing MySQL&lt;/p&gt;

&lt;p&gt;ShopEase stores application data in MySQL.&lt;/p&gt;

&lt;p&gt;So the next task was running MySQL as a separate container.&lt;/p&gt;

&lt;p&gt;Now instead of thinking about MySQL only as a database installed on my Windows machine, I could treat it as an independent service.&lt;/p&gt;

&lt;p&gt;The architecture started looking like this:&lt;/p&gt;

&lt;p&gt;Docker&lt;br&gt;
│&lt;br&gt;
├── ShopEase Backend Container&lt;br&gt;
│       │&lt;br&gt;
│       │&lt;br&gt;
│       ▼&lt;br&gt;
│&lt;br&gt;
└── MySQL Container&lt;/p&gt;

&lt;p&gt;But this introduced one of the most important challenges.&lt;/p&gt;

&lt;p&gt;⚠️ Challenge 1 — Connecting Spring Boot to MySQL&lt;/p&gt;

&lt;p&gt;When both applications are running directly on the same machine, using localhost feels natural.&lt;/p&gt;

&lt;p&gt;But containers change this concept.&lt;/p&gt;

&lt;p&gt;Inside the Spring Boot container:&lt;/p&gt;

&lt;p&gt;localhost&lt;/p&gt;

&lt;p&gt;refers to the Spring Boot container itself.&lt;/p&gt;

&lt;p&gt;It does not automatically mean the MySQL container.&lt;/p&gt;

&lt;p&gt;That was an important concept for me to understand.&lt;/p&gt;

&lt;p&gt;I needed the backend container to find and communicate with the database container correctly.&lt;/p&gt;

&lt;p&gt;This led directly to the next part of the implementation.&lt;/p&gt;

&lt;p&gt;🌐 Step 4 — Docker Networking&lt;/p&gt;

&lt;p&gt;To allow the Spring Boot and MySQL containers to communicate, I configured them to work through Docker networking.&lt;/p&gt;

&lt;p&gt;Conceptually, the architecture became:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;         Docker Network
               │
   ┌───────────┴───────────┐
   │                       │
   ▼                       ▼
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;┌──────────────┐        ┌──────────────┐&lt;br&gt;
│ Spring Boot  │ &amp;lt;────&amp;gt; │    MySQL     │&lt;br&gt;
│  Container   │        │  Container   │&lt;br&gt;
└──────────────┘        └──────────────┘&lt;/p&gt;

&lt;p&gt;Instead of treating the database as something running on the host machine, the backend can communicate with the database service inside the Docker environment.&lt;/p&gt;

&lt;p&gt;This helped me understand an important Docker concept:&lt;/p&gt;

&lt;p&gt;Containers are isolated, but they can communicate through properly configured networks.&lt;/p&gt;

&lt;p&gt;⚠️ Challenge 2 — Application Configuration&lt;/p&gt;

&lt;p&gt;Getting the containers running was only part of the work.&lt;/p&gt;

&lt;p&gt;The Spring Boot application also needed the correct database configuration.&lt;/p&gt;

&lt;p&gt;The application needed values such as:&lt;/p&gt;

&lt;p&gt;Database Host&lt;br&gt;
Database Port&lt;br&gt;
Database Name&lt;br&gt;
Database Username&lt;br&gt;
Database Password&lt;/p&gt;

&lt;p&gt;Hardcoding all of these values directly into the application would make the configuration difficult to manage across different environments.&lt;/p&gt;

&lt;p&gt;So I worked with environment variables.&lt;/p&gt;

&lt;p&gt;🔐 Step 5 — Using Environment Variables&lt;/p&gt;

&lt;p&gt;Environment variables allowed me to separate configuration from application code.&lt;/p&gt;

&lt;p&gt;For example, configuration can conceptually be represented as:&lt;/p&gt;

&lt;p&gt;DB_HOST&lt;br&gt;
DB_PORT&lt;br&gt;
DB_NAME&lt;br&gt;
DB_USERNAME&lt;br&gt;
DB_PASSWORD&lt;/p&gt;

&lt;p&gt;The application can then read these values from its environment.&lt;/p&gt;

&lt;p&gt;This means the same application can work with different configurations.&lt;/p&gt;

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

&lt;p&gt;Development Environment&lt;br&gt;
        │&lt;br&gt;
        ├── Development DB&lt;br&gt;
        │&lt;br&gt;
Testing Environment&lt;br&gt;
        │&lt;br&gt;
        ├── Testing DB&lt;br&gt;
        │&lt;br&gt;
Production Environment&lt;br&gt;
        │&lt;br&gt;
        └── Production DB&lt;/p&gt;

&lt;p&gt;without requiring the actual application logic to be rewritten.&lt;/p&gt;

&lt;p&gt;This also taught me an important backend engineering principle:&lt;/p&gt;

&lt;p&gt;Configuration should be separated from application logic whenever possible.&lt;/p&gt;

&lt;p&gt;Sensitive credentials should also not be committed directly to a public Git repository.&lt;/p&gt;

&lt;p&gt;🧩 Step 6 — Bringing Everything Together with Docker Compose&lt;/p&gt;

&lt;p&gt;At this point, ShopEase had more than one container.&lt;/p&gt;

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

&lt;p&gt;Spring Boot Container&lt;br&gt;
MySQL Container&lt;/p&gt;

&lt;p&gt;Starting and managing every service separately would quickly become inconvenient.&lt;/p&gt;

&lt;p&gt;That's where Docker Compose became useful.&lt;/p&gt;

&lt;p&gt;With Docker Compose, I could describe the services required by ShopEase together.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;p&gt;docker compose&lt;br&gt;
      │&lt;br&gt;
      ├── Spring Boot Service&lt;br&gt;
      │&lt;br&gt;
      ├── MySQL Service&lt;br&gt;
      │&lt;br&gt;
      ├── Environment Variables&lt;br&gt;
      │&lt;br&gt;
      └── Networking&lt;/p&gt;

&lt;p&gt;Then the complete environment could be managed as one multi-container application.&lt;/p&gt;

&lt;p&gt;The startup process became much cleaner:&lt;/p&gt;

&lt;p&gt;docker compose up&lt;br&gt;
        │&lt;br&gt;
        ▼&lt;br&gt;
Create / Start Services&lt;br&gt;
        │&lt;br&gt;
        ├───────────────┐&lt;br&gt;
        ▼               ▼&lt;br&gt;
  Spring Boot         MySQL&lt;br&gt;
   Container         Container&lt;br&gt;
        │               │&lt;br&gt;
        └──── Network ──┘&lt;/p&gt;

&lt;p&gt;This was one of the biggest improvements Docker brought to ShopEase.&lt;/p&gt;

&lt;p&gt;⚠️ Challenge 3 — Moving from Localhost Thinking to Container Thinking&lt;/p&gt;

&lt;p&gt;One of my biggest learnings during this module was that containerized applications require a different way of thinking.&lt;/p&gt;

&lt;p&gt;Previously, my environment was mostly:&lt;/p&gt;

&lt;p&gt;My Computer&lt;br&gt;
   ├── Java&lt;br&gt;
   ├── Spring Boot&lt;br&gt;
   └── MySQL&lt;/p&gt;

&lt;p&gt;After Docker:&lt;/p&gt;

&lt;p&gt;My Computer&lt;br&gt;
     │&lt;br&gt;
   Docker&lt;br&gt;
     │&lt;br&gt;
     ├── Spring Boot Container&lt;br&gt;
     │&lt;br&gt;
     └── MySQL Container&lt;/p&gt;

&lt;p&gt;The application and database were no longer simply two programs running directly beside each other.&lt;/p&gt;

&lt;p&gt;They were independent containers.&lt;/p&gt;

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

&lt;p&gt;Hostnames&lt;br&gt;
Networking&lt;br&gt;
Ports&lt;br&gt;
Database configuration&lt;br&gt;
Environment variables&lt;br&gt;
Startup dependencies&lt;/p&gt;

&lt;p&gt;Understanding these differences was one of the most valuable parts of this module.&lt;/p&gt;

&lt;p&gt;🛠️ My Problem-Solving Approach&lt;/p&gt;

&lt;p&gt;I have followed a similar development process throughout ShopEase.&lt;/p&gt;

&lt;p&gt;Whenever something doesn't work, I try not to randomly change code until the error disappears.&lt;/p&gt;

&lt;p&gt;My approach is generally:&lt;/p&gt;

&lt;p&gt;Implement Feature&lt;br&gt;
      ↓&lt;br&gt;
Run Application&lt;br&gt;
      ↓&lt;br&gt;
Test Feature&lt;br&gt;
      ↓&lt;br&gt;
Observe Error&lt;br&gt;
      ↓&lt;br&gt;
Understand the Cause&lt;br&gt;
      ↓&lt;br&gt;
Change Configuration / Code&lt;br&gt;
      ↓&lt;br&gt;
Test Again&lt;br&gt;
      ↓&lt;br&gt;
Verify Complete Flow&lt;/p&gt;

&lt;p&gt;I followed the same approach while implementing Docker.&lt;/p&gt;

&lt;p&gt;Containerization introduced new problems because the environment was different from my normal local setup.&lt;/p&gt;

&lt;p&gt;I had to understand how the Spring Boot container sees MySQL, how the services communicate, and how configuration should reach the application.&lt;/p&gt;

&lt;p&gt;Solving those problems step by step made Docker much easier to understand than simply memorizing Docker commands.&lt;/p&gt;

&lt;p&gt;🧪 Step 7 — Testing the Containerized Application&lt;/p&gt;

&lt;p&gt;I didn't want to consider the module complete just because the containers started successfully.&lt;/p&gt;

&lt;p&gt;The important question was:&lt;/p&gt;

&lt;p&gt;Does ShopEase actually work correctly inside this environment?&lt;/p&gt;

&lt;p&gt;So I tested the setup to verify that:&lt;/p&gt;

&lt;p&gt;✅ Docker image builds correctly&lt;br&gt;
✅ Spring Boot container starts&lt;br&gt;
✅ MySQL container starts&lt;br&gt;
✅ Spring Boot can communicate with MySQL&lt;br&gt;
✅ Docker networking works&lt;br&gt;
✅ Environment variables are passed correctly&lt;br&gt;
✅ Database connectivity works&lt;br&gt;
✅ Backend APIs continue functioning in the containerized environment&lt;/p&gt;

&lt;p&gt;After testing the complete flow, I marked:&lt;/p&gt;

&lt;p&gt;✅ Module 28 — Docker: Completed &amp;amp; Tested&lt;br&gt;
🏗️ ShopEase Docker Architecture&lt;/p&gt;

&lt;p&gt;The final containerized backend architecture can be visualized like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                ShopEase
                   │
                   ▼
            Docker Compose
                   │
          Docker Network
                   │
       ┌───────────┴───────────┐
       │                       │
       ▼                       ▼
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;┌─────────────────────┐   ┌─────────────────┐&lt;br&gt;
│     Spring Boot     │   │      MySQL      │&lt;br&gt;
│      Container      │◄─►│    Container    │&lt;br&gt;
│                     │   │                 │&lt;br&gt;
│   ShopEase Backend  │   │ ShopEase Data   │&lt;br&gt;
└─────────────────────┘   └─────────────────┘&lt;br&gt;
           │&lt;br&gt;
           ▼&lt;br&gt;
       REST APIs&lt;br&gt;
💡 What I Learned From Module 28&lt;/p&gt;

&lt;p&gt;Before implementing this module, Docker was mostly another technology on my learning roadmap.&lt;/p&gt;

&lt;p&gt;After actually integrating it into ShopEase, I understood why containerization matters.&lt;/p&gt;

&lt;p&gt;I gained practical experience with:&lt;/p&gt;

&lt;p&gt;Dockerfile — packaging the Spring Boot application.&lt;/p&gt;

&lt;p&gt;Docker Images — understanding the blueprint used to create containers.&lt;/p&gt;

&lt;p&gt;Docker Containers — running isolated application services.&lt;/p&gt;

&lt;p&gt;Docker Compose — managing multiple services together.&lt;/p&gt;

&lt;p&gt;Docker Networking — enabling communication between Spring Boot and MySQL.&lt;/p&gt;

&lt;p&gt;Environment Variables — separating configuration from application code.&lt;/p&gt;

&lt;p&gt;Containerized Databases — running MySQL as an independent service.&lt;/p&gt;

&lt;p&gt;But the biggest learning wasn't a Docker command.&lt;/p&gt;

&lt;p&gt;It was understanding that:&lt;/p&gt;

&lt;p&gt;Building an application is not only about writing code. You also need to think about how that application will be configured, packaged, connected, run, tested, and eventually deployed.&lt;/p&gt;

&lt;p&gt;👨‍💻 Building ShopEase Step by Step&lt;/p&gt;

&lt;p&gt;ShopEase has been a learning-by-building project for me.&lt;/p&gt;

&lt;p&gt;I didn't start by knowing everything required to build the complete application.&lt;/p&gt;

&lt;p&gt;Instead, I have been developing it incrementally.&lt;/p&gt;

&lt;p&gt;Learn&lt;br&gt;
  ↓&lt;br&gt;
Implement&lt;br&gt;
  ↓&lt;br&gt;
Face Problems&lt;br&gt;
  ↓&lt;br&gt;
Debug&lt;br&gt;
  ↓&lt;br&gt;
Understand&lt;br&gt;
  ↓&lt;br&gt;
Improve&lt;br&gt;
  ↓&lt;br&gt;
Move to Next Module&lt;/p&gt;

&lt;p&gt;Every new feature has introduced something new for me to understand.&lt;/p&gt;

&lt;p&gt;Some challenges have been related to backend logic, some to databases, some to security and API integration, and now some to infrastructure and containerization.&lt;/p&gt;

&lt;p&gt;That process is exactly why I continue developing ShopEase.&lt;/p&gt;

&lt;p&gt;The goal isn't just to add a long list of technologies to the project.&lt;/p&gt;

&lt;p&gt;The goal is to understand why they are needed and how they work together in a real application.&lt;/p&gt;

&lt;p&gt;🚀 What's Next for ShopEase?&lt;/p&gt;

&lt;p&gt;Completing Docker doesn't mean ShopEase is finished.&lt;/p&gt;

&lt;p&gt;Containerization is another step toward making the project more deployment-oriented.&lt;/p&gt;

&lt;p&gt;My upcoming areas of focus include further improving:&lt;/p&gt;

&lt;p&gt;Automated testing&lt;br&gt;
CI/CD&lt;br&gt;
Production configuration&lt;br&gt;
Cloud deployment&lt;br&gt;
Monitoring and logging&lt;br&gt;
Backend reliability and optimization&lt;/p&gt;

&lt;p&gt;I want to continue evolving ShopEase while learning the engineering practices used beyond local development.&lt;/p&gt;

&lt;p&gt;🎯 Conclusion&lt;/p&gt;

&lt;p&gt;Module 28 was more than simply adding a Dockerfile to ShopEase.&lt;/p&gt;

&lt;p&gt;It changed how I think about running an application.&lt;/p&gt;

&lt;p&gt;I moved from running Spring Boot and MySQL as locally configured components to understanding how they can operate as separate but connected containerized services.&lt;/p&gt;

&lt;p&gt;During the implementation, I had to understand networking, configuration, environment variables, service communication, and multi-container management.&lt;/p&gt;

&lt;p&gt;I faced problems, debugged them step by step, tested the complete setup, and finally got Spring Boot and MySQL running together successfully using Docker Compose.&lt;/p&gt;

&lt;p&gt;There is still much more for me to learn and improve, but that's exactly how I am building ShopEase:&lt;/p&gt;

&lt;p&gt;One module. One challenge. One solution at a time. 🚀&lt;/p&gt;

&lt;p&gt;🐳 Module 28 — Docker&lt;/p&gt;

&lt;p&gt;Status: ✅ Completed &amp;amp; Tested&lt;/p&gt;

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

</description>
      <category>webdev</category>
      <category>backend</category>
      <category>java</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Who is Shitanshu Jha?</title>
      <dc:creator>Shitanshu Jha</dc:creator>
      <pubDate>Mon, 31 Aug 2026 05:29:21 +0000</pubDate>
      <link>https://dev.to/shitanshu686/who-is-shitanshu-jha-14ko</link>
      <guid>https://dev.to/shitanshu686/who-is-shitanshu-jha-14ko</guid>
      <description>&lt;p&gt;&lt;strong&gt;Building My Journey as a Java Backend Developer&lt;br&gt;
Shitanshu Jha is a Java Backend Developer building real-world applications with Java, Spring Boot and MySQL.&lt;/strong&gt;&lt;br&gt;
By Shitanshu Jha · 5 min read&lt;br&gt;
I’m Shitanshu Jha, a BCA student at Guru Gobind Singh Indraprastha University with a growing focus on Java backend development.&lt;/p&gt;

&lt;p&gt;My journey started with learning programming fundamentals and gradually moved toward building real applications. Instead of limiting myself to tutorials and small examples, I wanted to understand how the different pieces of a real application actually work together.&lt;/p&gt;

&lt;p&gt;That led me to my biggest project so far — ShopEase.&lt;/p&gt;

&lt;p&gt;From Learning Java to Building Real Applications&lt;/p&gt;

&lt;p&gt;Java became the foundation of my backend development journey.&lt;/p&gt;

&lt;p&gt;As I progressed, I moved from Core Java and OOP into technologies such as JDBC, Spring Boot, Spring MVC, Spring Data JPA, Hibernate, REST APIs, Spring Security and MySQL.&lt;/p&gt;

&lt;p&gt;The important part wasn't simply learning these technologies individually.&lt;/p&gt;

&lt;p&gt;It was learning how they fit together.&lt;/p&gt;

&lt;p&gt;A request from a frontend application can travel through a REST controller, reach the service layer, interact with the database through JPA/Hibernate, pass through security mechanisms, and finally return a structured response to the client.&lt;/p&gt;

&lt;p&gt;Understanding that flow changed the way I approached backend development.&lt;/p&gt;

&lt;p&gt;Building ShopEase&lt;/p&gt;

&lt;p&gt;ShopEase is my full-stack e-commerce application built using:&lt;/p&gt;

&lt;p&gt;Frontend → HTML, CSS, JavaScript, Fetch API&lt;/p&gt;

&lt;p&gt;Backend → Java, Spring Boot, Spring MVC, Spring Data JPA, Hibernate&lt;/p&gt;

&lt;p&gt;Security → Spring Security, JWT, BCrypt&lt;/p&gt;

&lt;p&gt;Database → MySQL&lt;/p&gt;

&lt;p&gt;Payments → Razorpay&lt;/p&gt;

&lt;p&gt;The architecture follows a simple but practical flow:&lt;/p&gt;

&lt;p&gt;Frontend → Fetch API → Spring Boot REST API → Spring Security + JWT → Service/Repository Layer → MySQL&lt;/p&gt;

&lt;p&gt;Building this application helped me move beyond isolated coding exercises and start thinking about application architecture, security, validation, database relationships and business logic.&lt;/p&gt;

&lt;p&gt;What I Have Built&lt;/p&gt;

&lt;p&gt;ShopEase has grown from a basic product application into a much larger e-commerce system.&lt;/p&gt;

&lt;p&gt;The application currently includes:&lt;/p&gt;

&lt;p&gt;User signup and login&lt;/p&gt;

&lt;p&gt;JWT authentication&lt;/p&gt;

&lt;p&gt;BCrypt password hashing&lt;/p&gt;

&lt;p&gt;Role-based authorization&lt;/p&gt;

&lt;p&gt;Product management&lt;/p&gt;

&lt;p&gt;Product search and categories&lt;/p&gt;

&lt;p&gt;Product details and specifications&lt;/p&gt;

&lt;p&gt;Similar products&lt;/p&gt;

&lt;p&gt;Shopping cart and persistent cart&lt;/p&gt;

&lt;p&gt;Wishlist&lt;/p&gt;

&lt;p&gt;Checkout and shipping address&lt;/p&gt;

&lt;p&gt;Orders and order history&lt;/p&gt;

&lt;p&gt;Order status management&lt;/p&gt;

&lt;p&gt;Product feedback and moderation&lt;/p&gt;

&lt;p&gt;Razorpay payments&lt;/p&gt;

&lt;p&gt;Payment verification and signature validation&lt;/p&gt;

&lt;p&gt;Admin dashboard&lt;/p&gt;

&lt;p&gt;User, product and order management&lt;/p&gt;

&lt;p&gt;Inventory management&lt;/p&gt;

&lt;p&gt;Low-stock and out-of-stock alerts&lt;/p&gt;

&lt;p&gt;Application logging&lt;/p&gt;

&lt;p&gt;Standard API responses&lt;/p&gt;

&lt;p&gt;DTO-based validation and exception handling&lt;/p&gt;

&lt;p&gt;The project has also given me practical experience with tools such as Git, GitHub, Eclipse, Postman and XAMPP.&lt;/p&gt;

&lt;p&gt;What I Learned From Building It&lt;/p&gt;

&lt;p&gt;The biggest lesson hasn't been learning another framework.&lt;/p&gt;

&lt;p&gt;It has been learning how different parts of software interact.&lt;/p&gt;

&lt;p&gt;For example, implementing authentication taught me about JWTs and Spring Security. Building the cart and order systems forced me to think about relationships between entities and persistent data. Razorpay integration introduced payment verification and security concerns.&lt;/p&gt;

&lt;p&gt;Admin functionality made me think beyond the customer's experience and consider inventory, order management and authorization.&lt;/p&gt;

&lt;p&gt;Logging also showed me why knowing that an application failed isn't enough — developers need useful information about where and why it failed.&lt;/p&gt;

&lt;p&gt;My Current Focus&lt;/p&gt;

&lt;p&gt;I am now moving from feature development toward production hardening.&lt;/p&gt;

&lt;p&gt;My next areas of focus are:&lt;/p&gt;

&lt;p&gt;Automated testing&lt;/p&gt;

&lt;p&gt;API documentation with OpenAPI/Swagger&lt;/p&gt;

&lt;p&gt;Pagination and sorting&lt;/p&gt;

&lt;p&gt;Advanced search&lt;/p&gt;

&lt;p&gt;Image upload&lt;/p&gt;

&lt;p&gt;Docker&lt;/p&gt;

&lt;p&gt;CI/CD&lt;/p&gt;

&lt;p&gt;Deployment&lt;/p&gt;

&lt;p&gt;Cloud deployment&lt;/p&gt;

&lt;p&gt;The goal is no longer just to make an application that works.&lt;/p&gt;

&lt;p&gt;The goal is to understand how to make an application that is testable, maintainable, secure, deployable and closer to production standards.&lt;/p&gt;

&lt;p&gt;What's Next?&lt;/p&gt;

&lt;p&gt;I am still at the beginning of my career, and I know there is a lot more to learn.&lt;/p&gt;

&lt;p&gt;My current direction is clear:&lt;/p&gt;

&lt;p&gt;Java → Spring Boot → Backend Engineering → Production Systems&lt;/p&gt;

&lt;p&gt;I want to keep building projects, solving problems, improving my understanding of backend architecture and gradually working with larger and more complex systems.&lt;/p&gt;

&lt;p&gt;ShopEase is not the final destination.&lt;/p&gt;

&lt;p&gt;It is the project through which I am learning how to become a better software developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shitanshu Jha #ShopEase #ShopEaseShitanshuJha #Backend #Software Engineer #SpringBoot #Java
&lt;/h2&gt;

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

</description>
      <category>backend</category>
      <category>java</category>
      <category>springboot</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>🚀 Building the ShopEase Admin Dashboard — Challenges, Solutions &amp; What I Learned By Shitanshu Jha</title>
      <dc:creator>Shitanshu Jha</dc:creator>
      <pubDate>Wed, 26 Aug 2026 06:26:59 +0000</pubDate>
      <link>https://dev.to/shitanshu686/building-the-shopease-admin-dashboard-challenges-solutions-what-i-learnedby-shitanshu-jha-25dp</link>
      <guid>https://dev.to/shitanshu686/building-the-shopease-admin-dashboard-challenges-solutions-what-i-learnedby-shitanshu-jha-25dp</guid>
      <description>&lt;p&gt;While developing ShopEase, my goal was not just to create a basic e-commerce website. I wanted to build it as a complete application while learning how real-world Java backend systems are designed.&lt;/p&gt;

&lt;p&gt;I am currently developing ShopEase as a full-stack e-commerce application using Java, Spring Boot, Spring Data JPA, Hibernate, MySQL, HTML, CSS and JavaScript.&lt;/p&gt;

&lt;p&gt;One of the major milestones in this journey was Module 23 — Admin Dashboard.&lt;/p&gt;

&lt;p&gt;The dashboard started as a simple admin page, but gradually became a proper management system for products, users, orders, order statuses and inventory.&lt;/p&gt;

&lt;p&gt;🛠️ What I Built&lt;/p&gt;

&lt;p&gt;The ShopEase Admin Dashboard currently provides:&lt;/p&gt;

&lt;p&gt;📊 Dashboard statistics&lt;br&gt;
📦 Product Management&lt;br&gt;
👥 User Management&lt;br&gt;
🛒 Order Management&lt;br&gt;
🔄 Order Status Management&lt;br&gt;
📋 Inventory Management&lt;br&gt;
⚠️ Low Stock Alerts&lt;br&gt;
❌ Out-of-Stock Alerts&lt;br&gt;
🕐 Recent Orders&lt;/p&gt;

&lt;p&gt;The dashboard communicates with my Spring Boot backend through REST APIs and retrieves the required data from MySQL using Spring Data JPA.&lt;/p&gt;

&lt;p&gt;😵 The Challenges I Faced&lt;/p&gt;

&lt;p&gt;Building the dashboard wasn't as straightforward as I initially expected.&lt;/p&gt;

&lt;p&gt;The biggest challenges were not creating the HTML cards or buttons. The difficult part was making sure that the frontend, backend, database and business logic were all connected correctly.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Calculating Dashboard Statistics&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Initially, the dashboard needed to display information such as:&lt;br&gt;
Total Products&lt;br&gt;
Total Users&lt;br&gt;
Total Orders&lt;br&gt;
Total Revenue&lt;/p&gt;

&lt;p&gt;The challenge was deciding where these values should actually come from.&lt;/p&gt;

&lt;p&gt;Instead of calculating everything on the frontend, I implemented the logic on the backend.&lt;/p&gt;

&lt;p&gt;For example, product and user counts are retrieved using repository operations:&lt;/p&gt;

&lt;p&gt;productRepository.count();&lt;br&gt;
userRepository.count();&lt;/p&gt;

&lt;p&gt;Similarly, total revenue required a database query that considers only confirmed orders.&lt;/p&gt;

&lt;p&gt;This taught me an important lesson:&lt;/p&gt;

&lt;p&gt;Dashboard statistics should come from reliable backend data rather than being calculated or trusted on the client side.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Implementing Inventory Alerts&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One of the more interesting parts was implementing inventory monitoring.&lt;/p&gt;

&lt;p&gt;I wanted the dashboard to show:&lt;/p&gt;

&lt;p&gt;Low Stock&lt;br&gt;
Out of Stock&lt;/p&gt;

&lt;p&gt;I implemented repository queries such as:&lt;/p&gt;

&lt;p&gt;long lowStockProducts =&lt;br&gt;
        productRepository.countByStockBetween(1, 10);&lt;/p&gt;

&lt;p&gt;long outOfStockProducts =&lt;br&gt;
        productRepository.countByStock(0);&lt;/p&gt;

&lt;p&gt;This allowed the backend to directly determine the inventory status.&lt;/p&gt;

&lt;p&gt;The dashboard could then display something like:&lt;/p&gt;

&lt;p&gt;⚠️ Low Stock       13&lt;/p&gt;

&lt;p&gt;❌ Out of Stock     1&lt;/p&gt;

&lt;p&gt;This was a good example of how a simple UI feature actually requires proper backend and database logic behind it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetching Recent Orders&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Another requirement was displaying the latest orders on the Admin Dashboard.&lt;/p&gt;

&lt;p&gt;Instead of returning every order and filtering it on the frontend, I created a repository-level query to retrieve recent orders.&lt;/p&gt;

&lt;p&gt;The backend then converts the Order entities into a dedicated DTO:&lt;/p&gt;

&lt;p&gt;AdminRecentOrderDTO&lt;/p&gt;

&lt;p&gt;The response contains information such as:&lt;/p&gt;

&lt;p&gt;Order ID&lt;br&gt;
Customer name&lt;br&gt;
Total amount&lt;br&gt;
Order status&lt;br&gt;
Order creation time&lt;/p&gt;

&lt;p&gt;This helped me understand why DTOs are useful when exposing database entities through APIs.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connecting Everything Through a Dashboard Service&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I didn't want the controller to contain all the dashboard business logic.&lt;/p&gt;

&lt;p&gt;So I created:&lt;/p&gt;

&lt;p&gt;AdminDashboardService&lt;/p&gt;

&lt;p&gt;The service is responsible for collecting:&lt;/p&gt;

&lt;p&gt;Products&lt;br&gt;
Users&lt;br&gt;
Orders&lt;br&gt;
Revenue&lt;br&gt;
Inventory&lt;br&gt;
Recent Orders&lt;/p&gt;

&lt;p&gt;and combining them into:&lt;/p&gt;

&lt;p&gt;AdminDashboardResponseDTO&lt;/p&gt;

&lt;p&gt;This gave me a much cleaner architecture:&lt;/p&gt;

&lt;p&gt;Frontend&lt;br&gt;
   ↓&lt;br&gt;
Controller&lt;br&gt;
   ↓&lt;br&gt;
Service&lt;br&gt;
   ↓&lt;br&gt;
Repository&lt;br&gt;
   ↓&lt;br&gt;
MySQL&lt;/p&gt;

&lt;p&gt;Working through this helped me understand the importance of separating responsibilities instead of putting everything inside one class.&lt;/p&gt;

&lt;p&gt;🐛 Debugging Was a Major Part of the Work&lt;/p&gt;

&lt;p&gt;One thing I learned while developing ShopEase is that writing code is only half the job.&lt;/p&gt;

&lt;p&gt;A lot of my time went into debugging.&lt;/p&gt;

&lt;p&gt;For example, I encountered issues where repository methods were not recognized correctly, constructors didn't match DTO parameters, and entity fields differed from what the service expected.&lt;/p&gt;

&lt;p&gt;There were also situations where the dashboard displayed incorrect inventory numbers.&lt;/p&gt;

&lt;p&gt;Instead of randomly changing code, I started checking the complete flow:&lt;/p&gt;

&lt;p&gt;Database&lt;br&gt;
   ↓&lt;br&gt;
Repository&lt;br&gt;
   ↓&lt;br&gt;
Service&lt;br&gt;
   ↓&lt;br&gt;
DTO&lt;br&gt;
   ↓&lt;br&gt;
Controller&lt;br&gt;
   ↓&lt;br&gt;
API Response&lt;br&gt;
   ↓&lt;br&gt;
Frontend&lt;/p&gt;

&lt;p&gt;That approach made debugging much easier.&lt;/p&gt;

&lt;p&gt;📊 Testing the Dashboard&lt;/p&gt;

&lt;p&gt;After implementing the features, I tested the dashboard with actual application data.&lt;/p&gt;

&lt;p&gt;For example, the backend returned dashboard information similar to:&lt;/p&gt;

&lt;p&gt;Total Products: 58&lt;br&gt;
Total Users: 9&lt;br&gt;
Total Orders: 21&lt;br&gt;
Total Revenue: 7798&lt;br&gt;
Low Stock Products: 13&lt;br&gt;
Out of Stock Products: 1&lt;/p&gt;

&lt;p&gt;I also tested inventory changes by changing product stock values in the database and verifying that the dashboard updated accordingly.&lt;/p&gt;

&lt;p&gt;This helped confirm that the values weren't hardcoded and were actually coming from the database.&lt;/p&gt;

&lt;p&gt;🔐 Admin-Specific Functionality&lt;/p&gt;

&lt;p&gt;Another important part was making sure that administrative functionality was separated from normal user functionality.&lt;/p&gt;

&lt;p&gt;ShopEase already has role-based behavior for:&lt;/p&gt;

&lt;p&gt;USER&lt;br&gt;
ADMIN&lt;/p&gt;

&lt;p&gt;The Admin Dashboard is therefore intended for administrative operations such as:&lt;/p&gt;

&lt;p&gt;Managing products&lt;br&gt;
Managing users&lt;br&gt;
Managing orders&lt;br&gt;
Updating order status&lt;br&gt;
Monitoring inventory&lt;/p&gt;

&lt;p&gt;This made me think more seriously about authorization and access control, rather than treating an admin page as just another frontend page.&lt;/p&gt;

&lt;p&gt;🚀 From Admin Page to Production-Ready Module&lt;/p&gt;

&lt;p&gt;The biggest takeaway from this module is that a dashboard isn't just a collection of cards.&lt;/p&gt;

&lt;p&gt;A proper admin dashboard requires:&lt;/p&gt;

&lt;p&gt;UI&lt;br&gt;
+&lt;br&gt;
REST APIs&lt;br&gt;
+&lt;br&gt;
Business Logic&lt;br&gt;
+&lt;br&gt;
Database Queries&lt;br&gt;
+&lt;br&gt;
DTOs&lt;br&gt;
+&lt;br&gt;
Validation&lt;br&gt;
+&lt;br&gt;
Authorization&lt;br&gt;
+&lt;br&gt;
Error Handling&lt;br&gt;
+&lt;br&gt;
Testing&lt;/p&gt;

&lt;p&gt;That is what made this module much more valuable for me than simply designing an admin interface.&lt;/p&gt;

&lt;p&gt;🧠 What I Learned&lt;/p&gt;

&lt;p&gt;While working on this module, I learned and practiced:&lt;/p&gt;

&lt;p&gt;Spring Boot service-layer architecture&lt;br&gt;
Spring Data JPA repository queries&lt;br&gt;
DTO-based API responses&lt;br&gt;
Database aggregation&lt;br&gt;
Inventory management logic&lt;br&gt;
Order management&lt;br&gt;
Role-based functionality&lt;br&gt;
Debugging backend/frontend integration&lt;br&gt;
API testing&lt;br&gt;
Separating business logic from controllers&lt;br&gt;
Designing features around actual application data&lt;/p&gt;

&lt;p&gt;More importantly, I learned that production-ready development is mostly about handling the problems that appear between different parts of the system.&lt;/p&gt;

&lt;p&gt;👨‍💻 About Me&lt;/p&gt;

&lt;p&gt;I'm Shitanshu Jha, a BCA student and developer currently building ShopEase as a hands-on project to strengthen my skills in Java backend and full-stack development.&lt;/p&gt;

&lt;p&gt;Instead of only learning technologies theoretically, I'm trying to understand them by building a complete application step by step.&lt;/p&gt;

&lt;p&gt;With ShopEase, I'm working with:&lt;/p&gt;

&lt;p&gt;Java&lt;br&gt;
Spring Boot&lt;br&gt;
Spring MVC&lt;br&gt;
Spring Data JPA&lt;br&gt;
Hibernate&lt;br&gt;
MySQL&lt;br&gt;
REST APIs&lt;br&gt;
JWT&lt;br&gt;
Spring Security&lt;br&gt;
HTML&lt;br&gt;
CSS&lt;br&gt;
JavaScript&lt;br&gt;
Git &amp;amp; GitHub&lt;br&gt;
Postman&lt;/p&gt;

&lt;p&gt;ShopEase is still an ongoing project, and I'm continuing to improve it module by module.&lt;/p&gt;

&lt;p&gt;The objective isn't simply to finish another college project.&lt;/p&gt;

&lt;p&gt;I'm using ShopEase to understand how real software is designed, debugged, tested and gradually made production-ready.&lt;/p&gt;

&lt;p&gt;🚀 What's Next?&lt;/p&gt;

&lt;p&gt;With the Admin Dashboard completed, ShopEase has moved into Phase 6 — Production Ready.&lt;/p&gt;

&lt;p&gt;The next focus is improving the application's production-level capabilities, including:&lt;/p&gt;

&lt;p&gt;Logging&lt;br&gt;
Better error tracking&lt;br&gt;
Reliability&lt;br&gt;
Security improvements&lt;br&gt;
Performance&lt;br&gt;
Deployment considerations&lt;/p&gt;

&lt;p&gt;There is still a lot to build, but every module is teaching me something that a tutorial alone couldn't.&lt;/p&gt;

&lt;p&gt;ShopEase is not finished yet — and that's the point.&lt;/p&gt;

&lt;h1&gt;
  
  
  Java
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Spring Boot
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Backend Development
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Full Stack Development
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Web Development
&lt;/h1&gt;

</description>
      <category>backend</category>
      <category>database</category>
      <category>java</category>
      <category>springboot</category>
    </item>
    <item>
      <title>I Integrated Razorpay Payments into My Java Spring Boot E-Commerce Project — Challenges, Bugs, and What I Learned</title>
      <dc:creator>Shitanshu Jha</dc:creator>
      <pubDate>Sun, 23 Aug 2026 12:13:24 +0000</pubDate>
      <link>https://dev.to/shitanshu686/i-integrated-razorpay-payments-into-my-java-spring-boot-e-commerce-project-challenges-bugs-and-21f3</link>
      <guid>https://dev.to/shitanshu686/i-integrated-razorpay-payments-into-my-java-spring-boot-e-commerce-project-challenges-bugs-and-21f3</guid>
      <description>&lt;p&gt;&lt;strong&gt;💳 Integrating Razorpay Payment Gateway into My Java Spring Boot E-Commerce Project&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Building an e-commerce application is not just about displaying products and adding them to a cart.&lt;/p&gt;

&lt;p&gt;At some point, the application needs to handle one of the most important parts of the entire flow:&lt;/p&gt;

&lt;p&gt;Payments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F472kl5kbjc5gcjjfz693.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F472kl5kbjc5gcjjfz693.png" alt=" " width="800" height="443"&gt;&lt;/a&gt;&lt;br&gt;
While working on my ShopEase, a full-stack e-commerce application built with Java Spring Boot, MySQL, JavaScript and JWT authentication, I recently implemented Razorpay Test Mode payments.&lt;/p&gt;

&lt;p&gt;The implementation looked straightforward at first:&lt;br&gt;
Checkout&lt;br&gt;
   ↓&lt;br&gt;
Create Order&lt;br&gt;
   ↓&lt;br&gt;
Create Razorpay Order&lt;br&gt;
   ↓&lt;br&gt;
Open Razorpay Checkout&lt;br&gt;
   ↓&lt;br&gt;
Verify Payment&lt;br&gt;
   ↓&lt;br&gt;
Confirm Order&lt;br&gt;
But in practice, there were several problems that I had to debug and solve.&lt;/p&gt;

&lt;p&gt;This post documents what I actually implemented, the problems I faced, and what I learned from them.&lt;/p&gt;

&lt;p&gt;🛒 About ShopEase&lt;/p&gt;

&lt;p&gt;ShopEase is my full-stack e-commerce project.&lt;/p&gt;

&lt;p&gt;Tech Stack&lt;/p&gt;

&lt;p&gt;Frontend&lt;/p&gt;

&lt;p&gt;HTML&lt;br&gt;
CSS&lt;br&gt;
JavaScript&lt;br&gt;
Fetch API&lt;br&gt;
LocalStorage&lt;/p&gt;

&lt;p&gt;Backend&lt;/p&gt;

&lt;p&gt;Java&lt;br&gt;
Spring Boot&lt;br&gt;
Spring MVC&lt;br&gt;
Spring Data JPA&lt;br&gt;
Hibernate&lt;br&gt;
Spring Security&lt;br&gt;
JWT&lt;br&gt;
BCrypt&lt;/p&gt;

&lt;p&gt;Database&lt;/p&gt;

&lt;p&gt;MySQL&lt;/p&gt;

&lt;p&gt;Payment Gateway&lt;/p&gt;

&lt;p&gt;Razorpay&lt;/p&gt;

&lt;p&gt;Tools&lt;/p&gt;

&lt;p&gt;Eclipse&lt;br&gt;
Postman&lt;br&gt;
XAMPP&lt;br&gt;
Git&lt;br&gt;
GitHub&lt;/p&gt;

&lt;p&gt;Before implementing payments, I already had:&lt;/p&gt;

&lt;p&gt;User authentication&lt;br&gt;
JWT authorization&lt;br&gt;
Product system&lt;br&gt;
Shopping cart&lt;br&gt;
Wishlist&lt;br&gt;
Checkout&lt;br&gt;
Order creation&lt;br&gt;
Order history&lt;/p&gt;

&lt;p&gt;So the next logical step was integrating payments.&lt;/p&gt;

&lt;p&gt;🎯 What I Wanted to Build&lt;/p&gt;

&lt;p&gt;I didn't want Razorpay to simply open a payment popup.&lt;/p&gt;

&lt;p&gt;I wanted a complete payment lifecycle.&lt;/p&gt;

&lt;p&gt;The final architecture became:&lt;br&gt;
User&lt;br&gt;
 ↓&lt;br&gt;
Cart&lt;br&gt;
 ↓&lt;br&gt;
Checkout&lt;br&gt;
 ↓&lt;br&gt;
POST /orders&lt;br&gt;
 ↓&lt;br&gt;
ShopEase Order Created&lt;br&gt;
 ↓&lt;br&gt;
POST /payments/create&lt;br&gt;
 ↓&lt;br&gt;
Razorpay Order Created&lt;br&gt;
 ↓&lt;br&gt;
Razorpay Checkout&lt;br&gt;
 ↓&lt;br&gt;
Payment&lt;br&gt;
 ├── SUCCESS&lt;br&gt;
 │      ↓&lt;br&gt;
 │   Verify Signature&lt;br&gt;
 │      ↓&lt;br&gt;
 │   Payment = SUCCESS&lt;br&gt;
 │      ↓&lt;br&gt;
 │   Order = CONFIRMED&lt;br&gt;
 │      ↓&lt;br&gt;
 │   Cart Cleared&lt;br&gt;
 │&lt;br&gt;
 └── FAILURE&lt;br&gt;
        ↓&lt;br&gt;
     Payment = FAILED&lt;br&gt;
        ↓&lt;br&gt;
     Order = PENDING&lt;br&gt;
        ↓&lt;br&gt;
     Cart Preserved&lt;br&gt;
This distinction between ShopEase Order and Razorpay Order was one of the most important concepts I learned during the implementation.&lt;/p&gt;

&lt;p&gt;🧩 Step 1 — Creating a Razorpay Order&lt;/p&gt;

&lt;p&gt;I created a backend endpoint:&lt;br&gt;
POST /payments/create&lt;br&gt;
The frontend sends:&lt;/p&gt;

&lt;p&gt;orderId&lt;br&gt;
amount&lt;/p&gt;

&lt;p&gt;The backend first finds the ShopEase order.&lt;/p&gt;

&lt;p&gt;Then I validate that the payment amount matches the actual order amount.&lt;/p&gt;

&lt;p&gt;if (!order.getTotalAmount().equals(amount)) {&lt;br&gt;
    throw new RuntimeException(&lt;br&gt;
        "Payment amount does not match order amount"&lt;br&gt;
    );&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;I then convert the amount into paise:&lt;/p&gt;

&lt;p&gt;int amountInPaise =&lt;br&gt;
        (int) Math.round(amount * 100);&lt;/p&gt;

&lt;p&gt;and create the Razorpay order.&lt;/p&gt;

&lt;p&gt;The Razorpay order ID is then stored in my Payment entity.&lt;/p&gt;

&lt;p&gt;This gives me a relationship like:&lt;/p&gt;

&lt;p&gt;ShopEase Order&lt;br&gt;
      ↓&lt;br&gt;
Payment&lt;br&gt;
      ↓&lt;br&gt;
Razorpay Order ID&lt;br&gt;
🔐 Step 2 — Payment Verification&lt;/p&gt;

&lt;p&gt;One of the most important parts of the integration was payment verification.&lt;/p&gt;

&lt;p&gt;After successful payment, Razorpay provides:&lt;/p&gt;

&lt;p&gt;razorpay_order_id&lt;br&gt;
razorpay_payment_id&lt;br&gt;
razorpay_signature&lt;/p&gt;

&lt;p&gt;I send these values to:&lt;/p&gt;

&lt;p&gt;POST /payments/verify&lt;/p&gt;

&lt;p&gt;The backend constructs the signature payload:&lt;/p&gt;

&lt;p&gt;String payload =&lt;br&gt;
        razorpayOrderId&lt;br&gt;
        + "|"&lt;br&gt;
        + razorpayPaymentId;&lt;/p&gt;

&lt;p&gt;Then I verify the signature using the Razorpay secret:&lt;/p&gt;

&lt;p&gt;Utils.verifySignature(&lt;br&gt;
    payload,&lt;br&gt;
    razorpaySignature,&lt;br&gt;
    System.getenv("RAZORPAY_KEY_SECRET")&lt;br&gt;
);&lt;/p&gt;

&lt;p&gt;I deliberately kept the secret on the backend instead of exposing it in JavaScript.&lt;/p&gt;

&lt;p&gt;🐛 Challenge 1 — Order ID Was Missing&lt;/p&gt;

&lt;p&gt;This was one of the first real bugs I encountered.&lt;/p&gt;

&lt;p&gt;The frontend initially expected the order response to directly contain the order ID.&lt;/p&gt;

&lt;p&gt;But my backend response was wrapped inside my standard:&lt;/p&gt;

&lt;p&gt;ApiResponse&lt;/p&gt;

&lt;p&gt;The actual response structure was effectively:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "success": true,&lt;br&gt;
  "message": "Order placed successfully",&lt;br&gt;
  "data": {&lt;br&gt;
    "orderId": 14,&lt;br&gt;
    "totalAmount": 4299&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;My frontend initially wasn't extracting the nested data correctly.&lt;/p&gt;

&lt;p&gt;This resulted in:&lt;/p&gt;

&lt;p&gt;Order created but Order ID was not received.&lt;/p&gt;

&lt;p&gt;I debugged it by printing the raw response:&lt;/p&gt;

&lt;p&gt;console.log(&lt;br&gt;
    "RAW ORDER RESPONSE:",&lt;br&gt;
    JSON.stringify(order, null, 2)&lt;br&gt;
);&lt;/p&gt;

&lt;p&gt;The response showed me that I was reading the wrong level of the JSON structure.&lt;/p&gt;

&lt;p&gt;I fixed the API layer so that placeOrder() returns:&lt;/p&gt;

&lt;p&gt;return {&lt;br&gt;
    orderId: order.orderId,&lt;br&gt;
    totalAmount: order.totalAmount&lt;br&gt;
};&lt;/p&gt;

&lt;p&gt;This was a good reminder that frontend/backend integration bugs are often response-contract bugs, not business-logic bugs.&lt;/p&gt;

&lt;p&gt;🐛 Challenge 2 — Razorpay Was Not Opening Reliably&lt;/p&gt;

&lt;p&gt;Another confusing problem was that Razorpay sometimes didn't open when I clicked Place Order from the cart flow.&lt;/p&gt;

&lt;p&gt;But when I manually opened Checkout.html, it worked.&lt;/p&gt;

&lt;p&gt;I initially suspected Razorpay itself.&lt;/p&gt;

&lt;p&gt;The actual problem was in my application flow and state handling around the cart/checkout page.&lt;/p&gt;

&lt;p&gt;I traced the complete flow instead of assuming the payment gateway was broken:&lt;/p&gt;

&lt;p&gt;Cart&lt;br&gt;
 ↓&lt;br&gt;
Checkout&lt;br&gt;
 ↓&lt;br&gt;
Create Order&lt;br&gt;
 ↓&lt;br&gt;
Create Razorpay Order&lt;br&gt;
 ↓&lt;br&gt;
Open Razorpay&lt;/p&gt;

&lt;p&gt;This debugging process helped me separate:&lt;/p&gt;

&lt;p&gt;application bugs&lt;/p&gt;

&lt;p&gt;from&lt;/p&gt;

&lt;p&gt;payment gateway bugs.&lt;/p&gt;

&lt;p&gt;That distinction saved a lot of time.&lt;/p&gt;

&lt;p&gt;🐛 Challenge 3 — Payment Failed But Database Still Had CREATED&lt;/p&gt;

&lt;p&gt;This was a more important backend problem.&lt;/p&gt;

&lt;p&gt;When a Razorpay payment failed, I initially had a record like:&lt;/p&gt;

&lt;p&gt;Payment&lt;br&gt;
Status = CREATED&lt;/p&gt;

&lt;p&gt;even though the user had already failed the payment.&lt;/p&gt;

&lt;p&gt;That meant my database wasn't representing the actual payment state.&lt;/p&gt;

&lt;p&gt;I implemented a failure endpoint:&lt;/p&gt;

&lt;p&gt;POST /payments/fail&lt;/p&gt;

&lt;p&gt;and added logic to update the payment:&lt;/p&gt;

&lt;p&gt;payment.setStatus(&lt;br&gt;
    PaymentStatus.FAILED&lt;br&gt;
);&lt;/p&gt;

&lt;p&gt;paymentRepository.save(payment);&lt;/p&gt;

&lt;p&gt;The frontend listens for Razorpay's failure event:&lt;/p&gt;

&lt;p&gt;razorpay.on(&lt;br&gt;
    "payment.failed",&lt;br&gt;
    async function(response) {&lt;br&gt;
        ...&lt;br&gt;
    }&lt;br&gt;
);&lt;/p&gt;

&lt;p&gt;and records the failure on the backend.&lt;/p&gt;

&lt;p&gt;After that, my database correctly reflected:&lt;/p&gt;

&lt;p&gt;Payment → FAILED&lt;br&gt;
🐛 Challenge 4 — Failed Payment Was Clearing My Cart&lt;/p&gt;

&lt;p&gt;This was probably the most important business-logic issue I encountered.&lt;/p&gt;

&lt;p&gt;Initially, the order creation flow deleted cart items immediately after creating the order.&lt;/p&gt;

&lt;p&gt;That produced this problem:&lt;/p&gt;

&lt;p&gt;Cart&lt;br&gt;
 ↓&lt;br&gt;
Create Order&lt;br&gt;
 ↓&lt;br&gt;
Cart deleted ❌&lt;br&gt;
 ↓&lt;br&gt;
Payment&lt;br&gt;
 ↓&lt;br&gt;
Payment FAILED&lt;/p&gt;

&lt;p&gt;Now the customer had paid nothing, but their cart was already empty.&lt;/p&gt;

&lt;p&gt;That's bad e-commerce behavior.&lt;/p&gt;

&lt;p&gt;✅ The Solution — Clear Cart Only After Successful Payment&lt;/p&gt;

&lt;p&gt;I changed the flow so that creating an order does not immediately delete the cart.&lt;/p&gt;

&lt;p&gt;Instead:&lt;/p&gt;

&lt;p&gt;Order Created&lt;br&gt;
 ↓&lt;br&gt;
Payment Created&lt;br&gt;
 ↓&lt;br&gt;
Razorpay Payment&lt;/p&gt;

&lt;p&gt;Only after successful payment verification:&lt;/p&gt;

&lt;p&gt;Payment SUCCESS&lt;br&gt;
 ↓&lt;br&gt;
Order CONFIRMED&lt;br&gt;
 ↓&lt;br&gt;
Cart Cleared&lt;/p&gt;

&lt;p&gt;The backend finds the user's cart:&lt;/p&gt;

&lt;p&gt;Cart cart =&lt;br&gt;
        cartRepository&lt;br&gt;
        .findByUser(order.getUser())&lt;br&gt;
        .orElse(null);&lt;/p&gt;

&lt;p&gt;Then retrieves its items:&lt;/p&gt;

&lt;p&gt;List cartItems =&lt;br&gt;
        cartItemRepository&lt;br&gt;
        .findByCart(cart);&lt;/p&gt;

&lt;p&gt;and deletes them only after successful payment.&lt;/p&gt;

&lt;p&gt;This gives the correct behavior:&lt;/p&gt;

&lt;p&gt;Successful payment&lt;br&gt;
Payment = SUCCESS&lt;br&gt;
Order = CONFIRMED&lt;br&gt;
Cart = EMPTY&lt;br&gt;
Failed payment&lt;br&gt;
Payment = FAILED&lt;br&gt;
Order = PENDING&lt;br&gt;
Cart = PRESERVED&lt;br&gt;
🧠 Challenge 5 — Java Method/Brace Error&lt;/p&gt;

&lt;p&gt;While modifying PaymentService, I also introduced a simple but annoying Java structure error.&lt;/p&gt;

&lt;p&gt;I accidentally placed:&lt;/p&gt;

&lt;p&gt;markPaymentAsFailed()&lt;/p&gt;

&lt;p&gt;inside:&lt;/p&gt;

&lt;p&gt;verifyPayment()&lt;/p&gt;

&lt;p&gt;because a closing brace was missing.&lt;/p&gt;

&lt;p&gt;The compiler then highlighted:&lt;/p&gt;

&lt;p&gt;return true;&lt;/p&gt;

&lt;p&gt;which initially made it look like return true itself was the problem.&lt;/p&gt;

&lt;p&gt;The actual issue was the method structure.&lt;/p&gt;

&lt;p&gt;The correct structure is:&lt;/p&gt;

&lt;p&gt;verifyPayment() {&lt;br&gt;
    ...&lt;br&gt;
    return true;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;markPaymentAsFailed() {&lt;br&gt;
    ...&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This was a small bug, but it reinforced an important debugging lesson:&lt;/p&gt;

&lt;p&gt;When Java highlights a perfectly valid line, don't automatically assume that line is the real problem. Check the surrounding structure first.&lt;/p&gt;

&lt;p&gt;🔄 Final Payment Flow&lt;/p&gt;

&lt;p&gt;After fixing these issues, the complete flow became:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             SHOP EASE
                 │
               Cart
                 │
             Checkout
                 │
          Create Order
                 │
          MySQL Order
                 │
      Create Razorpay Order
                 │
         Razorpay Checkout
             /       \
            /         \
       SUCCESS       FAILURE
          │              │
   Verify Signature      │
          │              │
    Payment SUCCESS  Payment FAILED
          │              │
   Order CONFIRMED   Order PENDING
          │              │
     Clear Cart     Keep Cart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;🧪 Testing&lt;/p&gt;

&lt;p&gt;I tested both important scenarios.&lt;/p&gt;

&lt;p&gt;Successful Payment&lt;/p&gt;

&lt;p&gt;Result:&lt;/p&gt;

&lt;p&gt;Order ID: 20&lt;br&gt;
Status: CONFIRMED&lt;br&gt;
Total: ₹3499&lt;br&gt;
Payment: SUCCESS&lt;br&gt;
Cart: Cleared&lt;br&gt;
Failed Payment&lt;/p&gt;

&lt;p&gt;Result:&lt;/p&gt;

&lt;p&gt;Payment: FAILED&lt;br&gt;
Order: PENDING&lt;br&gt;
Cart: Preserved&lt;/p&gt;

&lt;p&gt;This was important because testing only successful payments would have hidden the cart-loss bug.&lt;/p&gt;

&lt;p&gt;🔒 Security Considerations&lt;/p&gt;

&lt;p&gt;I also made sure that sensitive payment information wasn't trusted blindly from the frontend.&lt;/p&gt;

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

&lt;p&gt;Validates the order amount&lt;br&gt;
Creates the Razorpay order&lt;br&gt;
Stores the Razorpay order ID&lt;br&gt;
Verifies the Razorpay signature&lt;br&gt;
Keeps the Razorpay secret on the backend&lt;br&gt;
Updates payment status on the backend&lt;br&gt;
Updates order status only after successful verification&lt;/p&gt;

&lt;p&gt;The frontend is responsible for initiating the checkout experience, but the backend is responsible for trusting and recording the payment result.&lt;/p&gt;

&lt;p&gt;📚 What I Learned&lt;/p&gt;

&lt;p&gt;The biggest lesson wasn't actually how to call the Razorpay API.&lt;/p&gt;

&lt;p&gt;It was understanding that payment integration is a state-management problem.&lt;/p&gt;

&lt;p&gt;A payment can move through states like:&lt;/p&gt;

&lt;p&gt;CREATED&lt;br&gt;
   ↓&lt;br&gt;
SUCCESS&lt;/p&gt;

&lt;p&gt;or:&lt;/p&gt;

&lt;p&gt;CREATED&lt;br&gt;
   ↓&lt;br&gt;
FAILED&lt;/p&gt;

&lt;p&gt;And the order has its own state:&lt;/p&gt;

&lt;p&gt;PENDING&lt;br&gt;
   ↓&lt;br&gt;
CONFIRMED&lt;/p&gt;

&lt;p&gt;These states need to remain consistent.&lt;/p&gt;

&lt;p&gt;I also learned:&lt;/p&gt;

&lt;p&gt;Never clear a cart before payment succeeds.&lt;br&gt;
Always verify payment on the backend.&lt;br&gt;
Don't expose payment secrets in frontend code.&lt;br&gt;
Debug the complete frontend → API → service → database flow.&lt;br&gt;
API response structure matters as much as business logic.&lt;br&gt;
Always test failure scenarios, not just the happy path.&lt;br&gt;
Payment integration is tightly connected to order and cart state.&lt;br&gt;
🚀 What's Next?&lt;/p&gt;

&lt;p&gt;Razorpay completes another major part of ShopEase.&lt;/p&gt;

&lt;p&gt;The next areas I want to work on are:&lt;/p&gt;

&lt;p&gt;Admin Dashboard&lt;br&gt;
User Management&lt;br&gt;
Inventory Management&lt;br&gt;
Automated Testing&lt;br&gt;
Pagination&lt;br&gt;
Sorting&lt;br&gt;
Advanced Search&lt;br&gt;
Docker&lt;br&gt;
CI/CD&lt;br&gt;
Deployment&lt;/p&gt;

&lt;p&gt;Eventually, I want to take ShopEase from a learning project toward a more production-oriented architecture.&lt;/p&gt;

&lt;p&gt;🎯 Final Thoughts&lt;/p&gt;

&lt;p&gt;Implementing Razorpay wasn't just about adding a payment popup.&lt;/p&gt;

&lt;p&gt;The real challenge was making sure that:&lt;/p&gt;

&lt;p&gt;Payment&lt;br&gt;
   ↕&lt;br&gt;
Order&lt;br&gt;
   ↕&lt;br&gt;
Cart&lt;/p&gt;

&lt;p&gt;all remain consistent.&lt;/p&gt;

&lt;p&gt;The bugs I encountered—missing order IDs, incorrect response handling, failed payment state, cart deletion and Java method structure issues—were actually more valuable than simply getting the first successful payment.&lt;/p&gt;

&lt;p&gt;That's what made this implementation useful as a development experience.&lt;/p&gt;

&lt;p&gt;ShopEase now has a complete tested payment flow using Razorpay Test Mode, with backend verification, payment status tracking, order confirmation, failure handling and correct cart behavior.&lt;br&gt;
ShopEase -Shitanshu Jha&lt;/p&gt;

&lt;h1&gt;
  
  
  java #springboot #razorpay #ecommerce #webdev
&lt;/h1&gt;

</description>
    </item>
    <item>
      <title>Building ShopEase: My Journey From a Basic E-Commerce App to a Spring Boot Backend</title>
      <dc:creator>Shitanshu Jha</dc:creator>
      <pubDate>Sat, 22 Aug 2026 02:33:38 +0000</pubDate>
      <link>https://dev.to/shitanshu686/building-shopease-my-journey-from-a-basic-e-commerce-app-to-a-spring-boot-backend-4bah</link>
      <guid>https://dev.to/shitanshu686/building-shopease-my-journey-from-a-basic-e-commerce-app-to-a-spring-boot-backend-4bah</guid>
      <description>&lt;p&gt;Building ShopEase: My Journey From a Basic E-Commerce App to a Spring Boot Backend&lt;/p&gt;

&lt;p&gt;By Shitanshu Jha&lt;/p&gt;

&lt;p&gt;**👋 Hi, I'm Shitanshu Jha&lt;/p&gt;

&lt;p&gt;I'm a BCA student and Java Developer focused on backend development and building real-world applications with Java, Spring Boot, REST APIs, MySQL, and Spring Security.**&lt;/p&gt;

&lt;p&gt;I'm currently pursuing my Bachelor of Computer Applications at Guru Gobind Singh Indraprastha University (GGSIPU). While learning software development, I wanted to move beyond small practice programs and understand how a complete application is actually designed, connected, secured, tested, and developed over time.&lt;/p&gt;

&lt;p&gt;That's what led me to build ShopEase.&lt;/p&gt;

&lt;p&gt;ShopEase is a full-stack e-commerce application that I'm developing module by module, starting from basic product management and gradually adding authentication, authorization, cart management, wishlist, checkout, orders, and payment integration. The project currently has a Java/Spring Boot backend, JavaScript frontend, MySQL database, JWT authentication, role-based authorization, and several integrated modules.**&lt;/p&gt;

&lt;p&gt;How I built and evolved a full-stack e-commerce application using Java, Spring Boot, MySQL, JavaScript, JWT authentication, and REST APIs.&lt;br&gt;
When I started building ShopEase, my goal wasn't to create a perfect e-commerce application from day one.&lt;/p&gt;

&lt;p&gt;I wanted to understand what actually happens behind a real application — how the frontend communicates with a backend, how data is stored, how authentication works, how users are authorized, and how different features come together into one system.&lt;/p&gt;

&lt;p&gt;ShopEase started as an e-commerce project and gradually evolved into a much larger full-stack application.&lt;/p&gt;

&lt;p&gt;Today, it has a Java + Spring Boot backend, a JavaScript frontend, MySQL database integration, JWT authentication, role-based authorization, persistent cart and wishlist functionality, checkout and order management, validation, DTOs, and centralized exception handling.&lt;br&gt;
🛠️ Tech Stack&lt;br&gt;
Frontend&lt;br&gt;
HTML&lt;br&gt;
CSS&lt;br&gt;
JavaScript&lt;br&gt;
Fetch API&lt;br&gt;
LocalStorage&lt;br&gt;
Backend&lt;br&gt;
Java&lt;br&gt;
Spring Boot&lt;br&gt;
Spring MVC&lt;br&gt;
Spring Data JPA&lt;br&gt;
Hibernate&lt;br&gt;
Spring Security&lt;br&gt;
JWT&lt;br&gt;
BCrypt&lt;br&gt;
Jakarta Validation&lt;br&gt;
Database&lt;br&gt;
MySQL&lt;br&gt;
Tools&lt;br&gt;
Eclipse&lt;br&gt;
Postman&lt;br&gt;
XAMPP&lt;br&gt;
Git&lt;br&gt;
GitHub&lt;br&gt;
🏗️ The Architecture&lt;/p&gt;

&lt;p&gt;The basic architecture of ShopEase looks like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                ShopEase
                   │
      ┌────────────┴────────────┐
      │                         │
  FRONTEND                   BACKEND
      │                         │
HTML / CSS / JS            Spring Boot
      │                         │
  Fetch API               Spring MVC
      │                         │
   api.js               Spring Security
      │                         │
      └────── REST API ─────────┘
                   │
                  JWT
                   │
                 MySQL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The frontend communicates with the Spring Boot backend through REST APIs, while authentication is handled using JWT.&lt;/p&gt;

&lt;p&gt;📦 1. Building the Product System&lt;/p&gt;

&lt;p&gt;The product module was one of the first major parts of ShopEase.&lt;/p&gt;

&lt;p&gt;On the frontend, I implemented product cards containing information such as:&lt;/p&gt;

&lt;p&gt;Product image&lt;br&gt;
Name&lt;br&gt;
Brand&lt;br&gt;
Description&lt;br&gt;
Price&lt;br&gt;
Old price&lt;br&gt;
Discount&lt;br&gt;
Rating&lt;br&gt;
Stock status&lt;br&gt;
Add to cart&lt;br&gt;
View details&lt;/p&gt;

&lt;p&gt;On the backend, the product system includes:&lt;/p&gt;

&lt;p&gt;Product Entity&lt;br&gt;
Repository&lt;br&gt;
Service&lt;br&gt;
Controller&lt;br&gt;
MySQL integration&lt;br&gt;
JPA/Hibernate&lt;br&gt;
CRUD operations&lt;br&gt;
DTOs&lt;br&gt;
Validation&lt;br&gt;
Exception handling&lt;/p&gt;

&lt;p&gt;The main REST APIs are:&lt;/p&gt;

&lt;p&gt;GET    /products&lt;br&gt;
GET    /products/{id}&lt;br&gt;
POST   /products&lt;br&gt;
PUT    /products/{id}&lt;br&gt;
DELETE /products/{id}&lt;/p&gt;

&lt;p&gt;The data flows from the frontend through the Fetch API to the controller, service, repository and finally MySQL before returning a JSON response to the frontend.&lt;/p&gt;

&lt;p&gt;🔐 2. Authentication with Spring Security and JWT&lt;/p&gt;

&lt;p&gt;This was one of the more important parts of the project.&lt;/p&gt;

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

&lt;p&gt;User registration&lt;br&gt;
Login&lt;br&gt;
BCrypt password encoding&lt;br&gt;
JWT generation&lt;br&gt;
JWT validation&lt;br&gt;
JWT authentication filter&lt;br&gt;
Protected APIs&lt;br&gt;
Role-based authorization&lt;/p&gt;

&lt;p&gt;The login flow looks like:&lt;/p&gt;

&lt;p&gt;Login Form&lt;br&gt;
    ↓&lt;br&gt;
POST /users/login&lt;br&gt;
    ↓&lt;br&gt;
UserService&lt;br&gt;
    ↓&lt;br&gt;
BCrypt Verification&lt;br&gt;
    ↓&lt;br&gt;
JWT Generation&lt;br&gt;
    ↓&lt;br&gt;
Token Response&lt;br&gt;
    ↓&lt;br&gt;
LocalStorage&lt;/p&gt;

&lt;p&gt;For protected requests, the frontend automatically sends:&lt;/p&gt;

&lt;p&gt;Authorization: Bearer &lt;/p&gt;

&lt;p&gt;The backend then validates the JWT through the authentication filter and Spring Security context.&lt;/p&gt;

&lt;p&gt;👥 3. Role-Based Authorization&lt;/p&gt;

&lt;p&gt;I didn't want authentication to simply mean “the user is logged in.”&lt;/p&gt;

&lt;p&gt;Different users should have different permissions.&lt;/p&gt;

&lt;p&gt;ShopEase currently has USER and ADMIN roles.&lt;/p&gt;

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

&lt;p&gt;USER&lt;br&gt;
 ↓&lt;br&gt;
Protected API&lt;br&gt;
 ↓&lt;br&gt;
Unauthorized operation&lt;br&gt;
 ↓&lt;br&gt;
403 Forbidden&lt;/p&gt;

&lt;p&gt;while:&lt;/p&gt;

&lt;p&gt;ADMIN&lt;br&gt;
 ↓&lt;br&gt;
Protected Admin API&lt;br&gt;
 ↓&lt;br&gt;
Allowed&lt;/p&gt;

&lt;p&gt;This is used for operations such as product and specification management.&lt;/p&gt;

&lt;p&gt;🛒 4. Building a Persistent Shopping Cart&lt;/p&gt;

&lt;p&gt;The cart was where the frontend and backend really started behaving like one application.&lt;/p&gt;

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

&lt;p&gt;User&lt;br&gt;
 ↓&lt;br&gt;
Cart&lt;br&gt;
 ↓&lt;br&gt;
CartItem&lt;br&gt;
 ↓&lt;br&gt;
Product&lt;/p&gt;

&lt;p&gt;The cart supports:&lt;/p&gt;

&lt;p&gt;Add product&lt;br&gt;
View cart&lt;br&gt;
Update quantity&lt;br&gt;
Remove item&lt;br&gt;
Stock validation&lt;br&gt;
Quantity validation&lt;br&gt;
Subtotal&lt;br&gt;
Total&lt;br&gt;
Total item count&lt;/p&gt;

&lt;p&gt;The APIs are:&lt;/p&gt;

&lt;p&gt;POST   /cart&lt;br&gt;
GET    /cart&lt;br&gt;
PUT    /cart/{itemId}&lt;br&gt;
DELETE /cart/{itemId}&lt;/p&gt;

&lt;p&gt;The important part was making the cart persistent.&lt;/p&gt;

&lt;p&gt;If a user adds a product, logs out, and later logs in again, the cart is restored from the database instead of being lost.&lt;/p&gt;

&lt;p&gt;🤍 5. Adding Wishlist Functionality&lt;/p&gt;

&lt;p&gt;After the cart, I implemented a user-specific persistent wishlist.&lt;/p&gt;

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

&lt;p&gt;POST   /wishlist/{productId}&lt;br&gt;
GET    /wishlist&lt;br&gt;
DELETE /wishlist/{itemId}&lt;/p&gt;

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

&lt;p&gt;Wishlist button&lt;br&gt;
Wishlist count&lt;br&gt;
Wishlist drawer&lt;br&gt;
Product cards&lt;br&gt;
Add/remove functionality&lt;br&gt;
Wishlist state synchronization&lt;br&gt;
Empty wishlist UI&lt;/p&gt;

&lt;p&gt;I also added duplicate-product handling and ownership validation.&lt;/p&gt;

&lt;p&gt;The wishlist module is currently fully integrated and tested.&lt;/p&gt;

&lt;p&gt;🧾 6. DTOs, Validation and Exception Handling&lt;/p&gt;

&lt;p&gt;As the project became bigger, I realized that directly exposing entities through APIs wasn't a good approach.&lt;/p&gt;

&lt;p&gt;So I introduced DTOs such as:&lt;/p&gt;

&lt;p&gt;ProductRequestDTO&lt;br&gt;
ProductResponseDTO&lt;/p&gt;

&lt;p&gt;UserRequestDTO&lt;br&gt;
UserResponseDTO&lt;/p&gt;

&lt;p&gt;LoginRequestDTO&lt;br&gt;
LoginResponseDTO&lt;/p&gt;

&lt;p&gt;AddToCartRequestDTO&lt;br&gt;
UpdateCartItemDTO&lt;/p&gt;

&lt;p&gt;CartItemResponseDTO&lt;br&gt;
CartResponseDTO&lt;/p&gt;

&lt;p&gt;The purpose was to separate the API layer from the entity layer and control exactly what data enters and leaves the application.&lt;/p&gt;

&lt;p&gt;I also implemented Jakarta Validation with annotations such as:&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/notblank"&gt;@notblank&lt;/a&gt;&lt;br&gt;
@NotNull&lt;br&gt;
&lt;a class="mentioned-user" href="https://dev.to/positive"&gt;@positive&lt;/a&gt;&lt;br&gt;
&lt;a class="mentioned-user" href="https://dev.to/min"&gt;@min&lt;/a&gt;&lt;br&gt;
&lt;a class="mentioned-user" href="https://dev.to/max"&gt;@max&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and created a centralized GlobalExceptionHandler for validation, authentication, product, stock and cart-related errors.&lt;/p&gt;

&lt;p&gt;🧾 7. Checkout and Orders&lt;/p&gt;

&lt;p&gt;The project has now moved beyond just shopping-cart functionality.&lt;/p&gt;

&lt;p&gt;Checkout and order management are implemented and tested.&lt;/p&gt;

&lt;p&gt;The current flow is:&lt;/p&gt;

&lt;p&gt;USER&lt;br&gt;
 ↓&lt;br&gt;
Cart&lt;br&gt;
 ↓&lt;br&gt;
Checkout&lt;br&gt;
 ↓&lt;br&gt;
POST /orders&lt;br&gt;
 ↓&lt;br&gt;
Order Success&lt;br&gt;
 ↓&lt;br&gt;
Order Details&lt;br&gt;
 ↓&lt;br&gt;
My Orders&lt;br&gt;
 ↓&lt;br&gt;
Order History&lt;/p&gt;

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

&lt;p&gt;POST /orders&lt;br&gt;
GET  /orders&lt;br&gt;
GET  /orders/{id}&lt;/p&gt;

&lt;p&gt;It also handles user-specific order history and order-status transitions.&lt;/p&gt;

&lt;p&gt;🚧 What's Next?&lt;/p&gt;

&lt;p&gt;The next major target is payment integration.&lt;/p&gt;

&lt;p&gt;I'm currently planning the Razorpay integration around:&lt;/p&gt;

&lt;p&gt;Payment order creation&lt;br&gt;
Payment verification&lt;br&gt;
Payment status handling&lt;br&gt;
Order-payment integration&lt;br&gt;
Successful payment handling&lt;br&gt;
Failed payment handling&lt;br&gt;
Payment security&lt;br&gt;
Payment testing&lt;/p&gt;

&lt;p&gt;The frontend will also have payment initiation and success/failure handling.&lt;/p&gt;

&lt;p&gt;After that, the longer-term roadmap includes production hardening, automated testing, Docker, CI/CD, deployment, and eventually more advanced architecture such as microservices and event-driven communication.&lt;/p&gt;

&lt;p&gt;🧠 What I'm Learning From ShopEase&lt;/p&gt;

&lt;p&gt;The biggest thing I've learned from this project is that building a real application is very different from writing isolated code.&lt;/p&gt;

&lt;p&gt;A feature isn't finished when the Java class compiles.&lt;/p&gt;

&lt;p&gt;It has to go through a complete workflow:&lt;/p&gt;

&lt;p&gt;Backend Development&lt;br&gt;
        ↓&lt;br&gt;
API Testing&lt;br&gt;
        ↓&lt;br&gt;
Frontend Development&lt;br&gt;
        ↓&lt;br&gt;
API Integration&lt;br&gt;
        ↓&lt;br&gt;
Full Feature Testing&lt;br&gt;
        ↓&lt;br&gt;
Bug Fixing&lt;br&gt;
        ↓&lt;br&gt;
Git Commit&lt;br&gt;
        ↓&lt;br&gt;
Git Push&lt;/p&gt;

&lt;p&gt;That process has become an important part of how I'm developing ShopEase.&lt;/p&gt;

&lt;p&gt;🚀 What's Next for ShopEase?&lt;/p&gt;

&lt;p&gt;The final goal is to take ShopEase from a learning project toward a production-oriented full-stack e-commerce application.&lt;/p&gt;

&lt;p&gt;The long-term architecture is planned around:&lt;/p&gt;

&lt;p&gt;Frontend&lt;br&gt;
   ↓&lt;br&gt;
Spring Boot Backend&lt;br&gt;
   ↓&lt;br&gt;
MySQL&lt;br&gt;
   ↓&lt;br&gt;
JWT Authentication&lt;br&gt;
   ↓&lt;br&gt;
Role-Based Authorization&lt;br&gt;
   ↓&lt;br&gt;
Cart + Wishlist&lt;br&gt;
   ↓&lt;br&gt;
Checkout&lt;br&gt;
   ↓&lt;br&gt;
Orders&lt;br&gt;
   ↓&lt;br&gt;
Payment&lt;br&gt;
   ↓&lt;br&gt;
Admin Dashboard&lt;br&gt;
   ↓&lt;br&gt;
Inventory&lt;br&gt;
   ↓&lt;br&gt;
Testing&lt;br&gt;
   ↓&lt;br&gt;
Docker&lt;br&gt;
   ↓&lt;br&gt;
CI/CD&lt;br&gt;
   ↓&lt;br&gt;
Cloud Deployment&lt;/p&gt;

&lt;p&gt;The project is being developed module by module, with backend development, frontend integration, testing and Git commits forming the development workflow&lt;/p&gt;

&lt;p&gt;ShopEase is still a work in progress.&lt;/p&gt;

&lt;p&gt;I'm not trying to rush toward calling it “production-ready.” There are still important areas left to build, including payment integration, automated testing, Docker, CI/CD, deployment and production hardening.&lt;/p&gt;

&lt;p&gt;For me, that's actually the point of the project.&lt;/p&gt;

&lt;p&gt;I'm using ShopEase to understand how a real full-stack application grows from individual features into a complete system — one module at a time.&lt;/p&gt;

&lt;p&gt;GitHub: github.com/Shitanshu686&lt;br&gt;
Portfolio: shitanshu686.github.io/ShitanshuJhaaaa/&lt;br&gt;
LinkedIn: linkedin.com/in/shitanshu-jha-738012342/&lt;/p&gt;

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

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