Backend Engineer

I build systems that
hold under pressure.

Backend developer with production experience in payment integrations, event-driven architectures, and queue-based systems. I care about transaction safety, audit trails, and building infrastructure that holds up under real load.

Currently working at Trogon Media — shipping production code daily

Experience

Where I've written code that went to production

Software Developer · Trogon Media Pvt. Ltd.
June 2025 — Present

Engineering

Systems I designed and shipped

Not tutorials. Not clones. These are domain-specific backend systems where I made real architectural decisions — and learned from the ones that didn't work.

LoanLedger

Fintech Infrastructure

A ledger-based loan management system where every financial transaction creates an immutable, hash-chained entry — the same principle banks use for audit trails. Loans go through a full lifecycle: application → async credit check → approval → Kafka-driven disbursal → EMI generation → repayment with late penalty calculation → foreclosure.

System Flow
User applies for loan ├── RiskAssessmentEngine runs async credit check on background ThreadPool │ └── CompletableFuture + custom ThreadPoolExecutor (5 core, 20 max, CallerRunsPolicy) ├── Admin approves → disburseLoan() publishes DisbursalEvent to Kafka │ └── DisbursalConsumer: credits wallet + generates installment schedule ├── Each payment: SELECT FOR UPDATE on installment row (pessimistic lock) │ ├── Wallet debit with BigDecimal precision │ ├── Late penalty = per-day rate × days overdue (rate varies by credit score) │ └── LedgerEntry created with SHA-256 hash chain (previousHash → currentHash) └── Every ledger write triggers: score recalculation + fraud detection └── FraudDetectionService: sliding-window rate limiter (ConcurrentHashMap + ArrayDeque)
Spring Boot 3.2 Spring Kafka JPA + PostgreSQL Spring Security + JWT Spring AOP Caffeine Cache Spring Actuator BigDecimal
Centralized Audit Logging — Spring AOP
Custom @Auditing annotation + @Around aspect intercepts any annotated service method ├── Captures: authenticated userId (from SecurityContext), client IP (X-Forwarded-For aware) ├── Measures: method execution time via System.currentTimeMillis() delta ├── Records: method arguments, action name, SUCCESS/FAILED status └── Persists to AuditLog entity — every loan approval, wallet debit, disbursal is traced Result: zero audit code inside business logic. Add @Auditing(action = "LOAN_DISBURSED") and it's logged.
Kafka Event Pipeline
LedgerService.record() saves hash-chained entry → publishes LedgerCreatedEvent ├── @EventListener + @Async → recalculates credit score (repayment +20, deposit +5) ├── Forwards to Kafka "ledger-topic" → LedgerConsumer (downstream analytics) └── FraudDetectionService: sliding-window rate limiter └── ConcurrentHashMap + ArrayDeque: if >10 txns in 5 sec → publishes to "fraud-topic" "disbursal-topic": LoanService publishes DisbursalEvent on approval └── DisbursalConsumer: wallet credit + installment schedule generation — fully async
View source on GitHub ↗

MedQueue

Healthcare Operations

A real-time appointment and queue management system for clinics. Patients book slots, get token numbers, and see live queue updates via WebSocket. The interesting part: a smart shuffling engine that promotes checked-in patients over no-shows in real time.

Queue Intelligence
Patient checks in at reception ├── QueueShufflingService acquires ReentrantLock │ ├── Scans today's BOOKED appointments sorted by token │ ├── Finds "holes": absent patient ahead of present patient │ └── Swaps token numbers atomically, then releases lock ├── WebSocket broadcast via STOMP to /topic/queue/{doctorId} │ └── All connected clients see updated queue positions instantly └── Doctor calls next → tracks consultation duration → calculates average wait time from historical data (totalDuration / totalConsultations)
Spring Boot 3.2 WebSocket + STOMP Spring Security + JWT JPA + PostgreSQL Spring Mail Caffeine Cache Swagger/OpenAPI
View source on GitHub ↗

Notification Platform

Multi-Tenant Infrastructure

A Kafka-driven notification microservice built to decouple delivery from the calling system entirely. A single REST call to the gateway dispatches to one, several, or all three channels — Email, SMS, and Firebase push — without the caller knowing or caring which provider handles it. Designed for multi-tenant use: each tenant gets its own Firebase app, initialized on-demand and cached.

Request → Kafka → Channel Services
POST /api/v1/notify (notificationType: EMAIL | SMS | PUSH | ALL) ├── NotificationGatewayService validates channel-specific fields │ └── email required for EMAIL, phone for SMS, fcmToken for PUSH ├── NotificationEventPublisher routes to Kafka topic(s) │ ├── email-notification-topic → brevo-email-service │ ├── sms-notification-topic → sms-service (2Factor API) │ └── push-notification-topic → firebase-fcm-service └── Gateway returns 202 ACCEPTED immediately — caller never waits on delivery
Kafka Producer — Reliability Config
Producer keyed by tenantId — ordering guarantee within a tenant's messages ├── acks=all: broker waits for all in-sync replicas before confirming ├── enable.idempotence=true: exactly-once semantics, no duplicate messages on retry └── retries=3 with CompletableFuture callback — failures logged with topic + partition + tenantId
Consumer Error Handling — All Three Services
AckMode: MANUAL_IMMEDIATE — consumer only commits offset after confirmed delivery ├── DefaultErrorHandler with FixedBackOff: 3 retries × 2 s before dead-lettering ├── Delivery failure re-throws → Kafka retries without committing the offset └── Each service independently recoverable — email outage doesn't affect SMS or push
Multi-Tenant Firebase — Dynamic App Management
Each tenant has a registered Firebase service-account JSON stored in PostgreSQL ├── FirebaseAppManager: @Cacheable("firebaseApps") keyed by tenantId │ └── Caffeine cache: max 200 tenants, evicted after 60 min of inactivity ├── On cache miss: loads JSON from DB → GoogleCredentials → FirebaseApp.initializeApp() │ └── Checks FirebaseApp.getInstance() first — guards against double-init on warm restart └── Each push delivery: FirebaseMessaging.getInstance(app).send() with correct tenant app
Spring Boot 3.2 Spring Kafka Firebase Admin SDK Brevo (Sendinblue) API 2Factor SMS API Caffeine Cache PostgreSQL Docker Compose Confluent Kafka 7.5

Writing

Things I actually worked through

Not tutorials. Notes from real production problems — what broke, why it broke, and what it taught me.

Legacy ERP Refactoring PHP / CodeIgniter 3 4 min read · May 2026

That One Time the PF Report Went Blank for a Single Person

The HR person called and said — "the PF report is fine for everyone, but one person's data isn't showing up." No error. No crash. Just gone. Works for 23 people, silently breaks for one.

Read post ↗

Toolkit

What I work with

Languages
  • Java 17
  • PHP
  • JavaScript
  • SQL
Backend
  • Spring Boot
  • Spring Security
  • Spring Data JPA
  • Spring Kafka
Data
  • PostgreSQL
  • MySQL
  • Caffeine Cache
  • Kafka
Infrastructure
  • Docker / Compose
  • Kafka (Confluent)
  • Microservices
  • Event-Driven Design
Practices
  • REST API Design
  • JWT Authentication
  • WebSocket / STOMP
  • Git

Education

Background

KMCT College of Engineering
B.Tech Information Technology — CGPA 7.5
2025

Building something that needs a backend engineer who cares about getting the details right?