Skip to content

Repository files navigation

-ooloop-

-ooloop- — Digital Wallet

A modern bank-account management platform. Built with a hexagonal-architecture backend (Java 26 + Spring Boot) and a dependencies-free vanilla JavaScript SPA frontend.

JavaSpring BootSpring SecurityJWTMySQLRedisFlywayVanilla JS


Table of Contents


Overview

Digital Wallet is a full-stack learning project by -ooloop-: a digital bank that lets users open accounts (USD, COP, EUR…), make deposits, withdrawals and peer-to-peer transfers, track every transaction, and — for admins — manage users, customers, accounts and even run financial reconciliation reports.

The emphasis is on showing how a real-world, production-minded banking backend is designed:

  • a hexagonal (ports & adapters) architecture where domain logic is pure Java, unaware of Spring or the database;
  • concurrent-safe money operations using transactions and pessimistic locking;
  • idempotency so a double tap on "Deposit" never duplicates money;
  • rate limiting backed by Redis;
  • full audit logging of admin actions and money movements.

Features

Users & Authentication

  • Registration and login by username (not email).
  • JWT access tokens issued and validated by the API.
  • Role-based access control: USER and ADMIN.
  • Promote / demote administration privileges.

Customers & Accounts

  • Customer profile management (name, phone, ID, birth date).
  • Open multiple bank accounts with balance and type (CHECKINGS, SAVINGS).
  • Multi-currency balances (USD, COP, EUR…).
  • Block, activate and inactivate accounts.

Money Operations

  • Deposit, withdraw and transfer between accounts.
  • Every operation is atomic (@Transactional) and protected against concurrent races with MySQL row locks.
  • Transactions keep a full audit of balanceBefore / balanceAfter.
  • Idempotent operations via the Idempotency-Key header.
  • Transfer history per account with pagination.

Admin Console & Dashboards

  • Admin overview dashboard with KPIs.
  • User / customer / account administration.
  • Audit logs: auth events, transaction events, user-control events.
  • Reconciliation reports to verify financial consistency.

Tech Stack

Layer Technology
Language Java 26
Framework Spring Boot 4.1 (Web, Data JPA, Security, Validation)
Authentication Spring Security + JJWT (JWT access tokens)
Database MySQL 8 (via JPA/Hibernate + Flyway migrations)
Cache / Rate-limit Redis
Migrations Flyway
Frontend Vanilla JavaScript (ES Modules), HTML5, CSS3
Deployment nginx reverse proxy + Docker

Architecture

The project follows Hexagonal Architecture (Ports & Adapters), which keeps business logic independent of the frameworks around it.

src/main/java/com/ooloop/wallet/
│
├── domain/            ← pure business logic (no Spring, no SQL)
│   ├── model/         ← records & enums (User, Customer, BankAccount, Transaction…)
│   ├── port/          ← contracts/interfaces the domain needs
│   └── event/         ← domain events (registration, money, admin)
│
├── application/       ← use cases ("orchestrators")
│   └── usecase/       ← DepositCase, WithdrawCase, TransferCase, …
│
└── infraestructure/   ← adapters: Spring, HTTP, JPA, Redis, events
    ├── adapter/in/web      ← REST controllers
    ├── persistence/        ← JPA entities & repositories
    ├── config/             ← Spring configuration & beans
    ├── seed/               ← DemoDataSeeder
    └── security/           ← JWT filter, security config

Any infrastructure detail (which DB, which HTTP framework, which cache) can be swapped without touching the domain or the use cases — the exact point of a hexagonal design.

A step-by-step line-by-line tutorial on locking, idempotency, rate limiting, pagination and the full deposit flow lives in TUTORIAL_ENTENDIENDO_PROYECTO.txt.


Getting Started

Prerequisites

  • Java 26 (JDK) — required by pom.xml (java.version=26).
  • Maven (or use the included wrapper ./mvnw).
  • MySQL 8 running locally.
  • Redis running locally (redis-server).
  • (Optional but recommended) a modern browser + any static file server for the frontend.

Run the backend

Configure the credentials. In development the app reads src/main/resources/application-local.properties (this file is git-ignored — copy from the .example and fill in your values):

cp src/main/resources/application-local.properties.example \
   src/main/resources/application-local.properties

Start MySQL and Redis, then run:

./mvnw spring-boot:run

The API is served at http://localhost:8080.

To seed demo data (recommended for a first run):

SEED_DEMO_DATA=true ./mvnw spring-boot:run

Run the frontend

The frontend is static HTML/CSS/JS with no build step. Serve the frontend/ folder with any static server, e.g.:

python -m http.server 5500 --directory frontend

Then open http://localhost:5500. In development the frontend detects the port and points the API at http://localhost:8080 (CORS is enabled for that origin).

In production the same files are served behind nginx, which also reverse-proxies /auth, /users, /customers, /accounts and /admin to the backend on the same origin (no CORS, no separate port).

Demo accounts

With SEED_DEMO_DATA=true, the seeder creates:

Username Password Role Accounts
admin Admin123! ADMIN CHECKINGS USD + SAVINGS USD
demo Demo123! USER CHECKINGS USD + SAVINGS COP

Login is by username (not email).


API Reference

Base URL: http://localhost:8080 — all routes below /auth except public sign-in require the Authorization: Bearer <token> header.

Auth

Method Path Description
POST /auth/register Register a new user
POST /auth/login Login and obtain a JWT

