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 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.
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.
example with a 20.00 EUR main wallet on the DEFAULT tier. An admin account, admin, also exists to manage users and inspect roles.
In sessionStorage, so a reload keeps your balance and a new tab starts clean. Nothing is sent to a server.
Signing in as admin unlocks the Admin Users console in the sidebar, allowing user status toggling and role switching.
Every registered user gets a main EUR wallet seeded with a starting balance. Deposits and withdrawals are recorded as transactions.
A transfer is a withdrawal from the sender paired with a deposit to the recipient's first active wallet, inside one database transaction.
Default, Premium and Ultimate tiers on a monthly or yearly period. Upgrading charges the chosen wallet and completes the previous subscription.
Preferences are pushed to a separate notification service over an OpenFeign client. The call degrades to a logged warning when that service is down.
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.
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.
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
| Route | Access | Purpose |
|---|---|---|
GET / | Public | Landing page |
GET /login | Public | Sign in |
GET /register | Public | Create an account |
GET /home | User | Dashboard: profile, main wallet, subscription |
GET /transfers | User | Send funds to another user |
GET /transactions | User | Transaction history |
GET /subscriptions | User | Compare and buy a tier |
GET /subscriptions/history | User | Past subscriptions |
GET /users/{id}/profile | Self or admin | View and edit a profile |
GET /users | Admin | User administration |
GET /reports | Admin | Reporting |
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.
UserDetailsService, with method-level @PreAuthorize guarding admin and per-user routes.CI runs on every push and pull request against master. All three steps must pass:
| Step | Command |
|---|---|
| Checkstyle | ./mvnw checkstyle:check |
| Build and test | ./mvnw clean verify |
| Boot smoke test | Runs 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.