whisper-money/app/Services/Banking
Víctor Falcón 220b1e11f1
refactor(banking): scalable per-provider sync via a syncer factory (#545)
## Why

Syncing was a growing `if/elseif` chain in
`SyncBankingConnectionJob::handle()` plus one private method per
provider. Every new provider meant editing the job, and the file mixed
provider-specific logic with cross-cutting orchestration. This does not
scale to dozens/hundreds of providers.

## What

Introduces a **factory + strategy** pattern:

- **`App\Contracts\BankingConnectionSyncer`** — interface: `sync()`,
`expires()`, `notifiesOnAuthFailure()`.
- **`AbstractBankingConnectionSyncer`** — defaults for the common case
(API-key provider: never expires, notifies on auth failure). A new
provider usually only implements `sync()`.
- **`BankingConnectionSyncerFactory`** — maps `connection.provider` to
its syncer (resolved from the container, so dependencies are injected).
- **Six syncers** — `IndexaCapitalSyncer`, `BinanceSyncer`,
`WiseSyncer`, `BitpandaSyncer`, `CoinbaseSyncer`, `EnableBankingSyncer`.
Each fully owns its provider behavior, including EnableBanking's daily
email and first-sync cutoff.

`SyncBankingConnectionJob` drops from ~520 to ~190 lines and now only
orchestrates: deleted-user/expiry/rate-limit checks, error handling,
retries, logging, and status updates. It asks the syncer `expires()` /
`notifiesOnAuthFailure()` instead of hardcoding provider lists.

### Adding a provider now

1. Create `XSyncer extends AbstractBankingConnectionSyncer` implementing
`sync()`.
2. Add one line to the factory map.

No changes to the job.

## Tests

- Existing job tests (`SyncBankingConnectionJobTest`,
`SyncRetryAndLoggingTest`) migrated through a shared `runSync()` helper
in `tests/Pest.php`; all original assertions preserved.
- New `BankingConnectionSyncerFactoryTest`: provider→syncer resolution,
unknown-provider exception, and the capability flags.
- Full suite green: **1604 passed**, 0 failures. PHPStan clean, Pint
applied.

## Docs

Adds `docs/adding-a-banking-provider.md` — a step-by-step developer
guide (usable by a human or an AI agent) covering the sync provider and
the broader end-to-end integration touchpoints.
2026-06-16 16:25:29 +02:00
..
Formatters feat: Add per-bank description formatter for bank-synced transactions (#120) 2026-02-13 09:54:58 +01:00
Sync refactor(banking): scalable per-provider sync via a syncer factory (#545) 2026-06-16 16:25:29 +02:00
BalanceSyncService.php Batch historical balance writes (#356) 2026-05-05 15:26:28 +01:00
BinanceBalanceSyncService.php feat: store invested_amount in user currency instead of account currency (#262) 2026-04-06 12:48:13 +02:00
BinanceClient.php fix(static-analysis): clear phpstan-baseline by fixing all suppressed errors (#183) 2026-03-02 12:22:30 +00:00
BitpandaBalanceSyncService.php feat: store invested_amount in user currency instead of account currency (#262) 2026-04-06 12:48:13 +02:00
BitpandaClient.php fix(static-analysis): clear phpstan-baseline by fixing all suppressed errors (#183) 2026-03-02 12:22:30 +00:00
CoinbaseBalanceSyncService.php Backfill Coinbase monthly history (#395) 2026-05-14 10:52:46 +01:00
CoinbaseClient.php Backfill Coinbase monthly history (#395) 2026-05-14 10:52:46 +01:00
EnableBankingProvider.php feat(open-banking): finalize bank connection without a session via state token (#498) 2026-06-06 12:12:07 +02:00
IndexaCapitalBalanceSyncService.php feat: store invested_amount in user currency instead of account currency (#262) 2026-04-06 12:48:13 +02:00
IndexaCapitalClient.php fix(banking): treat Indexa Capital performance 404 as empty data (#386) 2026-05-13 09:34:28 +01:00
TransactionCounterpartyExtractor.php feat(transactions): add counterparty fields (#440) 2026-05-27 16:20:55 +02:00
TransactionDescriptionFormatter.php feat: Add per-bank description formatter for bank-synced transactions (#120) 2026-02-13 09:54:58 +01:00
TransactionFingerprint.php fix(banking): dedup EnableBanking transactions by deterministic fingerprint (#390) 2026-05-13 11:30:11 +01:00
TransactionSyncService.php feat(transactions): add counterparty fields (#440) 2026-05-27 16:20:55 +02:00
WiseBalanceSyncService.php feat: add Wise open banking integration with balance sync (#525) 2026-06-16 13:23:25 +00:00
WiseClient.php feat: add Wise open banking integration with balance sync (#525) 2026-06-16 13:23:25 +00:00
WiseTransactionSyncService.php feat: add Wise open banking integration with balance sync (#525) 2026-06-16 13:23:25 +00:00