Customers

Method Path Description
POST /customers Register a customer
GET /customers/me Current customer profile
PATCH /customers/me Update own profile
GET /customers List customers (admin)
PATCH /customers/{id}/block Block a customer (admin)
PATCH /customers/{id}/activate Activate a customer (admin)
PATCH /customers/{id}/inactivate Inactivate a customer (admin)

Accounts

Method Path Description
POST /accounts Open a new account
GET /accounts/me List my accounts
GET /accounts/{accountNumber} Account detail
PATCH /accounts/{id}/block Block an account (admin)
PATCH /accounts/{id}/activate Activate an account
PATCH /accounts/{id}/inactivate Inactivate an account
POST /accounts/{accountNumber}/deposit Deposit funds (idempotent)
POST /accounts/{accountNumber}/withdraw Withdraw funds (idempotent)
POST /accounts/{accountNumber}/transfer Transfer to another account (idempotent)
GET /accounts/{accountNumber}/transactions Account transaction history

Users

Method Path Description
GET /users List users (admin)
GET /users/me Current user
GET /users/{id} User by id (admin)
PATCH /users/me Update own user
PATCH /users/{id} Update a user (admin)
PATCH /users/{id}/promote Promote to admin (admin)
PATCH /users/{id}/demote Remove admin role (admin)
DELETE /users/{id} Delete a user (admin)

Admin

Method Path Description
GET /admin/dashboard Admin KPIs dashboard
GET /admin/audit/auth Auth audit events
GET /admin/audit/transactions Transaction audit events
GET /admin/audit/user-control User control audit events
POST /admin/reconciliation/run Run a reconciliation report
GET /admin/reconciliation/reports List reconciliation reports

Money operations accept an Idempotency-Key header. The frontend generates one with crypto.randomUUID() so a double submission cannot duplicate a transfer.


Project Structure

.
├── src/
│   ├── main/
│   │   ├── java/com/ooloop/wallet/   # domain, application, infraestructure
│   │   └── resources/
│   │       ├── application.properties
│   │       ├── db/migration/         # Flyway SQL migrations (V1..V9)
│   │       └── logback-spring.xml
│   └── test/                          # unit & integration tests
├── frontend/
│   ├── index.html                    # public login + register
│   ├── app.html                      # authenticated shell (sidebar + router)
│   ├── css/                          # reset, variables, global, components, pages
│   ├── js/                           # ES modules (config, auth, api, components, pages…)
│   ├── assets/brand/                 # company logo & CEO photo
│   ├── nginx.conf                    # reverse proxy for production
│   └── Dockerfile                    # frontend nginx image
├── pom.xml                           # Maven build (Spring Boot 4.1, Java 26)
├── docker-compose.yml                # MySQL + Redis services
└── mvnw / mvnw.cmd                   # Maven wrapper

Testing

Run the test suite with the Maven wrapper:

./mvnw test

The suite covers core use cases (idempotency, exception handling, transfers, locking) at the unit/application layer using spring-boot-starter-test.


Configuration

All external configuration is read from environment variables with sensible defaults (see src/main/resources/application.properties):

Variable Default Description
DB_URL jdbc:mysql://localhost:3306/auth_db JDBC connection URL
DB_USERNAME Database user
DB_PASSWORD Database password
JWT_SECRET Secret used to sign JWT tokens
JWT_EXPIRATION 86400000 Token lifetime in ms (24 h)
REDIS_HOST localhost Redis host
REDIS_PORT 6379 Redis port
RATE_LIMIT_STORE redis Rate-limit store backend
CORS_ALLOWED_ORIGINS localhost dev ports Allowed CORS origins
SEED_DEMO_DATA false Seed demo users/accounts on startup

Local secrets such as JWT_SECRET, DB password and Redis host live in application-local.properties, which is git-ignored and must never be committed.


Security & Reliability

  • JWT authentication — stateless access tokens validated on every request; roles are read as Spring authorities (ROLE_USER / ROLE_ADMIN).
  • Password hashing — passwords are stored hashed via a PasswordEncoder port.
  • Atomic money operations — deposits, withdrawals and transfers are @Transactional and use pessimistic locking in MySQL to prevent conflicting balance updates under concurrency.
  • Idempotency — unique Idempotency-Keys prevent double charges on retries.
  • Rate limiting — Redis-backed limits throttle abusive requests.
  • Audit logging — every auth, transaction and admin (user-control) event is logged for traceability.
  • Reconciliation — scheduled/admin-driven reports cross-check financial operations for consistency.
  • CORS — restricted to allowed origins; the production nginx serves frontend and API from the same origin.
  • Flyway migrations — the schema is versioned and applied deterministically.

Roadmap

  • Core banking operations (deposits, withdrawals, transfers)
  • JWT authentication & role-based authorization
  • Concurrency-safe locking for money operations
  • Idempotency, rate limiting, audit & reconciliation
  • Admin dashboard & management console
  • Vanilla JS SPA frontend
  • CI/CD pipeline (TUTORIAL_CI_CD.txt)
  • Root .env.example & environment-driven deployment
  • Full Docker orchestration (backend + frontend + MySQL + Redis)

License

This project is released for learning and portfolio purposes. It is a demo application and does not manage real funds. See the repository for details.


Built with care by Carlos Alberto — -ooloop- · Java, Spring & clean architecture.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages