Budget management assistant for Firefly III. Automatically manages budget limits, links PayPal transactions, and sends notifications via Discord or Gotify.
- Budget overspend detection — Alerts when spending exceeds a budget limit
- Dynamic bills budget — Automatically updates the bills budget limit (sum of paid bills + max of unpaid bills)
- Dynamic leftovers budget — Automatically updates the leftovers budget limit (income − all other budgets)
- PayPal linking — Links PayPal transactions to Firefly III transactions across 2 Firefly III accounts
- Auto-import — Schedules or manually triggers transaction imports via the Firefly III Data Importer
- Budget sum-up — Schedules or manually triggers a monthly budgets summary report
- Webhook integration — Real-time triggers from Firefly III on transaction and budget events
- Manual Transaction categorisation — Notifies when new uncategorised withdrawals appear, with interactive buttons to assign a category
- Manual Transaction budget assignment — Notifies when new unbudgeted withdrawals appear, with interactive buttons to assign a budget
- Manual Import trigger — Trigger a Firefly III Data Importer job on demand
- Manual Budget Sum-up trigger — Trigger a budget summary job on demand
- Hidden items — Hide unwanted budgets or categories from notification listings (persisted in Redis)
- Budget roles — Designate which budget acts as the Bills and Leftovers budget (persisted in Redis)
Sparkleft is split into three services communicating via a Redis-backed job queue (BullMQ):
┌──────────────────────────────────┐
│ Express Server (port 3000) │
│ HTTP API · Web UI · Job creator │
└──────────────┬───────────────────┘
│ enqueue jobs
▼
┌───────────────┐
│ Redis │
│ (BullMQ) │
└───────┬───────┘
│ dequeue & process
▼
┌───────────────┐
│ Worker │
│ Job processor │
└───────────────┘
│
▼
┌───────────────┐
│ Firefly III API│
└───────────────┘
- Server — Handles HTTP endpoints, serves the web UI, and enqueues jobs into Redis.
- Worker — Processes jobs from the queue (budget calculations, notifications, imports, etc.).
- Redis — Message broker between server and worker.
| Layer | Technology |
|---|---|
| Runtime | Node.js 26, TypeScript |
| HTTP | Express 5 |
| Job queue | BullMQ + ioredis |
| Firefly III client | @billos/firefly-iii-sdk |
| Templates | Pug (UI), Nunjucks (notifications) |
| Logging | Pino |
| Testing | Vitest + v8 coverage |
| CI/CD | Semantic Release, Docker Hub |
| Package manager | Yarn 4 |
- A running Firefly III instance with API access
- Docker & Docker Compose or Node.js ≥ 26 with Yarn 4
- A Redis instance (provided by Docker Compose or external)
- The target budgets (bills, leftovers) must already exist in Firefly III with an initial limit set
Copy .env.default to .env and fill in the values:
# ─── Firefly III ─────────────────────────────────────────
FIREFLY_III_URL= # Firefly III base URL including /api (e.g. https://firefly.example.com/api)
FIREFLY_III_TOKEN= # Personal Access Token for the main account
FIREFLY_III_PAYPAL_ACCOUNT_TOKEN= # Token for the PayPal-linked account (optional)
FIREFLY_III_WEBHOOK_SECRET= # Webhook signature secret configured in Firefly III
FIREFLY_III_CLI_TOKEN= # CLI token used for triggering Firefly III cron jobs
# ─── API security ────────────────────────────────────────
API_TOKEN= # Token to protect Sparkleft endpoints
USE_API_TOKEN= # Set to 'false' to disable token protection (default: true)
# ─── Auto-import ─────────────────────────────────────────
IMPORTER_URL= # URL of the Firefly III Data Importer
IMPORT_DIRECTORY= # Path to the import configuration directory
AUTO_IMPORT_SECRET= # Secret for the auto-import endpoint
# ─── Redis ───────────────────────────────────────────────
REDIS_URL= # Redis connection URL (e.g. redis://redis:6379)
# ─── Other ───────────────────────────────────────────────
SERVICE_URL= # Public URL of this Sparkleft instance (used in notification links)
TZ= # Timezone (e.g. Europe/Paris)Production:
docker compose up -dThis starts three services:
| Service | Role | Port |
|---|---|---|
redis |
Message queue broker | — |
server |
HTTP API & web UI | 3000 |
worker |
Background job processor | — |
Development (with hot-reload):
docker compose -f docker-compose.dev.yml upSource files are mounted as volumes — changes are picked up automatically.
# Install dependencies
yarn install
# Build
yarn build
# Start the server
yarn start:server
# Start the worker (in a separate terminal)
yarn start:workerA Redis instance must be reachable at the URL specified in REDIS_URL.
All endpoints are protected by the API_TOKEN when USE_API_TOKEN is enabled (default).
| Method | Endpoint | Description |
|---|---|---|
GET |
/control |
Dashboard to trigger jobs and toggle hidden items |
GET |
/api/config |
Get current configuration (budgets, hidden items, etc.) |
GET |
/api/transaction/:id/newCategory?name=X |
Create and assign a new category |
GET |
/transaction/:id/category/:categoryId |
Assign a category to a transaction |
GET |
/transaction/:id/budget/:budgetId |
Assign a budget to a transaction |
POST |
/api/cron/:type |
Setting the Cron value of the associated type |
POST |
/api/auto-import |
Trigger an auto-import job |
POST |
/api/budget-sumup |
Trigger a budget sum-up job |
POST |
/api/hide-toggle/category/:name |
Toggle visibility of a category |
POST |
/api/hide-toggle/budget/:name |
Toggle visibility of a budget |
POST |
/api/budget-role/:role/:budgetId |
Set/clear the Bills or Leftovers budget (role = bills | leftovers) |
POST |
/webhook |
Firefly III webhook receiver (HMAC SHA3-256 verified) |
Configure a webhook in Firefly III pointing to https://<SERVICE_URL>/webhook with the secret matching FIREFLY_III_WEBHOOK_SECRET.
Supported triggers:
- Transaction create / update / delete
- Budget create / update / delete
- Budget limit store / update
When a webhook is received, Sparkleft enqueues the relevant jobs (uncategorised check, unbudgeted check, budget limit update, message cleanup, etc.).
yarn dev:server # Server with hot-reload + pretty logs
yarn dev:worker # Worker with hot-reload + pretty logs
yarn build # Compile TypeScript → build/
yarn lint # oxlint
yarn format # Prettier (write)
yarn format-check # Prettier (check)
yarn type-check # TypeScript type checking
yarn test # Run tests
yarn test:coverage # Run tests with coverage report
yarn docker:build # Build the Docker image locally
yarn types:api:generate # Regenerate Firefly III API types
yarn release # Semantic release
yarn clean # Remove build/ and node_modules/src/
├── server.ts # Express server entry point
├── worker.ts # BullMQ worker entry point
├── config.ts # Environment variable configuration
├── client.ts # Firefly III SDK clients
├── redis.ts # Redis connection
├── endpoints/ # HTTP route handlers
├── queues/
│ ├── jobs/ # Job implementations (11 job types)
│ ├── queue.ts # Queue initialisation
│ ├── index.ts # Worker initialisation
│ ├── queueArgs.ts # Job argument types
│ └── utils.ts # Queue utilities
├── modules/notifiers/ # Notification adapters (Discord, Gotify)
├── utils/ # Shared utilities
└── __tests__/ # Test files
templates/ # Pug (UI) & Nunjucks (notifications) templates
public/ # Static assets (CSS, favicon)
Tests are run with Vitest:
yarn test # Run all tests
yarn test:coverage # Generate coverage report (text + HTML)Coverage reports are published to GitHub Pages.
| Workflow | Trigger | Purpose |
|---|---|---|
ci.yml |
Pull requests & non-main branches | Lint, format check, build, test |
codeql.yml |
Push & schedule | CodeQL security analysis |
coverage-pages.yml |
Push to main | Deploy coverage report to GitHub Pages |
release.yml |
Push to main | Semantic release, Docker image build & push to Docker Hub |
This project is licensed under the GPL-3.0 license.