Started Day 2 on my offline-first UPI payment system in Java + Spring Boot. Today’s focus was moving beyond basic money transfer APIs into something real products need: transaction history. Built a recent transactions endpoint that returns the last activity for a user instead of dumping raw database rows. Also started shaping responses through DTO mapping so customers only see relevant data like amount, status, counterparty, and transaction type (Sent / Received) — not internal fields. One underrated part of backend development: debugging response serialization, mapping layers, and edge cases often takes more effort than writing the endpoint itself. That’s where real learning happens. Current progress: ✅ Account creation API ✅ Payment transfer API ✅ Custom exception handling ✅ Transaction history feature in progress ✅ DTO-based response design Next steps: Finish transaction history cleanly Add timestamps JWT auth layer Idempotency for duplicate payment prevention PostgreSQL migration from H2 Building with a product mindset, not just CRUD. #Java #SpringBoot #BackendDevelopment #SystemDesign #FinTech #BuildInPublic #backenddev #SpringAI #SpringdataJPA #microservices
Building Offline UPI Payment System in Java + Spring Boot
More Relevant Posts
-
Started building an offline-first UPI payment system in Java + Spring Boot. The core problem: digital payments fail when internet drops. Most solutions assume connectivity. This one doesn't. Day 1 focused on foundations- Account and Transaction models, initial settlement logic, REST APIs for testing, and H2 for rapid prototyping (PostgreSQL planned next for persistent storage and scale). But the more interesting work was defining the real engineering challenges: • How do you prevent the same payment from being processed twice when multiple relay devices forward it simultaneously? • How do you ensure an intercepted payment packet from yesterday cannot be replayed today? • How do you route payment data through untrusted devices without those devices being able to read it? None of that is implemented yet. But clear problem definition is exactly how Day 1 should end. #Java #SpringBoot #SystemDesign #FinTech #BuildInPublic #coding #springai
To view or add a comment, sign in
-
Excited to share a project I have been working on — FinFlow, a production-inspired banking backend built with Java and Spring Boot. The goal was simple: go beyond tutorial-level projects and build something that reflects real backend engineering challenges. What FinFlow covers: 🔐 JWT Authentication — stateless session management, BCrypt password encoding, and a custom Spring Security filter chain 💸 Money Transfers — idempotency via Redis key tracking, deadlock-safe pessimistic locking with ordered lock acquisition, and atomic balance updates 📨 Event-driven Fraud Detection — Kafka-based async pipeline with a dedicated thread pool, performing high-frequency, odd-hour, and card-testing checks without impacting transaction response time ⚙️ Batch Processing — asynchronous job execution using CompletableFuture with Redisson distributed locking to prevent duplicate processing 🛡️ Resilience — Resilience4j circuit breakers with a Facade pattern, and distributed rate limiting using Bucket4j backed by Redis 🧪 Unit Testing — JUnit 5 and Mockito covering success and failure paths of core transaction logic A few challenges worth mentioning: 🔄 Resolved a circular dependency between SecurityConfig and UserService by extracting PasswordEncoder to a separate configuration class — a good reminder that Spring's bean lifecycle requires deliberate design 🔒 Prevented deadlocks in concurrent transfers by enforcing ordered lock acquisition — always locking the lower account ID first regardless of transfer direction, making a circular wait impossible Every design decision in this project has a deliberate justification — from choosing Redisson over raw Redis for locking, to using a Facade layer to separate resilience concerns from business logic. The repository is available on GitHub — feel free to explore: https://lnkd.in/gRisUBED #Java #SpringBoot #BackendDevelopment #OpenToWork #SpringSecurity #Kafka #Redis #SystemDesign
To view or add a comment, sign in
-
A subtle Spring behavior that causes real production issues: @Transactional propagation. Most people rely on the default propagation without thinking about transaction boundaries. Example: Method A → @Transactional (REQUIRED) calls Method B → @Transactional (REQUIRES_NEW) What actually happens? Method B runs in a NEW transaction. So even if Method A fails and rolls back, Method B can still commit ❌ Result: Partial data committed → inconsistent state Fix: • Use REQUIRED if operations must succeed or fail together • Use REQUIRES_NEW only when you intentionally need an independent transaction (e.g., audit/logging) • Define transaction boundaries clearly at the service layer Seen this during backend development while handling dependent operations. Lesson: Don’t rely on defaults — design your transaction boundaries consciously. #SpringBoot #Java #Transactions #Microservices #Backend #SoftwareEngineering
To view or add a comment, sign in
-
Recently, working on banking applications made me appreciate scalability even more. That makes it authentic. Writing code is one thing. Writing scalable code is another. Working with Java and Spring Boot in backend development has taught me that building APIs is not just about making them work — it’s about making them secure, maintainable, and scalable. One thing I’ve been focusing on improving is REST API design, because good API design impacts everything downstream. Still learning every day and enjoying the process. For backend developers here — what concept improved your coding the most? #Java #Springboot #BackendDevelopment #Microservices #SoftwareEngineering
To view or add a comment, sign in
-
Day 3 of Building an Offline UPI Payment System with Spring Boot Today I implemented idempotency in the payment flow using a unique requestId, while also studying the importance of concurrency handling in payment systems. What was added: • Duplicate payment requests are detected and blocked • Prevents double debit during retries or network interruptions • Proper 409 CONFLICT response handling • Custom exception flow for cleaner API behavior • Initial understanding of how concurrent duplicate requests can impact transactions Why this matters: In payment systems, retries and simultaneous requests are common. Without idempotency and concurrency safeguards, the same transaction can be processed multiple times. Current implementation works, but there is room to improve: Areas of improvement: • Return the original transaction response instead of only throwing duplicate error • Strengthen concurrent request handling with DB constraints / locking strategies • Add request payload validation for reused requestId • Introduce expiry/cleanup strategy for old idempotency keys • Improve observability with logs and audit trails Next step: I’ll be upgrading this into a more production-ready payment flow by improving concurrency safety and returning previous transaction state on retries. Built with: -Spring Boot -Spring Data JPA -H2 -REST APIs -Java Reliable backend systems are built by handling retries, race conditions, and edge cases not just successful requests. #Java #SpringBoot #BackendEngineering #Concurrency #Payments #SystemDesign #RESTAPI #SoftwareEngineering #LearningInPublic #Fintech
To view or add a comment, sign in
-
🚀 Understanding @Transactional in Spring Boot If you're working with Spring Boot, one annotation you must understand deeply is @Transactional. It plays a critical role in ensuring data consistency and integrity in your application. 🔹 What is @Transactional? @Transactional is used to manage database transactions in Spring. It ensures that a group of operations either: ✔️ All succeed (COMMIT) ❌ Or all fail together (ROLLBACK) 🔹 Why is it important? Imagine transferring money between two accounts: Debit from Account A Credit to Account B If one step fails and the other succeeds, your data becomes inconsistent. @Transactional prevents this by treating both steps as a single unit. 🔹 Key Features: ✅ Automatic transaction management ✅ Rollback on runtime exceptions ✅ Supports propagation (REQUIRED, REQUIRES_NEW, etc.) ✅ Supports isolation levels (READ_COMMITTED, SERIALIZABLE, etc.) 🔹 Example: @Service public class PaymentService { @Transactional public void transferMoney() { debit(); credit(); } } If any method fails, the entire transaction is rolled back. 🔹 Important Notes: ⚠️ Works only on public methods ⚠️ Self-invocation doesn’t trigger transactions ⚠️ By default, only unchecked exceptions cause rollback 🔹 Pro Tip: Use @Transactional at the service layer, not the controller layer, to maintain clean architecture. 💡 Mastering transactions is key to building reliable and scalable backend systems. #SpringBoot #Java #BackendDevelopment #Transactions #SoftwareEngineering #Fintech
To view or add a comment, sign in
-
Java 21 is generating buzz around Virtual Threads, but the crucial features ensuring their safety in production are often overlooked. After over a decade in Banking and Retail, I've learned that "Scalability" without "Predictability" can lead to 3 AM incidents. While many focus on the hype of "million threads," here are three essential features in Java 21 that truly matter for your Spring Boot 3 services: 1. Scoped Values (The ThreadLocal Killer): ThreadLocal was effective in a world with 200 threads, but with 1 million Virtual Threads, it can lead to memory leaks. Scoped Values enable the sharing of immutable data across threads, such as user context in banking transactions, without memory bloat and with total thread safety. It serves as the implicit method parameter we've needed. 2. Sequenced Collections (The API we should have had in 1995): If you've ever had to write list.get(list.size() - 1) or struggled with a LinkedHashMap to find the last entry, you'll appreciate this. SequencedCollection, SequencedSet, and SequencedMap introduce uniform .getFirst() and .getLast() methods, significantly reducing the risk of "off-by-one" errors in complex data processing pipelines. 3. Record Patterns & Exhaustive Switch: If you're still using instanceof and manual casting, it's time to upgrade. Deconstructing a Record directly in a switch statement (Record Patterns) revolutionizes Fintech applications. You can match, validate, and extract fields from a Transaction record in a single clean block, eliminating the "Null Check" soup. The key takeaway: Don't just update the JDK version in your pom.xml. Replace your ThreadLocals with ScopedValues and your manual deconstruction with Record Patterns. That's where the real performance gains for 2026 lie. To my fellow Java Seniors: Which of these features are you currently using in your PRs? Or are we still just "testing #Java #Java21 #SpringBoot #BackendEngineering #SoftwareArchitecture #CleanCode #FullStackDeveloper #Microservices #SystemDesign #JavaDeveloper #SeniorDeveloper #H1BTech #ProjectLoom #TechTrends2026
To view or add a comment, sign in
-
We had to switch payment gateways last year. The actual payment logic? Didn't change. Same amount, same customer, same order. What broke everything was this: Service A wanted different JSON format: Service B wanted different JSON format Same data. Completely different shape. And both want the amount in cents, not dollars. And both have their own status codes in the response — Service A returns "succeeded", Service B returns "captured" our service used 0 and 1. Both mean SUCCESS on our end. So we ended up with two DTOs, two mappers, and two places to break. I got tired of this and built a library that handles it differently. You just define the mapping once in a config file. Want to switch to Service A? Change one word. That's it. But the part I'm most happy with is transforms. The transforms handle the messy parts. Dollar to cents, status code normalization, phone masking — you register them once and reuse across every mapping. Works on the response side too. Their status codes map back to yours automatically. No new DTOs. No new mappers. Just a config file. I know this isn't a groundbreaking computer science problem, but it's the kind of thing that wastes hours every few months in almost every backend project I've seen. Built it in Spring Boot. Happy to share the repo if anyone wants to take a look or give feedback. Here is repo link if you want to use it: https://lnkd.in/geYginqf #Java #SpringBoot #Backend #OpenSource
To view or add a comment, sign in
-
How do we debug issues in a Java + Spring Boot backend ? 🏦☕ Expectation: 👉 Check logs → find issue → fix 😎 Reality: 👉 Transaction initiated… but stuck in “PROCESSING” 👉 API returns 200… but downstream failed 👉 No errors… but data is inconsistent 🥹 We’ve all been there. 🔹 Service is UP… but latency is high 🔹 Logs are clean… but transactions are incomplete 🔹 DB looks fine… but rows are locked / not committed 🔹 Metrics are green… but SLAs are breaking Spring Boot isn’t broken. The issue is usually in flow, not code. At 3 AM, debugging = Tracing one transaction across multiple systems 🔍 💡 Real skill in production = Understanding where the request is stuck 🔥 Simple technical checklist I follow: 1️⃣ Start with Transaction ID / Correlation ID → Trace request across all services (logs / tracing tools) 2️⃣ Check API Layer → Response codes, latency, timeout configs 3️⃣ Thread & JVM Check → Thread dumps (BLOCKED / WAITING threads) → GC pauses, heap usage 4️⃣ Database Layer → Long-running queries → Locks / uncommitted transactions → Connection pool exhaustion 5️⃣ Messaging Layer (Kafka / Queue) → Messages stuck / retrying / in DLQ 6️⃣ External Dependencies → Payment gateway / bank API latency or failures 7️⃣ Recent Changes → Deployment, config, timeout, retry settings ⚡ In banking systems, most issues are: → Timeouts → Partial failures → Data consistency gaps (very critical) #Java #SpringBoot #BankingSystems #FinTech #DistributedSystems #Microservices #Kafka #DevOps #SRE #ProductionSupport #Observability 🚀
To view or add a comment, sign in
-
🚨 I thought I understood Java Multithreading… until it broke my logic I started with a simple idea: 👉 Build a Bank Transaction System (deposit, withdraw, transfer) Easy, right? Then I added threads. And suddenly… Same account was getting updated by multiple threads Balances didn’t make sense Logs were completely messed up Even when code looked “correct”… output wasn’t That’s when I realized: 👉 Multithreading is not about writing threads 👉 It’s about controlling who touches data and when 💥 So I rebuilt it step by step: 1️⃣ Started simple Single-threaded system → everything worked perfectly 2️⃣ Introduced Executor Framework Used ExecutorService to run multiple transactions concurrently → Cleaner and more scalable than manual threads 3️⃣ Hit race conditions Multiple withdrawals on the same account broke consistency 4️⃣ Fixed with synchronized Made deposit & withdraw thread-safe → But transfer was still tricky 5️⃣ Enter ReentrantLock Used locks per account for transfer → Now managing two resources at once 6️⃣ Faced deadlock risk 😬 Two threads: A → B B → A Both got stuck. 7️⃣ Solved it with lock ordering Always lock smaller account ID first → Deadlock gone ✅ 😵 Then came another problem… Even when logic was correct → logs looked WRONG Example: Withdraw shows balance = 400 Deposit also shows 400 Nothing made sense 👉 Root cause: Logs were reading shared state after other threads modified it Final fix 🔥 I introduced a result object: 👉 each operation returns its own exact balance + status Now logs finally reflect reality: pool-1-thread-1 | TXN:101 | WITHDRAW | ACC:1001 | SUCCESS | Balance: 500 pool-1-thread-2 | TXN:108 | TRANSFER | FAILED | Insufficient balance 🧠 What I actually learned: Executor Framework > manual thread creation synchronized vs ReentrantLock (control matters) Race conditions are subtle but dangerous Deadlocks are real — and avoidable with design Logging in multithreaded systems is harder than it looks Concurrency is more about thinking correctly than coding This project changed my understanding from: 👉 “I can use threads” to 👉 “I can design thread-safe systems” If you’ve ever struggled with multithreading, I’d love to hear your experience 👇 #Java #Multithreading #ExecutorService #ReentrantLock #Concurrency #BackendDevelopment #LearningInPublic #SoftwareEngineering #JavaProjects
To view or add a comment, sign in
-
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development