Spring Boot · Java 17

Smart Wallet Application

A server-rendered wallet service: users hold multiple currency wallets, transfer funds to each other, and move between subscription tiers that are charged against a wallet balance.

Open the demo → No install, no database. Use demo accounts or register.

The demo

The console published alongside these docs is the application's own Thymeleaf markup and stylesheets, running against a seeded registry in your browser. There is no backend behind a static host, so the services in src/main/java/app are reproduced in JavaScript: the same arithmetic, the same failure reasons, the same order of checks.

What works

Sign in, register new accounts, transfer funds, top up a wallet, switch a wallet off, upgrade or downgrade a tier, edit your profile, and read the transaction and subscription history.

Seeded state

example with a 20.00 EUR main wallet on the DEFAULT tier. An admin account, admin, also exists to manage users and inspect roles.

Where state lives

In sessionStorage, so a reload keeps your balance and a new tab starts clean. Nothing is sent to a server.

Admin functions

Signing in as admin unlocks the Admin Users console in the sidebar, allowing user status toggling and role switching.

What it does

Wallets

Every registered user gets a main EUR wallet seeded with a starting balance. Deposits and withdrawals are recorded as transactions.

Transfers

A transfer is a withdrawal from the sender paired with a deposit to the recipient's first active wallet, inside one database transaction.

Subscriptions

Default, Premium and Ultimate tiers on a monthly or yearly period. Upgrading charges the chosen wallet and completes the previous subscription.

Notifications

Preferences are pushed to a separate notification service over an OpenFeign client. The call degrades to a logged warning when that service is down.

How a transfer flows

TransferController WalletService withdrawal(sender wallet) deposit(recipient wallet) TransactionService

The controller resolves the authenticated user and hands it to WalletService.transfer, so the wallet id in the request is checked against its real owner before any balance moves. A withdrawal that fails ownership, an inactive wallet, or an insufficient balance is still persisted as a FAILED transaction with a failure reason, and the deposit never runs.

Running it locally

Requires JDK 17 and a MySQL instance on localhost:3306. The Maven wrapper is checked in, so no local Maven install is needed.

git clone https://github.com/PhoenixMaster123/smart-wallet-application.git
cd smart-wallet-application

./mvnw spring-boot:run

The app starts on http://localhost:8080 and seeds a default user from application.properties.

Profiles. dev is active by default and points at a local MySQL; the schema is created on first run. Deploy with --spring.profiles.active=prod and supply DB_URL, DB_USERNAME and DB_PASSWORD as environment variables.

Without a database

To boot against an in-memory H2 instead — this is exactly what CI does:

./mvnw clean package
java -jar target/smart-wallet-application-*.jar \
  --spring.datasource.url='jdbc:h2:mem:local;DB_CLOSE_DELAY=-1' \
  --spring.datasource.driverClassName=org.h2.Driver \
  --spring.datasource.username=sa \
  --spring.datasource.password= \
  --spring.jpa.hibernate.ddl-auto=create-drop

Routes

RouteAccessPurpose
GET /PublicLanding page
GET /loginPublicSign in
GET /registerPublicCreate an account
GET /homeUserDashboard: profile, main wallet, subscription
GET /transfersUserSend funds to another user
GET /transactionsUserTransaction history
GET /subscriptionsUserCompare and buy a tier
GET /subscriptions/historyUserPast subscriptions
GET /users/{id}/profileSelf or adminView and edit a profile
GET /usersAdminUser administration
GET /reportsAdminReporting

Architecture

Packages are organised by feature rather than by layer. Each of user, wallet, transaction and subscription owns its model, repository and service; web holds the controllers, DTOs and mappers that sit in front of them.

Quality gates

CI runs on every push and pull request against master. All three steps must pass:

StepCommand
Checkstyle./mvnw checkstyle:check
Build and test./mvnw clean verify
Boot smoke testRuns the packaged jar and waits for startup

The Checkstyle rules in config/checkstyle/checkstyle.xml are structural rather than cosmetic: imports, naming, braces and common correctness traps. Formatting an IDE already handles is left out, so the build fails only on things worth failing on.