Understand your personal finances. Forget Excels, try Whisper Money.
Go to file
Víctor Falcón af64f56399
feat(onboarding): clarify the "categorize at least 5" goal in the categorizer (#616)
## Why

Feedback from onboarding users: in the categorizer step people often
**don't realize they need to categorize at least 5 transactions** before
*Continue* unlocks, and can't tell why the button is disabled. Worse,
the old counter switched to **"N remaining"** after 5 (showing *every*
uncategorized transaction, e.g. "195 remaining"), which made several
users think they had to categorize **all** of them.

## What changed

### Categorizer clarity (`step-categorize-transactions.tsx`)
- **New full-width progress banner** above the transaction card,
replacing the cramped corner counter that was getting truncated on
mobile:
- explicit instruction: *"To continue, you need to categorize at least 5
transactions."* (reuses the existing intro string)
  - a **5-segment progress bar** that fills as you go
  - the live **X/5** count
  - a reassurance line: *"You do not need to categorize all of them."*
- When the minimum is reached (or the list is exhausted), the banner
turns **green** — *"Done! You can continue now, or keep categorizing if
you want."* — and the **Continue** button gets a ring so it's obvious
the step is unlocked.
- **Removed the misleading "N remaining"** display.

### Onboarding layout & toasts
- **Mobile top spacing** (`onboarding-layout.tsx`): reduced the large
top padding on the step content on mobile so it sits closer to the
progress dots (unchanged on desktop).
- **Toasts during onboarding** (`app.tsx`): onboarding has no bottom
navigation bar, so toasts now render **bottom-center, flush to the
bottom** instead of being lifted 110px to clear the (absent) mobile tab
bar. Behavior elsewhere in the app is unchanged.

Two new strings added to `lang/es.json`.

## Notes

- The `canContinue` / `minimumRequired` gating logic is unchanged.
- Verified: `lint` clean, `es.json` valid, `LocalizationTest` passes,
full CI green.
- Recorded mobile + desktop walkthroughs locally.
2026-07-01 08:34:51 +02:00
.agents/skills feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
.claude feat(console): add agent:db command for querying local and prod DB (#522) 2026-06-12 18:35:14 +02:00
.cursor chore: add sentry mcp (#300) 2026-04-17 10:42:34 +02:00
.github ci: remove production deploy job (#574) 2026-06-20 18:17:14 +00:00
.opencode/skills chore: Update larevel boot package 2026-01-27 10:55:46 +01:00
.pi fix(automation): avoid rule preview n+1 (#431) 2026-05-26 08:02:46 +02:00
app fix(analysis): respect category types like the cashflow screen (#612) 2026-06-29 21:04:18 +02:00
bootstrap feat(users): track last login and last active timestamps (#516) 2026-06-10 11:01:30 +02:00
config feat(subscriptions): trial/pricing A/B/C experiment (#600) 2026-06-27 18:00:15 +02:00
database feat(ai): learn from category corrections so the AI stops repeating the same mistake (#608) 2026-06-29 19:12:15 +02:00
docker fix(queue): add supervisor worker for the ai queue (#546) 2026-06-17 07:08:25 +00:00
docs feat(banking): add Interactive Brokers sync via Flex Web Service (#581) 2026-06-23 11:39:24 +02:00
experiments feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
lang feat(onboarding): clarify the "categorize at least 5" goal in the categorizer (#616) 2026-07-01 08:34:51 +02:00
public fix(banking): keep the native green Wise logo, not the aggregator's (#590) 2026-06-24 09:34:37 +02:00
resources feat(onboarding): clarify the "categorize at least 5" goal in the categorizer (#616) 2026-07-01 08:34:51 +02:00
routes feat(dashboard): add accounts manager dialog with visibility toggle and reorder (#604) 2026-06-27 16:11:25 +00:00
screenshots fix: Add gap between filter/create button on mobile settings pages (#115) 2026-02-12 20:50:05 +01:00
scripts chore: release v0.2.5 (#539) 2026-06-15 16:48:25 +00:00
src/lib/crypto E2E Encryption 2025-11-07 14:21:25 +00:00
storage feat: Enable email verification on sign up (#97) 2026-02-03 10:15:07 +01:00
templates/coolify fix: split drip and default email senders (#263) 2026-04-06 12:16:47 +02:00
tests fix(analysis): respect category types like the cashflow screen (#612) 2026-06-29 21:04:18 +02:00
.dockerignore fix: publish and use production Docker image (#393) 2026-05-20 07:19:31 +00:00
.editorconfig Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
.env.example feat(ai): add weekly AI-suggestions cohort report (#530) 2026-06-13 23:23:34 +02:00
.env.production.example chore: track Sentry releases in CI (#294) 2026-04-16 08:04:59 +01:00
.gitattributes Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
.gitignore chore: ignore .playwright-mcp directory (#511) 2026-06-09 12:05:21 +02:00
.mcp.json chore: add sentry mcp (#300) 2026-04-17 10:42:34 +02:00
.php-cs-fixer.dist.php Execute browser tests on CI (#10) 2025-12-03 16:26:30 +01:00
.php-version chore: ignore local .php-version 2026-02-07 18:48:04 +01:00
.prettierignore Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
.prettierrc Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
.release-it.json chore: release v0.2.5 (#539) 2026-06-15 16:48:25 +00:00
AGENTS.md chore: update Laravel Boost skills and guidelines (#521) 2026-06-12 18:20:30 +02:00
CHANGELOG.md chore: release v0.2.5 (#539) 2026-06-15 16:48:25 +00:00
CLAUDE.md chore: update Laravel Boost skills and guidelines (#521) 2026-06-12 18:20:30 +02:00
Dockerfile chore: Simplify IndexedDB sync by moving to Inertia shared props (#63) 2026-01-19 19:15:26 +01:00
Dockerfile.production ci: cap Docker image build time (#405) 2026-05-20 09:45:12 +01:00
LICENSE.md Add Creative Commons license 2025-11-26 17:07:20 +01:00
LOCALIZATION.md feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
ONBOARDING.md fix(banking): handle balance-fetch timeouts and silence handled retries (#450) 2026-05-29 14:58:38 +02:00
README.md chore: update Discord invite link (#452) 2026-05-29 15:56:48 +02:00
artisan Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
autoresearch-dashboard.md feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
autoresearch.jsonl feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
autoresearch.md feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
autoresearch.sh feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
boost.json feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
bun.lock feat(accounts): reorder accounts with drag-and-drop (#575) 2026-06-21 11:17:45 +02:00
components.json Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
compose.yaml chore: replace Caddy with Portless for local HTTPS proxy (#258) 2026-04-02 16:39:44 +01:00
composer.json feat(ai): manage AI consent outside onboarding with live backfill (#591) 2026-06-25 10:50:35 +02:00
composer.lock feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
docker-compose.production.yml Add production Docker setup for easy self-hosting with the CI-built image (#42) 2025-12-30 07:22:19 +01:00
eslint.config.js Y3:0 2025-11-26 12:01:49 +01:00
falcode.json Add falcode config file 2026-03-11 15:28:52 +01:00
opencode.json chore: add sentry mcp (#300) 2026-04-17 10:42:34 +02:00
package-lock.json chore: release v0.2.5 (#539) 2026-06-15 16:48:25 +00:00
package.json feat(accounts): reorder accounts with drag-and-drop (#575) 2026-06-21 11:17:45 +02:00
phpstan-baseline.neon fix(static-analysis): clear phpstan-baseline by fixing all suppressed errors (#183) 2026-03-02 12:22:30 +00:00
phpstan.neon feat: selective retry of failed lead email jobs (#286) 2026-04-15 08:00:29 +01:00
phpunit.xml feat: use testcontainers for isolated MySQL in test runs (#153) 2026-02-25 10:14:20 +01:00
tsconfig.json Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
vite.config.ts Init browser Sentry from env DSN (#370) 2026-05-09 12:07:11 +02:00
vitest.config.ts Fix cashflow null category rows (#382) 2026-05-11 18:54:26 +02:00
vitest.setup.ts feat: add multiple chart view modes for net worth evolution (#37) 2025-12-30 07:22:19 +01:00
whispermoney fix: Wrong whispermoney script path 2026-01-16 18:48:44 +01:00
worktree.sh Notify users about expired bank connections (#404) 2026-05-20 09:20:13 +02:00

README.md

Whisper Money

Deutsch | Español | français | 日本語 | 한국어 | Português | Русский | 中文

Whisper Money

CC BY-NC 4.0

The most secure way to understand your finances.

Whisper Money is a privacy-first personal finance application that helps you track, categorize, and understand your spending—all while keeping your financial data encrypted and secure.

🎮 Try the Demo: Experience Whisper Money with our demo account - no registration required!

💬 Join our Community: Whether you're a user looking for help or a developer wanting to contribute, we'd love to have you in our Discord server! Share feedback, ask questions, discuss new features, or just hang out with fellow privacy enthusiasts.

Features

  • 🔐 Privacy-first — Your data is never shared with third parties. You own it
  • 🏦 Bank account management — Track multiple accounts in one place
  • 📊 Transaction categorization — Automatic and manual categorization
  • 🤖 Automation rules — Set up rules to auto-categorize transactions
  • 📈 Financial insights — Understand your spending patterns

Tech Stack

  • Backend: Laravel 12, PHP 8.4
  • Frontend: React 19, Inertia.js v2, TypeScript
  • Styling: Tailwind CSS v4
  • Database: MySQL
  • Cache/Queue: Redis
  • Testing: Pest v4

Running Locally

The easiest way to get started is using our automated setup script:

bash <(curl -fsSL https://whisper.money/setup.sh)

After installation, just visit https://whisper.money.localhost in your browser.

Manual Setup

If you prefer to set up manually:

  1. Clone the repository:
git clone https://github.com/whisper-money/whisper-money.git
cd whisper-money
  1. Run the setup script:
whispermoney install

Available Commands

Important: You must run whispermoney install before using any other command. If you skip the install step, commands like start will not work.

Once installed, you can use the whispermoney command for common tasks:

# Start all services
whispermoney start

# Stop all services
whispermoney stop

# Upgrade to latest version
whispermoney upgrade

# Interactive menu
whispermoney

Development Server

For active development with hot reloading:

composer run dev

This will concurrently start:

  • PHP development server (via Portless HTTPS proxy)
  • Queue worker
  • Log viewer (Pail)
  • Vite dev server

The application will be available at https://dev.whisper.money.localhost. In git worktrees, the branch name is automatically prepended (e.g. https://fix-ui.dev.whisper.money.localhost).

Running with Docker (Production Image)

For testing the production Docker image locally:

  1. Copy the production environment file:
cp .env.production.example .env
  1. Start the services:
docker compose -f docker-compose.production.yml up -d

The application will be available at http://localhost:8080.

To use a different port, set APP_PORT:

APP_PORT=3000 docker compose -f docker-compose.production.yml up -d

Deploying to Coolify

Whisper Money can be easily deployed to Coolify using our Docker Compose template.

Quick Deploy

  1. In Coolify, create a new resource and select Docker Compose
  2. Choose Empty Compose File as the source
  3. Paste the contents from our template: 👉 whisper-money.yaml
  4. Deploy!

The template includes:

  • Whisper Money application container
  • MySQL 8.0 database with health checks
  • Persistent volumes for data and storage
  • Auto-generated database credentials

Required Environment Variables

Variable Description
RESEND_API_KEY Email service API key (for password resets, notifications)

Note: APP_KEY and APP_URL are auto-configured. The container generates an APP_KEY on first startup if not provided.

Optional Environment Variables

Variable Default Description
DRIP_EMAILS_ENABLED true Enable drip emails (welcome, onboarding, feedback)
HIDE_AUTH_BUTTONS false Hide login/register buttons on landing page
SUBSCRIPTIONS_ENABLED false Enable Stripe subscriptions
STRIPE_KEY - Stripe publishable key
STRIPE_SECRET - Stripe secret key
STRIPE_WEBHOOK_SECRET - Stripe webhook signing secret

Star History

Star History Chart

License

This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.