# Wealth Tracker: a self-hosted dashboard for net worth, not a ledger

> Wealth Tracker records balances across bank accounts, payment wallets, funds, property and debt, then visualises them, and it runs either as a desktop app, a Docker container or a pm2 service on your own machine. It tracks totals rather than individual transactions, and it asks for the trust of a self-hosted deployment that holds real financial data.

**nicejade/wealth-tracker** — 💰生财有迹（Wealth Tracker）是一款专注于个人资产分析的应用程序。其核心功能是：全面记录并展示用户的资产状况，帮助用户轻松了解财务现状；运用 AI 能力，结合每种资产的特性和当前环境，提供适宜的财务建议。

- Repository: https://github.com/nicejade/wealth-tracker
- Website: https://fund.lovejade.cn
- Stars: 912 · Forks: 78
- Language: Svelte
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/nicejade-wealth-tracker

## Wealth Tracker counts balances, not transactions

The framing decision in this project is what it refuses to do. Most personal finance tools are ledgers: every payment in and every payment out gets a row, and the value comes from categorising and reconciling that stream. The project documentation goes the other way, focusing on account balances and overall totals rather than the detail of individual income and spending, with the stated aim of revealing the trend in total assets over time.

That choice shapes everything else. The asset types named in the documentation cover bank deposits and wealth management products, mobile payment platforms such as WeChat Pay and Alipay, housing provident fund and medical insurance accounts, money market funds, bonds, stocks and funds, real estate, precious metals, and outside borrowing. The visual output leans the same way, with charts for asset change and a treemap that shows how assets distribute across a flexible tag system.

For someone whose money is scattered across a dozen providers, that is a genuine gap being filled. The balance model is also the cheaper one to maintain, since there is no category taxonomy to argue about and no reconciliation step that fails when a provider changes its transaction format. What you give up is the answer to where the money went, which is a different product and a different piece of software.

## A Svelte client over a Fastify server and a SQLite file

The stack is visible in the repository topics and the layout rather than described in prose. The client is a Svelte application built with Vite, the server is Node and Fastify, and persistence goes through Sequelize onto SQLite. TailwindCSS handles styling, axios handles HTTP calls, and dayjs handles dates. The repository is a Lerna monorepo with pnpm workspaces over three packages, and the root package.json lists them explicitly.

```json
  "workspaces": [
    "client",
    "server",
    "desktop"
  ],
```

That third workspace is the interesting one, because it holds an Electron shell that runs the interface and the backend together, keeping the data on the local machine with no separate server to install. The root scripts show the same split. Building the web application runs the client and server builds, while the desktop variants wrap that build into a packaged application, with separate macOS, Windows and Linux targets and a verify step for each:

```json
    "desktop:dist:mac": "yarn desktop:build && cd desktop && npm run dist:mac",
    "desktop:verify:dist:mac": "yarn desktop:build && cd desktop && npm run dist:mac:verify",
    "desktop:dist:win": "yarn desktop:build && cd desktop && npm run dist:win",
    "desktop:verify:dist:win": "yarn desktop:build && cd desktop && npm run dist:win:verify",
```

Two constraints follow from that structure. The server is not a passive library: the start script runs a deploy command inside the server package and the process is managed by pm2 under the name wealth-tracker, so a deployment is a running Node service with a database file, not a static site.

## The Docker image bakes a Bun runtime and one SQLite volume

The published image is built from a Bun base rather than Node, and the Dockerfile is short enough to describe in full. Server dependencies are installed with production only flags, the compiled server output and static assets are copied into the image, port 8888 is exposed, and /app/data is declared as a volume so the database survives container replacement.

```dockerfile
FROM oven/bun:canary-slim

WORKDIR /app

COPY ./server/package.json /app
RUN bun install --production

COPY ./server/dist /app/dist
COPY ./server/public /app/public

EXPOSE 8888

VOLUME ["/app/data"]

CMD ["bun", "dist/index.js"]
```

The compose file the project publishes is the shortest path to a running instance, and it mounts a local ./data directory onto /app/data, which is where the SQLite file lands:

```yaml
version: '3.8'

services:
  wealth-tracker:
    image: nicejade/wealth-tracker:latest
    container_name: wealth-tracker
    ports:
      - '8888:8888'
    volumes:
      - ./data:/app/data
    restart: unless-stopped

volumes:
  data:
```

Start it with docker-compose up -d in the directory holding that file, and the interface is on http://localhost:8888, or on port 8888 of your server address if the instance runs elsewhere. The single container command is equivalent:

```bash
docker run -d -p 8888:8888 -v "$(pwd)/data:/app/data" nicejade/wealth-tracker:latest
```

The port mapping is yours to change, but nothing in the documentation suggests the application itself listens on anything other than 8888.

## Password protection is a set of environment variables, not a login flow

Access control here is deliberately minimal, and the four environment variables that matter are documented in a short list. ALLOW_PASSWORD set to true turns on the access password, PEPPER_SECRET strengthens the protection of that password, CAN_BE_RESET set to true enables a database reset path, and GOOGLE_ANALYTICS_KEY enables page view and event tracking, which has to be injected when the client is built rather than at runtime.

```bash
docker run -d -p 8888:8888 \
  -e ALLOW_PASSWORD=true \
  -e CAN_BE_RESET=true \
  -v "$(pwd)/data:/app/data" \
  nicejade/wealth-tracker:latest
```

Two things follow. The analytics key cannot be set on a container you pull from the registry, because the documentation says it is injected at client build time, so a self-hosted build that wants analytics has to rebuild the client. And the reset switch is a real operational decision: leaving CAN_BE_RESET enabled in a deployment that holds real account balances is a different risk posture from leaving it off, and the documentation describes it as a convenience for getting unstuck rather than a recovery procedure with a rotation step.

