<?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: Ankur</title>
    <description>The latest articles on DEV Community by Ankur (@ankur400web).</description>
    <link>https://dev.to/ankur400web</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%2F4128415%2Fe0b9aca1-e7ab-4800-ba10-02a3a484ab55.png</url>
      <title>DEV Community: Ankur</title>
      <link>https://dev.to/ankur400web</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ankur400web"/>
    <language>en</language>
    <item>
      <title>How I Built a Banking System Backend with Java, Spring Boot, JWT, Docker and GitHub Actions</title>
      <dc:creator>Ankur</dc:creator>
      <pubDate>Wed, 23 Sep 2026 10:59:56 +0000</pubDate>
      <link>https://dev.to/ankur400web/how-i-built-a-banking-system-backend-with-java-spring-boot-jwt-docker-and-github-actions-4mb6</link>
      <guid>https://dev.to/ankur400web/how-i-built-a-banking-system-backend-with-java-spring-boot-jwt-docker-and-github-actions-4mb6</guid>
      <description>&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Start with why you built it:&lt;/p&gt;

&lt;p&gt;Most of my earlier Java projects focused on learning individual concepts. For this project, I wanted to put those concepts together into something closer to a real backend system.&lt;/p&gt;

&lt;p&gt;I built a banking management system using Java and Spring Boot, with authentication, authorization, transaction processing, database migrations, automated testing, Docker, and CI/CD.&lt;/p&gt;

&lt;p&gt;The goal wasn't to build an actual production banking platform, but to practice the engineering patterns and infrastructure involved in building a production-style backend.&lt;/p&gt;

&lt;p&gt;This is a much better opening than simply listing your technologies.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What I built&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Show the architecture:&lt;/p&gt;

&lt;p&gt;Client&lt;br&gt;
   ↓&lt;br&gt;
REST Controllers&lt;br&gt;
   ↓&lt;br&gt;
DTOs + Validation&lt;br&gt;
   ↓&lt;br&gt;
Services&lt;br&gt;
   ↓&lt;br&gt;
Repositories&lt;br&gt;
   ↓&lt;br&gt;
MySQL&lt;/p&gt;

&lt;p&gt;Then explain the supporting infrastructure:&lt;/p&gt;

&lt;p&gt;Spring Security + JWT&lt;br&gt;
        ↓&lt;br&gt;
Authentication / Authorization&lt;/p&gt;

&lt;p&gt;Flyway&lt;br&gt;
        ↓&lt;br&gt;
Database migrations&lt;/p&gt;

&lt;p&gt;Docker&lt;br&gt;
        ↓&lt;br&gt;
Application container&lt;/p&gt;

&lt;p&gt;GitHub Actions&lt;br&gt;
        ↓&lt;br&gt;
CI/CD&lt;/p&gt;

&lt;p&gt;GHCR&lt;br&gt;
        ↓&lt;br&gt;
Container registry&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tech stack&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Use a table:&lt;/p&gt;

&lt;p&gt;Technology  Purpose&lt;br&gt;
Java 21 Backend language&lt;br&gt;
Spring Boot Application framework&lt;br&gt;
Spring Security Authentication &amp;amp; authorization&lt;br&gt;
JWT Stateless authentication&lt;br&gt;
MySQL   Relational database&lt;br&gt;
JPA/Hibernate   Persistence&lt;br&gt;
Flyway  Database migrations&lt;br&gt;
JUnit/Mockito/MockMvc   Testing&lt;br&gt;
Docker  Containerization&lt;br&gt;
Docker Compose  Local multi-container environment&lt;br&gt;
GitHub Actions  CI/CD&lt;br&gt;
GHCR    Container registry&lt;br&gt;
Springdoc OpenAPI   API documentation&lt;br&gt;
Actuator    Monitoring&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User &amp;amp; account management&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Explain the actual functionality:&lt;/p&gt;

&lt;p&gt;User&lt;br&gt;
 ├── Create&lt;br&gt;
 ├── Retrieve&lt;br&gt;
 ├── Update&lt;br&gt;
 ├── Delete&lt;br&gt;
 └── Change password&lt;/p&gt;

