Skip to content

Commit 50080cd

Browse files
committed
doc: README + screenshots
1 parent 8ec78be commit 50080cd

3 files changed

Lines changed: 156 additions & 0 deletions

File tree

README.md

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# Sprank
2+
3+
Sprank is a robust, ledger-based banking and payment processing API built with Spring Boot.
4+
5+
This project was engineered to manage a complex, real-world financial domain model, using a **double-entry bookkeeping
6+
system for transaction integrity and audibility**. It accurately handles a wide array of core banking features,
7+
including:
8+
9+
* Cash deposits and transfers
10+
* Real-time transaction processing
11+
* Taxes and service fees calculations
12+
* QR payments and payment requests
13+
* Multiple currencies
14+
15+
**Index**
16+
17+
* [The main purpose of the project](#the-main-purpose-of-the-project)
18+
* [Screenshots](#screenshots)
19+
* [Features](#features)
20+
* [Project structure](#project-structure)
21+
* [Technical highlights](#technical-highlights)
22+
* [Limitations](#limitations)
23+
24+
### The main purpose of the project
25+
26+
My goal is to highlight my ability to create complex systems with complex business logic. That's what inspired many
27+
decisions like the ledger-based system, of course having a `balance` column in the database would've been much easier
28+
but not as interesting.
29+
30+
### Screenshots
31+
32+
#### Grafana dashboard
33+
34+
![](./doc/assets/grafana-dash.png)
35+
36+
#### Transaction legs in the database
37+
38+
Query:
39+
40+
```sql
41+
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;
42+
```
43+
44+
The screenshot below showcases a few deposits and transactions (the ones that were used to demo the Grafana dashboard)
45+
46+
![](./doc/assets/transaction-legs.png)
47+
48+
#### Entity-relationship diagram (ERD)
49+
50+
![](./doc/assets/erd.png)
51+
52+
### Features
53+
54+
The main features implemented right now are:
55+
56+
* Double-entry bookkeeping system for transaction auditability and integrity
57+
* Alias system for easy to remember accounts (similar to Argentina's alias/CVU/CBU system)
58+
* Administrative freezing and unfreezing of accounts
59+
* Multiple currencies
60+
* Transaction requests, which allow for QR-code based payments
61+
* Cash deposits with a cash reserve system
62+
* Configurable taxes and fees that can apply depending on different facts about the transaction, accounts involved,
63+
customers, etc.
64+
* Externally managed auth using Keycloak as IdP
65+
* Fully Dockerized setup (application, DB and metrics)
66+
* CI/CD GitHub pipeline for continuous builds and tests
67+
* Business metrics with Micrometer/Prometheus/Grafana
68+
69+
### Project structure
70+
71+
The project follows a simple structure. It is **not** domain separated since it only has a few domains, and is
72+
implemented
73+
a bit like how you'd implement a single-domain microservice.
74+
75+
```
76+
main
77+
├── java/dev/maddock/sprank
78+
│ ├── advice Controller advice (exception handling)
79+
│ ├── annotation Utility annotations
80+
│ │ ├── resolver Annotation resolvers (for Spring's MethodArgumentResolvers)
81+
│ │ └── validator Validators (for annotations used to validate DTOs)
82+
│ ├── config Config classes
83+
│ │ ├── fee Fee-related transaction modifiers
84+
│ │ └── tax Tax-related transaction modifiers
85+
│ ├── controller HTTP Controllers (@RestController)
86+
│ │ ├── account
87+
│ │ ├── customer
88+
│ │ ├── deposit
89+
│ │ ├── request
90+
│ │ └── transaction
91+
│ ├── dto DTOs
92+
│ │ ├── account
93+
│ │ ├── customer
94+
│ │ ├── deposit
95+
│ │ ├── error
96+
│ │ ├── request
97+
│ │ └── transaction
98+
│ ├── entity JPA entities
99+
│ ├── enumeration Enums
100+
│ ├── exception Business-specific exceptions (like InsufficientFundsException)
101+
│ │ ├── account
102+
│ │ ├── auth
103+
│ │ ├── customer
104+
│ │ ├── deposit
105+
│ │ ├── exchange
106+
│ │ └── transaction
107+
│ ├── repository JPA repositories
108+
│ └── service Service interfaces
109+
│ └── impl Service implementations
110+
└── resources
111+
├── db Database stuff, includes a script with default accounts for transaction modifiers
112+
│ └── migration Flyway migrations
113+
└── META-INF
114+
```
115+
116+
### Technical highlights
117+
118+
* **Stack:** Spring Boot, MySQL (JPA/Hibernate)
119+
120+
* **Security:** Managed by Keycloak as the dedicated identity provider (IdP),
121+
see [docker-compose.yml](docker-compose.yml)
122+
123+
* **CI/CD:** Fully containerized with a [Dockerfile](Dockerfile) and [docker-compose.yml](docker-compose.yml) setup. The
124+
pipeline
125+
includes a build and a test step and is available
126+
on [the GitHub Actions page](https://github.com/SowTag/sprank/actions)
127+
128+
* **Testing:** The API is thoroughly tested and has reached 90% test coverage (
129+
see [test/](src/test/java/dev/maddock/sprank)). The current test count
130+
as of commit [62aa1dd](https://github.com/SowTag/sprank/commit/62aa1dda5f995425791723c8c24789a6d15394e9) is **129**,
131+
covering over **6000 lines of code**.
132+
133+
* **Documentation:** The project is also extensively documented, with Javadoc comments, READMEs and even
134+
an [OpenAPI Specification](doc/sprank-openapi.yaml).
135+
136+
* **Monitoring:** The project exposes Micrometer metrics over the `/actuator/prometheus` endpoint, allowing monitoring
137+
of different business and runtime metrics [(screenshot)](./doc/assets/grafana-dash.png)
138+
139+
* **Code quality:** Apart from being extensively documented, the code applies common practices like SOLID and DRY.
140+
141+
### Limitations
142+
143+
There's a small limitation with the current system. Ideally, in a double-entry bookkeeping system, amounts are stored in
144+
a common currency, used as a reference value (commonly known as the "base" or "functional" currency). Being an
145+
argentinian
146+
myself, I'm well accustomed to inflation and volatility, and a conscious choice has been made to record transactions
147+
using
148+
**each account's own currency**. This is technically incorrect, but a decent and (in my opinion) acceptable compromise.
149+
150+
Using a single currency would require accounting for asset loss/growth thanks to currency value fluctuations, which
151+
would
152+
require handling income and expenses. This requirement also includes calculating said income and expenses, which in turn
153+
increases complexity considerably.
154+
155+
_TL;DR: I deliberately chose to implement double-entry bookkeeping slightly incorrectly for simplicity and to reduce
156+
time to portfolio (TTP!)_

doc/assets/erd.png

140 KB
Loading

doc/assets/transaction-legs.png

98.9 KB
Loading

0 commit comments

Comments
 (0)