whisper-money/app/Services
Víctor Falcón e71a743a0a
feat: Coinbase banking integration (#388)
## Summary

Adds **Coinbase** as a banking/investment provider, alongside existing
Binance, Bitpanda, and Indexa Capital integrations. Connection auth uses
Coinbase Developer Platform (CDP) JWT (ES256) API keys.

Sync model mirrors Bitpanda: no historical balance reconstruction
(Coinbase API has no daily snapshot endpoint). Balance tracking starts
from connection date.

## Account model

One single **Crypto Portfolio** Whisper Account in the user's fiat
currency, aggregating all Coinbase wallets (crypto + fiat).

## Backend

- `app/Services/Banking/CoinbaseClient.php` — JWT-signed Coinbase
Advanced Trade client (`firebase/php-jwt` ES256). Per-request JWT, 120s
TTL, `uri` claim `"METHOD host/path"`. Methods:
`getAccounts`/`getAllAccounts` (cursor pagination), `getProduct`,
`getBestBidAsk` (batched), with 429 retry/backoff.
- `app/Services/Banking/CoinbaseBalanceSyncService.php` — Partitions
wallets into fiat vs crypto. Batched `best_bid_ask` for prices, USD
stablecoin shortcut (USDT/USDC/DAI/PYUSD/GUSD),
`CurrencyConversionService` fallback. Aggregates everything into user
fiat.
- `app/Http/Controllers/OpenBanking/CoinbaseController.php` +
`ConnectCoinbaseRequest.php` — mirror Bitpanda flow, validates
`api_key_name` (`organizations/{org}/apiKeys/{id}`) + PEM `private_key`.
Stores key_name in `api_token`, PEM in `api_secret` (already encrypted
TEXT).
- `BankingConnection::isCoinbase()`,
`SyncBankingConnectionJob::syncCoinbase()`, credential-update flow.
- `routes/web.php`: `POST /open-banking/coinbase/connect`.
- Bank seeder entry + factory `coinbase()` state.

## Frontend

- `connect-account-dialog.tsx` / `connect-account-inline.tsx`: Coinbase
appears in the bank picker. Confirm step shows `<Input>` for API key
name and `<Textarea>` (multi-line) for the PEM private key, with link to
CDP portal.
- `update-credentials-dialog.tsx`: Coinbase credentials editable.
- `settings/connections.tsx`: coinbase included in `isApiKeyProvider`.
- Wayfinder auto-generated `CoinbaseController.ts` +
`routes/open-banking/coinbase`.

## Tests

- `tests/Feature/OpenBanking/CoinbaseControllerTest.php` — happy path,
invalid creds (401 → 422), validation errors, subscription gate.
- `tests/Feature/OpenBanking/CoinbaseBalanceSyncTest.php` — mixed
crypto+fiat aggregation, USD stablecoin valuation, skip when
external_account_id missing.

All **217 OpenBanking tests pass**. Pint + ESLint clean.

## Follow-ups (not in this PR)

- Upload `storage/banks/logos/coinbase.png` to production storage (URL
referenced in seeder + frontend).
- Invested-amount calc from transaction history (deferred).
- Historical balance reconstruction (deferred — Coinbase has no daily
snapshot endpoint).
2026-05-13 19:53:30 +02:00
..
Banking feat: Coinbase banking integration (#388) 2026-05-13 19:53:30 +02:00
Demo Remove encryption from browser tests and demo user (#129) 2026-02-17 11:45:27 +01:00
AccountMetricsService.php Preload exchange rates (#362) 2026-05-06 16:35:49 +01:00
AuthEntryPointService.php fix: route new PWA guests to signup (#313) 2026-04-21 10:53:05 +01:00
AutomationRuleService.php feat(rules): move automation rule evaluation to the backend (#168) 2026-03-01 10:37:12 +01:00
BalanceLookup.php fix(static-analysis): clear phpstan-baseline by fixing all suppressed errors (#183) 2026-03-02 12:22:30 +00:00
BudgetPeriodService.php Add yearly budget period (#384) 2026-05-12 13:35:25 +02:00
BudgetTransactionService.php fix(budgets): retry assignment deadlocks (#304) 2026-04-19 11:21:27 +01:00
CurrencyConversionService.php Fix missing historical currency rates (#344) 2026-05-04 11:26:45 +01:00
CurrencyOptions.php feat(settings): centralize currency options and split profile/account support (#256) 2026-04-02 19:23:10 +02:00
ExchangeRateService.php Fix PHP-LARAVEL-1V exchange rate cache race (#383) 2026-05-12 12:45:45 +02:00
LandingAuthOverrideService.php feat(leads): cohort-based launch invitations with per-user Stripe coupons (#333) 2026-04-30 15:10:28 +01:00
LeadCohortResolver.php feat(leads): cohort-based launch invitations with per-user Stripe coupons (#333) 2026-04-30 15:10:28 +01:00
LeadPromoCodeAllocator.php feat(leads): cohort-based launch invitations with per-user Stripe coupons (#333) 2026-04-30 15:10:28 +01:00
LoanAmortizationService.php fix(dashboard): avoid month overflow in real estate projection (#340) 2026-04-30 13:53:01 +00:00
LoanBalanceGeneratorService.php feat(loans): backfill historical balances on loan creation (#322) 2026-04-24 13:09:34 +01:00
PeriodComparator.php Refactor: Optimize category management in CreateDefaultCategories and ResetUserCategories 2025-12-01 15:37:53 +01:00
RealEstateBalanceGeneratorService.php feat(real-estate): auto-calculate revaluation % and generate historical balances (#253) 2026-04-15 12:18:33 +00:00
ResendService.php feat: sync user leads to resend (#283) 2026-04-13 19:56:08 +01:00