&lt;p&gt;User&lt;br&gt;
 │&lt;br&gt;
 └── Accounts&lt;br&gt;
       ├── Account number&lt;br&gt;
       ├── Account type&lt;br&gt;
       └── Balance&lt;/p&gt;

&lt;p&gt;Don't over-explain basic CRUD. Spend more article space on the interesting engineering decisions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;JWT authentication&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This deserves its own section.&lt;/p&gt;

&lt;p&gt;Explain:&lt;/p&gt;

&lt;p&gt;Login&lt;br&gt;
  ↓&lt;br&gt;
Validate credentials&lt;br&gt;
  ↓&lt;br&gt;
Generate JWT&lt;br&gt;
  ↓&lt;br&gt;
Client stores token&lt;br&gt;
  ↓&lt;br&gt;
Authorization: Bearer &lt;br&gt;
  ↓&lt;br&gt;
JWTAuthenticationFilter&lt;br&gt;
  ↓&lt;br&gt;
Validate token&lt;br&gt;
  ↓&lt;br&gt;
Authenticate request&lt;/p&gt;

&lt;p&gt;Then explain why you chose stateless authentication.&lt;/p&gt;

&lt;p&gt;You can include a Swagger screenshot here.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Transaction system&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This should be one of the main sections.&lt;/p&gt;

&lt;p&gt;Explain:&lt;/p&gt;

&lt;p&gt;Deposit&lt;br&gt;
Account balance&lt;br&gt;
      ↓&lt;br&gt;
Add amount&lt;br&gt;
      ↓&lt;br&gt;
Save new balance&lt;br&gt;
      ↓&lt;br&gt;
Create transaction record&lt;br&gt;
Withdrawal&lt;br&gt;
Account balance&lt;br&gt;
      ↓&lt;br&gt;
Check sufficient funds&lt;br&gt;
      ↓&lt;br&gt;
Subtract amount&lt;br&gt;
      ↓&lt;br&gt;
Save new balance&lt;br&gt;
      ↓&lt;br&gt;
Create transaction record&lt;br&gt;
Transfer&lt;br&gt;
Source account&lt;br&gt;
      ↓&lt;br&gt;
Validate ownership&lt;br&gt;
      ↓&lt;br&gt;
Check balance&lt;br&gt;
      ↓&lt;br&gt;
Debit source&lt;br&gt;
      ↓&lt;br&gt;
Credit destination&lt;br&gt;
      ↓&lt;br&gt;
Record transactions&lt;/p&gt;

&lt;p&gt;Then talk about the concurrency problem.&lt;/p&gt;

&lt;p&gt;That's much more interesting to a developer reading your article than "I created a POST endpoint."&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Preventing double spending&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'd make this a dedicated section:&lt;/p&gt;

&lt;p&gt;Handling concurrent transactions&lt;/p&gt;

&lt;p&gt;Explain the problem:&lt;/p&gt;

&lt;p&gt;Balance = ₹1000&lt;/p&gt;

&lt;p&gt;Request A → reads ₹1000&lt;br&gt;
Request B → reads ₹1000&lt;/p&gt;

&lt;p&gt;A withdraws ₹800&lt;br&gt;
B withdraws ₹800&lt;/p&gt;

&lt;p&gt;Without proper concurrency handling:&lt;br&gt;
₹1600 could potentially be withdrawn from ₹1000.&lt;/p&gt;

&lt;p&gt;Then explain the mechanism you implemented.&lt;/p&gt;

&lt;p&gt;This is probably one of the strongest technical parts of your project, so don't bury it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Database migrations with Flyway&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Show:&lt;/p&gt;

&lt;p&gt;V1&lt;br&gt;
 ↓&lt;br&gt;
users&lt;/p&gt;

&lt;p&gt;V2&lt;br&gt;
 ↓&lt;br&gt;
accounts&lt;/p&gt;

&lt;p&gt;V3&lt;br&gt;
 ↓&lt;br&gt;
transactions&lt;/p&gt;