The project also operates a public demo instance at the homepage address, filled with mock data, and the documentation asks people not to enter real financial details there. That is a reasonable request, but it also means the demo cannot be used to judge how the password flow behaves on a real dataset.

## The desktop build ships without macOS notarisation

The Electron route is the most attractive option for a single user, since the interface and the backend ship together and the data stays on the machine. Installation is a download from the Releases page, and the documentation states that no separate server deployment is required.

The catch is macOS. The documentation says the current installer is not notarised or signed, and that if the system blocks the first launch you remove the quarantine attribute from the terminal:

```bash
sudo xattr -cr /Applications/Wealth\ Tracker.app
```

That is a reasonable one time step for a person running their own finances, and it is also a step that a security team will ask about. Unnotarised binaries are the normal state of small open source desktop tools, so this is friction rather than a defect, but it belongs in the adoption decision rather than in a footnote. Windows and Linux build targets exist in the scripts alongside the macOS one.

The project also runs a public demonstration deployment under pm2 with mock data for anyone who wants to click through the interface before installing anything. For a tool that deals with account balances, that demo is the fastest way to judge whether the visualisations suit you, and the fastest way to confirm that the app and the service share a design language.

## Running from source needs pm2, pnpm and Lerna together

The source install path is a monorepo workflow rather than a single npm install, and the documentation lays out the exact sequence. The tooling is installed globally first, dependencies come from pnpm, and the client and server are then started separately for development.

```bash
# clone project
git clone https://github.com/nicejade/wealth-tracker.git

cd wealth-tracker

# globally install pm2 pnpm & lerna
npm i pm2 pnpm lerna -g

# install dependencies(client & server)
pnpm i

cd client && npm start

cd server && npm start
```

The client serves on port 5173 by default, so the development URL is http://localhost:5173, while the server side runs on 8888 as in the container build. Node 16 or newer is the stated minimum, and pnpm or Yarn is recommended, with the project using pnpm workspaces alongside Lerna 8.1.

For a production run on your own machine, the project wraps the pm2 configuration into npm scripts, so the lifecycle is a set of short commands rather than a hand written ecosystem file. The start script runs the server deploy command, and the surrounding scripts stop, restart and tail the logs of a process named wealth-tracker:

```bash
npm run build
npm run start
```

That is a comfortable setup for someone who already keeps services under pm2, and a heavier one for someone who does not, since the deployment path assumes a Linux host with a process manager already in place.

## MIT licence, recent commits, and major versions twice a year

The licence is MIT, which is the least restrictive common choice and means an organisation can fork, self-host and modify the application without negotiating terms. That matters here because the whole value proposition rests on running your own copy with your own data, and the licence does nothing to stand in the way of that.

The activity record is current. The last push to the repository was on 2026-10-19, and the recent tagged versions are v3.12.0 on 2025-11-12, v4.0.0 on 2026-04-10 and v5.0.0 on 2026-06-13. The spacing between those major releases is a few months, and the most recent commit is later than the last tag, which points to work still landing between releases rather than a project that has stopped.

The roadmap section names three directions for further work, namely stronger data visualisation, stronger data security and better AI assisted analysis. The AI feature is already the most opaque part of the project, since the documentation describes it as giving financial suggestions that combine the characteristics of each asset with current conditions, without specifying which model provider is called or what data leaves the machine. That is the part to read closely before enabling it with real holdings.

## Conclusion

Wealth Tracker fits a person who holds assets across many institutions and wants one glance at the total, and who is willing to run the server, mind the database file and turn on the access password before anything sensitive lives in it. It is a poor fit for anyone who wants transaction level accounting, a shared household ledger, or a hosted service with someone else responsible for uptime, and for the desktop build, notarisation is still missing, so expect the macOS gatekeeper workaround on first launch. Before adopting it, check the ELECTRON build you download against your platform, decide whether the data directory will sit on a backed up volume, and confirm which AI analysis configuration you want switched on, since the analytics key is injected at client build time rather than at runtime.

## FAQ

### How do I run Wealth Tracker with Docker?

Create a docker-compose.yml with the wealth-tracker service on port 8888 and a ./data volume mounted at /app/data, then run docker-compose up -d in that directory and open http://localhost:8888. A single container run is also documented, using the nicejade/wealth-tracker:latest image with the same port and volume mapping.

### Does Wealth Tracker work as a desktop app?

Yes. An Electron build for macOS, Windows and Linux is published on the Releases page and runs the interface and backend together with the data on the local machine. The macOS package is not notarised or signed, so a blocked first launch is cleared with sudo xattr -cr on the installed app.

### How do I enable the access password in Wealth Tracker?

Set ALLOW_PASSWORD to true when starting the service, and set PEPPER_SECRET to strengthen the protection of that password. A separate variable named CAN_BE_RESET set to true enables the database reset function.

### Is Wealth Tracker still being worked on?

The last push was on 2026-10-19, and the recent tags are v3.12.0 on 2025-11-12, v4.0.0 on 2026-04-10 and v5.0.0 on 2026-06-13. The roadmap lists planned work on visualisation, data security and AI assisted analysis.

### What licence does Wealth Tracker use?

The repository is under the MIT licence, so self hosting, modification and redistribution are all permitted without extra terms.

## Sources

- [License: MIT](https://github.com/nicejade/wealth-tracker/blob/main/LICENSE)
- [nicejade/wealth-tracker on GitHub](https://github.com/nicejade/wealth-tracker)
- [Project website](https://fund.lovejade.cn)
- [README](https://github.com/nicejade/wealth-tracker/blob/main/README.md)
- [Releases](https://github.com/nicejade/wealth-tracker/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/nicejade-wealth-tracker
