Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Yaffa Laravel Package

kantorge/yaffa

YAFFA is a self-hosted personal finance manager built with Laravel. Track accounts, transactions, budgets, and investments; import bank statements; categorize spending; and generate reports through a clean, responsive web interface with multi-currency support.

View on GitHub
Deep Wiki
Context7

Getting Started

Yaffa is a self-hosted Laravel personal-finance application (accounts, transactions, schedules, budgets, reports, AI document import) that you deploy and extend rather than composer require. v4.1.0 keeps the Laravel 13 + PHP ext-bcmath floor from 4.0, so confirm both before anything else — a missing bcmath extension fails late and confusingly, usually the first time a money value is cast.

Two viable entry paths:

  • Docker (fastest): docker compose up -d. The container generates and persists its own APP_KEY on first boot, so no .env editing is required. Add --profile https if you want the bundled Caddy reverse proxy.
  • From source: clone, composer install, copy .env.example, php artisan key:generate, set the DB connection, then php artisan migrate --seed.

Where to look first, in order:

  1. UPGRADE.md (section 3.x to 4.x) — the 4.0 data migrations are one-way; read this before you touch a production database. If you are coming from 4.0, also review the 4.1 migration that moves the preferred import profile from account_entities to accounts.
  2. routes/api.php and the app/Http/Controllers/Api/V1 namespace — this is the surface most integrations use.
  3. app/Models/{Transaction,Budget,Schedule,Account} — the 4.0 domain model changed materially, and 4.1 moves import-profile state onto Account.
  4. config/ plus .env.example — several values must be pinned explicitly under Laravel 13; if you use AI document import, check the configured OpenAI model is still supported.
  5. resources/js and the new payee/category show views if you extend the UI — Select2 has been replaced by Tom Select.

A good first use case is a read-only API client: create a token in User settings → API tokens with the read scope, then pull /api/v1/transactions and confirm your JSON parser handles money as decimal strings. That single step exercises the auth model, the API contract and the precision change at once.

If you are coming from 3.x: upgrade to the newest 3.x first, take a database backup, then run php artisan app:check:budget-migration and act on its output before installing 4.x. If you are already on 4.0, back up before 4.1 as well if you have custom import code touching account_entities.

Implementation Patterns

Treat recurrence as an RFC 5545 string, not columns. Schedules and budgets now store recurrence in a single rrule column; frequency, interval, count and end_date are gone. The UI and API fields are unchanged, so write through the model's accessors/casts rather than reassembling the old columns:

$schedule->rrule = 'FREQ=MONTHLY;BYDAY=1WE';        // first Wednesday of every month
$schedule->rrule = 'FREQ=MONTHLY;BYDAY=-1FR';       // last Friday of the month

New 4.0 patterns — "N days before month end", "last business day of month", "skip to nearest future occurrence" — are all expressible this way, so a custom importer or seeder can generate them without touching the UI.

Query Budget directly instead of the old flag. transactions.budget no longer exists. Budget-only transactions were migrated into Budget rows (one per category) and deleted. Any custom report, dashboard widget or SQL view you own must join budgets rather than filter where('budget', true). Budget management now lives under Reports → Schedules and Budgets.