&lt;p&gt;Explain why migrations are preferable to relying on Hibernate automatically changing the production schema.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Talk about the breadth of your tests.&lt;/p&gt;

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

&lt;p&gt;Service tests&lt;br&gt;
Controller tests&lt;br&gt;
Repository tests&lt;br&gt;
JWT tests&lt;br&gt;
Security tests&lt;br&gt;
Authentication tests&lt;br&gt;
Validation tests&lt;br&gt;
Exception handling tests&lt;br&gt;
Transaction tests&lt;/p&gt;

&lt;p&gt;Then show your GitHub Actions result.&lt;/p&gt;

&lt;p&gt;You can say:&lt;/p&gt;

&lt;p&gt;The project currently has 100+ automated tests, which are executed as part of the CI pipeline.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Explain your setup:&lt;/p&gt;

&lt;p&gt;Docker Compose&lt;br&gt;
│&lt;br&gt;
├── banking-api&lt;br&gt;
│      └── Spring Boot&lt;br&gt;
│&lt;br&gt;
└── banking-mysql&lt;br&gt;
       └── MySQL&lt;/p&gt;

&lt;p&gt;Then explain why you removed the dependency on locally installed application configuration and moved credentials to environment variables.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;CI/CD&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This should be another strong section.&lt;/p&gt;

&lt;p&gt;Show your actual pipeline:&lt;/p&gt;

&lt;p&gt;Git Push&lt;br&gt;
    ↓&lt;br&gt;
GitHub Actions&lt;br&gt;
    ↓&lt;br&gt;
Start MySQL&lt;br&gt;
    ↓&lt;br&gt;
Run Tests&lt;br&gt;
    ↓&lt;br&gt;
Build Application&lt;br&gt;
    ↓&lt;br&gt;
Build Docker Image&lt;br&gt;
    ↓&lt;br&gt;
Publish to GHCR&lt;/p&gt;

&lt;p&gt;Then include your GitHub Actions screenshot.&lt;/p&gt;

&lt;p&gt;This demonstrates that your CI/CD actually works.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;GitHub Container Registry&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Show the GHCR screenshot.&lt;/p&gt;

&lt;p&gt;Explain:&lt;/p&gt;

&lt;p&gt;docker pull ghcr.io/ankur400web/banking-system:main&lt;/p&gt;

&lt;p&gt;And explain that the container image is automatically published after the CI pipeline succeeds.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What I learned&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is where you can get personal.&lt;/p&gt;

&lt;p&gt;Something like:&lt;/p&gt;

&lt;p&gt;The biggest thing I learned from this project was that backend development isn't just about writing controllers and connecting a database.&lt;/p&gt;

&lt;p&gt;A real backend involves authentication, authorization, validation, database consistency, concurrency, testing, configuration management, logging, containerization, and deployment pipelines.&lt;/p&gt;

&lt;p&gt;Each feature introduced another engineering problem that I had to understand rather than simply implement.&lt;/p&gt;

&lt;p&gt;That would make a strong ending.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Project links&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At the bottom:&lt;/p&gt;

&lt;p&gt;🔗 Project&lt;/p&gt;

&lt;p&gt;GitHub:&lt;br&gt;
&lt;a href="https://github.com/Ankur400web/banking-system" rel="noopener noreferrer"&gt;https://github.com/Ankur400web/banking-system&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;docker pull ghcr.io/ankur400web/banking-system:main&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%2F96j65ermbdngqie6k751.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%2F96j65ermbdngqie6k751.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&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%2F0mtwbsdq6c0lyaonhszi.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%2F0mtwbsdq6c0lyaonhszi.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&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%2Fo3cf3bxdmwd47zir9ags.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%2Fo3cf3bxdmwd47zir9ags.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&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%2F9nbo89x1jlgrrm0jzi66.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%2F9nbo89x1jlgrrm0jzi66.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&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%2Fnfxpobs8glir2hgtolob.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%2Fnfxpobs8glir2hgtolob.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>backend</category>
      <category>docker</category>
      <category>java</category>
      <category>springboot</category>
    </item>
  </channel>
</rss>
