whisper-money/app
Víctor Falcón 4c83cb8b33
feat(import): persist per-account import configuration on the backend (#698)
## What & why

Import configuration (the CSV/Excel column mapping and date format a
user
sets up per account) was stored in the browser's `localStorage`, so it
never
followed the user to another device. Importing the same account's
statement on
mobile — or on a new machine — meant reconfiguring the mapping from
scratch.

This moves that configuration to the backend, keyed per account and per
import
type, so it's preconfigured and loaded automatically wherever the user
imports.

## Demo

Cross-device QA: import transactions on "device 1" with a custom column
mapping, then clear **all** cookies + local/session storage (simulating
a
fresh device), log back in, and start a new import — the mapping
(Description → *Movement*, Amount → *How Much*, date format
*DD-MM-YYYY*)
is auto-loaded from the backend with no manual setup.


https://github.com/user-attachments/assets/e449dfe9-3970-48d4-97ca-9e415c73835b



## How

- New `account_import_configs` table: one row per `(account_id, type)`
where
`type` is `transaction` or `balance`. The mapping + date format are
stored as
  an opaque `config` JSON blob (exactly what the client sends).
- `GET/PUT /api/accounts/{account}/import-config`
(`AccountImportConfigController`),
authorized via the existing `AccountPolicy` (`view`/`update`) — mirrors
  `AccountBalanceController`. `PUT` upserts on `(account_id, type)`.
- Frontend: the two import-config storage helpers now read/write the
endpoint
via `axios` instead of `localStorage` (merged into a single module — the
  transaction and balance variants shared the same logic).
- The saved config is fetched **off the file-parse critical path**: the
parsed
file shows immediately with auto-detected columns, and the saved mapping
is
applied when it arrives (guarded so a slow load can't clobber a file
picked
afterwards). A slow or hanging request never blocks the preview or Next
  button. When no config exists or the request fails, it falls back to
  auto-detection exactly as before.

## Notes / decisions

- **No localStorage migration.** Existing per-device configs aren't
migrated;
on the next import the mapping is auto-detected and re-saved to the
backend,
so it self-heals after one import. The old `import_config_account_*`
keys are
  simply no longer read.
- The mapping-validity check against the actual file headers stays
client-side
  (it depends on the just-parsed file).

## Testing

- `tests/Feature/AccountImportConfigTest.php` (9 tests): auth required,
  cross-user 403 on read and write, save→persist→load round-trip, upsert
  de-duplication, transaction/balance independence, and validation
  (unknown type, missing column mapping).
- Sibling suites green (`AccountBalanceControllerTest`,
`SavedFilterTest`) —
no regression from the new `Account::importConfigs()` relation or
routes.
2026-07-18 16:10:40 +02:00
..
Actions feat(spaces): phase 0 — multi-tenant Space foundation (no behaviour change) (#650) 2026-07-09 14:26:07 +02:00
Ai/Agents feat(ai): auto-categorize transactions with AI (behind flag) (#535) 2026-06-15 16:35:20 +02:00
Console/Commands feat(encryption): report count of users still holding encrypted data (#687) 2026-07-17 09:29:33 +00:00
Contracts feat(connections): manage which accounts a bank connection syncs (#558) 2026-06-18 16:22:49 +02:00
Enums feat(import): persist per-account import configuration on the backend (#698) 2026-07-18 16:10:40 +02:00
Events Add Budgeting Feature to Track and Manage Spending (#36) 2026-01-21 15:25:50 +01:00
Exceptions/Banking fix(banking): recover from EnableBanking 422 wrong-period instead of crashing the sync (PHP-LARAVEL-42) (#653) 2026-07-07 08:57:23 +02:00
Features feat(mcp): read-only MCP server for Pro accounts (#689) 2026-07-17 16:54:15 +02:00
Http feat(import): persist per-account import configuration on the backend (#698) 2026-07-18 16:10:40 +02:00
Jobs fix(queue): raise retry_after above the longest job timeout (PHP-LARAVEL-2D) (#645) 2026-07-05 09:31:23 +00:00
Listeners feat: reuse the upgrade modal at more upsell points and attribute revenue (#699) 2026-07-18 12:53:20 +00:00
Mail refactor(drip): extract base mailable and job for the drip email family (#641) 2026-07-04 20:51:38 +02:00
Mcp feat(mcp): add OAuth 2.1 for Claude Desktop & ChatGPT connectors (Phase 3) (#691) 2026-07-17 19:10:48 +02:00
Models feat(import): persist per-account import configuration on the backend (#698) 2026-07-18 16:10:40 +02:00
Notifications fix: verify email via signed link without requiring login (#490) 2026-06-05 10:01:32 +02:00
Policies refactor(policies): extract HandlesUserOwnership trait (#478) 2026-06-03 17:43:30 +02:00
Providers feat(mcp): add OAuth 2.1 for Claude Desktop & ChatGPT connectors (Phase 3) (#691) 2026-07-17 19:10:48 +02:00
Rules feat: parent/child category tree (#474) 2026-06-03 19:30:12 +02:00
Services fix(balances): propagate retroactive transaction changes to later balances (#682) 2026-07-16 08:38:02 +02:00
Support refactor: extract duplicated money formatter into App\Support\Money (#680) 2026-07-15 09:47:53 +02:00