Money is exact — keep it exact in your own code. The core uses decimal arithmetic throughout. On the API boundary, money and quantity fields in /api/v1/* responses are decimal strings. Parse with bcmath or a money value object, never (float):

$total = '0.00';
foreach ($payload['transactions'] as $tx) {
    $total = bcadd($total, $tx['amount'], 2);   // amount is "12.34", not 12.34
}

Report endpoints are exempt from the string change — they were already strings — so a single normalization helper at your client boundary keeps both shapes honest.

Update import automation for the new profile location. The preferred import profile now lives on accounts, not account_entities. Custom importers, seeders or direct DB queries should read/write through the Account model or relation; do not keep querying the old location.

Handle AI import outcomes explicitly. 4.1 adds AI document duplicate detection and a warning when an import returns no drafts. Background jobs and importers should treat an empty draft set as a valid outcome and inspect duplicate status rather than assuming every upload produces a new transaction.

Scope API tokens by intent. Tokens carry read, write and settings scopes. Issue one token per integration: a dashboard/BI job needs only read; an importer needs write; only an admin sync tool should hold settings. Pair with per-user TOTP and recovery codes for interactive logins — both are managed from user settings and are the replacement story for the removed reCAPTCHA on the human-facing flows.

Wire into the reporting layer rather than duplicating it. Find Transactions gained transaction-type and investment filters, a category waterfall, and item-level breakdown filtering; the dashboard waterfall widget deep-links into the report. 4.1 adds payee and category show pages, so check those before building custom drill-down views. If you need a bespoke view, compose existing report endpoints/controllers and filter server-side — reimplementing aggregation client-side will drift from the inflation-adjusted forecasting and split-total logic.

Use Tom Select for UI extensions. Select2 is gone in 4.1. If you maintained custom JS, styling, or browser tests around Select2 events/DOM, migrate them to Tom Select rather than shimming the old API.

Sentry is opt-in again. 4.1 removes the sentry/sentry-laravel dependency. If you need error reporting, require and configure it explicitly; otherwise remove stale Sentry references from custom code and config.

Deployment hygiene. Pin CACHE_PREFIX, REDIS_PREFIX and SESSION_COOKIE in .env before moving to Laravel 13; the framework changed the defaults, and un-pinned values silently orphan your cache namespace and log every user out. For HTTPS, start Caddy with docker compose --profile https up -d and set APP_PORT if 443 is taken. Re-apply any hand edits you previously made to a commented-out Caddy block — that block is now a live profile service.

Testing and style. PHPUnit 13 for unit/integration coverage, Pest 5 browser tests for UI flows, ESLint-clean, 2-space JS/Vue formatting. If you maintain a fork or a private module, match the formatting and update Select2-based browser tests to Tom Select to keep diffs reviewable.

Gotchas and Tips

  • The 4.0 migrations are irreversible. migrate:rollback will not restore transactions.budget or the dropped schedule columns. Back up, run app:check:budget-migration on the latest 3.x, and only then upgrade. 4.1's move of the preferred import profile from account_entities to accounts is another schema change — review it before upgrading from 4.0.
  • Decimal strings break naive clients. Anything doing Number(tx.amount) or json_decode(...)->amount + 1 in PHP will now produce string concatenation or NaN. Audit every consumer, including Blade/Vue formatters, exports and webhook payloads.
  • Over-precise input is rejected, not rounded. If you post 12.345 to a 2-decimal field you get a validation error where 3.x silently truncated. Validate and quantize on your side; the API will not do it for you.
  • GET /api/v1/transactions/scheduled-items dropped its type parameter. Remove type=budget|budget_only|both|any from clients — it is no longer accepted, and budget-vs-actual responses now carry budgetBreakdown and scheduleBreakdown arrays.
  • Deleting an AI document no longer deletes its transaction. That is deliberate and useful (audit trail), but it means cleanup scripts must handle orphaned transactions explicitly. A migration repairs invalid file paths on documents created from pasted text, so re-check any stored paths after upgrading.
  • AI duplicate detection changes cleanup assumptions. 4.1 can flag duplicate documents and warn on imports with no drafts. Automation that expects one successful import per upload must branch on duplicate/no-draft states instead of retrying blindly.
  • reCAPTCHA is gone. RECAPTCHA_* variables are read nowhere; delete them from .env to avoid false confidence. Confirm login/registration throttling is configured, since that is now your only automated abuse control.
  • bcmath in custom images. The official image has it; slim or distroless derivatives often do not. Add docker-php-ext-install bcmath or the app fails on the first monetary operation.
  • Sentry removal can break custom error handling. If your app code or config references sentry/sentry-laravel, 4.1 will not install it. Either re-add the package and wire it deliberately or remove the references.
  • Retired OpenAI models are deprecated. If AI import is configured for gpt-4o or gpt-4o-mini, switch to a currently supported model; otherwise document import may fail at the provider boundary.
  • Tom Select replaces Select2. Custom JS relying on Select2 events, CSS classes, or DOM structure will silently stop working. Update browser tests and any fork-specific UI code.
  • Preferred import profile moved. Any custom query or exporter reading the profile from account_entities must point at accounts after 4.1.
  • Index and pivot changes. Redundant indexes were removed and pivot tables gained primary/unique keys, with duplicate pivot rows cleaned during migration. Any raw SQL or query builder call relying on a dropped index may need re-tuning — check EXPLAIN on your heaviest custom reports.
  • Formatter caching. Number and date formatters are cached for large tables. If you override them (locale, currency symbol, precision display), make sure your customization invalidates or bypasses the cache, or you will ship stale formatting.
  • Notification/toast text is escaped as plain text (XSS fix). Passing HTML into flash messages or toasts no longer renders — pre-format your strings instead of expecting markup.
  • Rebase UI overrides against 4.1 fixes. AI-document layout and monthly breakdown report layout changed, and shared Vue components were refactored. Re-check any view or component overrides rather than assuming the old markup still applies.
  • Extension points worth knowing: model casts/accessors for rrule, policies for the new Budget entity, report controllers for custom widgets, the new payee/category show controllers/views, Tom Select configuration for UI extensions, and the per-user AI document retention policy for housekeeping jobs. Prefer these over patching migrations — with irreversible data migrations in play, a clean upgrade path is worth more than a convenient hack.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource