Skip to content

SowTag/sprank

Repository files navigation

Sprank

Sprank is a robust, ledger-based banking and payment processing API built with Spring Boot.

This project was engineered to manage a complex, real-world financial domain model, using a double-entry bookkeeping system for transaction integrity and audibility. It accurately handles a wide array of core banking features, including:

  • Cash deposits and transfers
  • Real-time transaction processing
  • Taxes and service fees calculations
  • QR payments and payment requests
  • Multiple currencies

Index

The main purpose of the project

My goal is to highlight my ability to create complex systems with complex business logic. That's what inspired many decisions like the ledger-based system, of course having a balance column in the database would've been much easier but not as interesting.

Screenshots

Grafana dashboard

Transaction legs in the database

Query:

SELECT t.id, t.created_at, tl.id, tl.account_id, running_balance, debit_amount debit, credit_amount credit
FROM transaction t
         JOIN sprank.transaction_leg tl on t.id = tl.transaction_id
ORDER BY t.created_at;

The screenshot below showcases a few deposits and transactions (the ones that were used to demo the Grafana dashboard)

Entity-relationship diagram (ERD)

Features

The main features implemented right now are:

  • Double-entry bookkeeping system for transaction auditability and integrity
  • Alias system for easy to remember accounts (similar to Argentina's alias/CVU/CBU system)
  • Administrative freezing and unfreezing of accounts
  • Multiple currencies
  • Transaction requests, which allow for QR-code based payments
  • Cash deposits with a cash reserve system
  • Configurable taxes and fees that can apply depending on different facts about the transaction, accounts involved, customers, etc.
  • Externally managed auth using Keycloak as IdP
  • Fully Dockerized setup (application, DB and metrics)
  • CI/CD GitHub pipeline for continuous builds and tests
  • Business metrics with Micrometer/Prometheus/Grafana

Project structure

The project follows a simple structure. It is not domain separated since it only has a few domains, and is implemented a bit like how you'd implement a single-domain microservice.

main
├── java/dev/maddock/sprank
│   ├── advice                  Controller advice (exception handling)
│   ├── annotation              Utility annotations
│   │   ├── resolver                Annotation resolvers (for Spring's MethodArgumentResolvers)
│   │   └── validator               Validators (for annotations used to validate DTOs)
│   ├── config                  Config classes
│   │   ├── fee                     Fee-related transaction modifiers
│   │   └── tax                     Tax-related transaction modifiers
│   ├── controller              HTTP Controllers (@RestController)
│   │   ├── account
│   │   ├── customer
│   │   ├── deposit
│   │   ├── request
│   │   └── transaction
│   ├── dto                     DTOs
│   │   ├── account
│   │   ├── customer
│   │   ├── deposit
│   │   ├── error
│   │   ├── request
│   │   └── transaction
│   ├── entity                  JPA entities
│   ├── enumeration             Enums
│   ├── exception               Business-specific exceptions (like InsufficientFundsException)
│   │   ├── account
│   │   ├── auth
│   │   ├── customer
│   │   ├── deposit
│   │   ├── exchange
│   │   └── transaction
│   ├── repository              JPA repositories
│   └── service                 Service interfaces
│       └── impl                    Service implementations
└── resources
    ├── db                      Database stuff, includes a script with default accounts for transaction modifiers
    │   └── migration               Flyway migrations
    └── META-INF

Technical highlights

  • Stack: Spring Boot, MySQL (JPA/Hibernate)

  • Security: Managed by Keycloak as the dedicated identity provider (IdP), see docker-compose.yml

  • CI/CD: Fully containerized with a Dockerfile and docker-compose.yml setup. The pipeline includes a build and a test step and is available on the GitHub Actions page

  • Testing: The API is thoroughly tested and has reached 90% test coverage ( see test/). The current test count as of commit 62aa1dd is 129, covering over 6000 lines of code.

  • Documentation: The project is also extensively documented, with Javadoc comments, READMEs and even an OpenAPI Specification.

  • Monitoring: The project exposes Micrometer metrics over the /actuator/prometheus endpoint, allowing monitoring of different business and runtime metrics (screenshot)

  • Code quality: Apart from being extensively documented, the code applies common practices like SOLID and DRY.

Limitations

There's a small limitation with the current system. Ideally, in a double-entry bookkeeping system, amounts are stored in a common currency, used as a reference value (commonly known as the "base" or "functional" currency). Being an argentinian myself, I'm well accustomed to inflation and volatility, and a conscious choice has been made to record transactions using each account's own currency. This is technically incorrect, but a decent and (in my opinion) acceptable compromise.

Using a single currency would require accounting for asset loss/growth thanks to currency value fluctuations, which would require handling income and expenses. This requirement also includes calculating said income and expenses, which in turn increases complexity considerably.

TL;DR: I deliberately chose to implement double-entry bookkeeping slightly incorrectly for simplicity and to reduce time to portfolio (TTP!)

About

Double-entry bookkeeping, Spring-based banking API

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published