Home
Softono
savvy

savvy

Open source MIT TypeScript
39
Stars
2
Forks
1
Issues
3
Watchers
1 week
Last Commit

About savvy

Savvy: Self-hosted finance tracker. One container, zero config, multiple currencies.

Platforms

Web Self-hosted Docker

Languages

TypeScript

Links

Savvy Savvy

Savvy

Selfhosted expense tracker with full multi-currency support. One container โ€” done.

Docker Version License

๐ŸŽฎ Try it now!

Demo

๐Ÿ” [email protected] / demo


Savvy Screenshot

โšก Quick Start

docker run -d -p 3000:80 -v savvy-data:/data truenormis/savvy:latest

Open localhost:3000 and create your account.

โœจ Features

  • Multi-currency โ€” any fiat or crypto, transfers between them
  • Auto exchange rates โ€” currency rates updated automatically via API
  • Recurring transactions โ€” scheduled payments (daily, weekly, monthly, yearly)
  • Automation rules โ€” auto-categorize transactions based on conditions
  • Debts โ€” track loans and borrowings with payment history
  • Budgets โ€” set limits and track progress
  • Categories & tags โ€” flexible organization
  • Multi-user โ€” share with family or team, role-based access (admin/user)
  • Rich analytics โ€” Sankey diagrams, heatmaps, net worth tracking, expense pace
  • CSV import โ€” import transactions from bank exports with duplicate detection
  • Backups โ€” create, restore and download database backups
  • 2FA โ€” two-factor authentication via TOTP (Google Authenticator, etc.)

Savvy Reports

๐Ÿ“ฑ Mobile-Friendly

Fully responsive design built with ShadCN/UI โ€” track expenses from your phone right after purchase.

Mobile Dashboard    

๐Ÿš€ Deployment

Docker Compose (Recommended)

services:
  savvy:
    image: truenormis/savvy:latest
    container_name: savvy
    restart: unless-stopped
    ports:
      - "3000:80"
    volumes:
      - savvy-data:/data
    environment:
      - APP_URL=https://savvy.yourdomain.com
      - TZ=Europe/Kyiv
    healthcheck:
      test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1/livez"]
      interval: 10s
      timeout: 3s
      start_period: 60s
      retries: 3

volumes:
  savvy-data:

Environment Variables

Variable Description Default
APP_URL Public URL of your instance http://localhost
TZ Timezone UTC

Behind a Reverse Proxy

Set APP_URL to your public https:// URL. Savvy honors the X-Forwarded-Proto and X-Forwarded-For headers from the proxy, so HTTPS link generation and real client IPs work automatically โ€” no extra configuration needed.

Health Checks

Two probe endpoints are exposed for orchestrators and uptime monitoring (responses use the IETF application/health+json format):

Endpoint Purpose Healthy Unhealthy
/livez Liveness โ€” the app process is up. Use it for container restart decisions. 200 โ€”
/readyz Readiness โ€” database is reachable and migrations are applied. Gate traffic. 200 503

/livez stays up during maintenance mode; /readyz returns 503 so traffic drains while the instance is not ready.

With Traefik (HTTPS)

services:
  savvy:
    image: truenormis/savvy:latest
    container_name: savvy
    restart: unless-stopped
    volumes:
      - savvy-data:/data
    environment:
      - APP_URL=https://savvy.yourdomain.com
      - TZ=Europe/Kyiv
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.savvy.rule=Host(`savvy.yourdomain.com`)"
      - "traefik.http.routers.savvy.entrypoints=websecure"
      - "traefik.http.routers.savvy.tls.certresolver=letsencrypt"
      - "traefik.http.services.savvy.loadbalancer.server.port=80"
    networks:
      - traefik

volumes:
  savvy-data:

networks:
  traefik:
    external: true

With Nginx Proxy Manager

  1. Run Savvy on internal port:
    
    services:
    savvy:
     image: truenormis/savvy:latest
     container_name: savvy
     restart: unless-stopped
     expose:
       - "80"
     volumes:
       - savvy-data:/data
     environment:
       - APP_URL=https://savvy.yourdomain.com
     networks:
       - npm-network

volumes: savvy-data:

networks: npm-network: external: true


2. In Nginx Proxy Manager, create proxy host pointing to `savvy:80`

### Kubernetes

Deploy as a single-replica `Deployment` with a `PersistentVolumeClaim` mounted at `/data`. SQLite is single-writer, so use `strategy: { type: Recreate }`. The container runs as non-root (`www-data`, uid 82) โ€” grant `NET_BIND_SERVICE` so it can bind port 80. Wire the probes to the health endpoints:

```yaml
        startupProbe:
          httpGet: { path: /livez, port: 80 }
          periodSeconds: 3
          failureThreshold: 30
        livenessProbe:
          httpGet: { path: /livez, port: 80 }
          periodSeconds: 10
        readinessProbe:
          httpGet: { path: /readyz, port: 80 }
          periodSeconds: 10

Helm chart coming soon.

๐Ÿ”„ Updating

docker compose pull
docker compose up -d

Your data is safe in the /data volume.

๐Ÿ’พ Backups

Backups can be managed directly from the UI (Settings โ†’ Backups).

[!WARNING] The database runs in WAL mode, so recent writes may still live in the database.sqlite-wal file and won't be in database.sqlite yet. Copying database.sqlite alone can silently lose the latest data. Always checkpoint the WAL into the main file first (or use the in-app backup, which handles this for you).

Manual backup:

# Fold the WAL into the main file, then copy
docker exec savvy php artisan tinker --execute="DB::statement('PRAGMA wal_checkpoint(TRUNCATE);');"
docker cp savvy:/data/database.sqlite ./backup-$(date +%Y%m%d).sqlite

Restore (stop writers first so the WAL doesn't fight the swap):

docker compose down
docker cp ./backup.sqlite savvy:/data/database.sqlite
docker compose up -d

๐Ÿ”’ Privacy

Your data stays with you. SQLite database stored in /data volume โ€” no external services required.

โš™๏ธ How It Works

One container runs everything under Supervisor โ€” Nginx, PHP-FPM, the scheduler (recurring transactions, automatic exchange-rate updates) and a queue worker for background jobs. SQLite lives in /data; no external database, cache, or queue service is required. Migrations run automatically on startup.

๐Ÿ›  Stack

Laravel โ€ข SQLite โ€ข Docker โ€ข ShadCN/UI โ€ข Tailwind CSS

๐Ÿค Contributing

Contributions are welcome! Please open an issue first to discuss what you would like to change.

๐Ÿ“„ License

MIT


Made with โค๏ธ for people who want control over their finances