A small suite of personal-finance calculators — a Vaadin (Spring Boot) web app. Pick a calculator, enter your numbers, and get an instant year-by-year projection with charts and a shareable link.
The Retirement Planner — live summary cards, an interactive projection chart, and a year-by-year breakdown that all recompute as you type:
Calculators included:
| Calculator | What it answers |
|---|---|
| Retirement Planner | Will my corpus last through retirement? Projects cashflow to life expectancy. |
| Goal Planner | How much must I invest monthly to hit a post-tax goal by a deadline? |
| Investment | What does a regular contribution grow to over an invest-and-hold horizon? |
| Loan / EMI | What's my EMI, and how do prepayments cut the tenure or interest? |
| Inflation Projection | What will an amount be worth across a horizon — forward or backward? |
| Buy vs Rent | Is buying a home better than renting and investing the difference? |
Your data stays in your browser. Inputs and preferences are saved to the
browser's localStorage — there's no database and nothing is sent to a server
to be stored. A "Share" link encodes the scenario into the URL itself, so
sharing is opt-in and self-contained.
Supports three currencies (₹ INR, € EUR, $ USD) and a light/dark theme.
A prebuilt, multi-architecture image (linux/amd64 + linux/arm64) is published
to Docker Hub at binarycodes/calculators.
No build, no license key, no configuration required.
docker run --rm -p 8080:8080 binarycodes/calculators:latestThen open http://localhost:8080.
- Use
binarycodes/calculators:latestfor the newest build, or pin a version tag — images are also tagged with the project's Maven version. - The app listens on port 8080. Override it with the
PORTenvironment variable:-e PORT=9090 -p 9090:9090.
services:
calculators:
image: binarycodes/calculators:latest
ports:
- "8080:8080"
restart: unless-stoppedIf you run Podman, a Quadlet
lets systemd manage the container declaratively — start on boot, restart on
failure, and optional auto-updates — without a long-running daemon. Drop this in
/etc/containers/systemd/calculators.container (rootful) or
~/.config/containers/systemd/calculators.container (rootless):
[Unit]
Description=Calculators web app
After=network-online.target
Wants=network-online.target
[Container]
Image=docker.io/binarycodes/calculators:latest
PublishPort=8080:8080
# Opt in to `podman auto-update` pulling newer :latest images.
AutoUpdate=registry
[Service]
Restart=always
[Install]
# multi-user.target for rootful; default.target for a rootless --user unit.
WantedBy=multi-user.target default.targetThen reload systemd and start it (add --user for the rootless path):
systemctl daemon-reload
systemctl start calculators.serviceWith AutoUpdate=registry, enabling podman-auto-update.timer keeps the
container on the latest published image.
Run the app behind a TLS-terminating reverse proxy (Caddy, Traefik, nginx, your
cloud load balancer, …). Beyond the usual security reasons, two features only
work in a secure context (HTTPS, or localhost):
- the Share button's native share sheet (browser Web Share API), and
- copying the share link to the clipboard.
Over plain HTTP on a LAN address (e.g. http://192.168.1.10:8080) the browser
hides these APIs: the calculators work fully, but the Share button falls back to
"Copy link" and, on iOS, the clipboard write is suppressed by the browser. Put
the app behind HTTPS and the native share sheet appears automatically — no app
configuration needed.
A minimal Caddy reverse proxy (automatic HTTPS) looks like:
calc.example.com {
reverse_proxy calculators:8080
}
Requirements: JDK 21 and Maven (a ./mvnw wrapper is included).
./mvnw spring-boot:runOpen http://localhost:8080. localhost counts as a secure context, so the
Web Share / clipboard features work here too. The frontend is rebuilt on the
fly in development mode; the first start downloads npm dependencies and takes a
little longer.
To exercise those secure-context features from another device (e.g. the Share sheet on a phone), expose your local server over HTTPS with a quick Cloudflare Tunnel — no account or DNS setup needed:
cloudflared tunnel --url http://localhost:8080It prints a temporary https://<random>.trycloudflare.com URL that proxies to
your running app; open it on the device under test. (ngrok http 8080 does the
same thing.)
This app uses commercial Vaadin components. The first time one renders in development, Vaadin Dev Tools prompts you to sign in to
vaadin.comor start a free trial. See Vaadin license below.
Run the tests:
./mvnw testProduction build (fat jar in target/):
./mvnw clean packageBuild a container — the repo ships a multi-stage Dockerfile and a
docker-bake.hcl for multi-arch builds:
# single-arch, local
docker build -t calculators:latest \
--build-arg APP_NAME=calculators \
--build-arg APP_VERSION=1.0.0-SNAPSHOT .
# multi-arch (amd64 + arm64) via Buildx Bake
docker buildx bakeVaadin license: this app uses commercial Vaadin components, so building it requires one of:
A valid Vaadin subscription (no banner). On a local machine the license is validated through your
vaadin.comlogin (stored at~/.vaadin/proKey). For a CI / Docker build, pass it as theVAADIN_SERVER_LICENSEbuild arg (wired through to-Dvaadin.offlineKey) or mount yourproKeyas a build secret.A trial build with the opt-in flag
-Dvaadin.commercialWithBanner. A production build does not enable commercial components without a license unless you opt in with this flag, which builds them in but shows a persistent banner at the bottom of the page at runtime:./mvnw clean package -Dvaadin.commercialWithBannerThe license is checked at build time, not at runtime. The prebuilt Docker Hub image is built with a license, so running it needs no key and shows no banner.
binarycodes/calculators on Docker Hub is built and pushed automatically by the
GitHub Actions CI workflow: on every push to main, the Docker image is
built and published only after mvn verify passes (the docker job is
gated on the verify job). Images are signed with cosign
and ship with provenance + SBOM attestations.
This project is licensed under the GNU General Public License v3.0 — see
LICENSE for the full text.
Note this covers the application's own source code. The commercial Vaadin components it builds against (see Vaadin license) remain governed by their own commercial terms and are not relicensed here.
