Phase 5: SimpleFIN Provider Sync #47

Closed
opened 2026-05-16 18:17:46 -05:00 by null · 0 comments
Owner

Goal

Add optional SimpleFIN Bridge support as the first bank sync provider. SimpleFIN feeds accounts and transactions into the shared data source and transactions system from Phase 2.

Depends on: Phase 2 (#44 — data_sources, financial_accounts, transactions), Phase 4 (#46 — matching for synced transactions)
Blocks: Phase 6
Parent: #42
See also: #41 (original SimpleFIN issue — this supersedes it for implementation)


Scope

Implement

  • SimpleFIN provider service (simplefinSource.js)
  • Setup token claim flow
  • Encrypted access URL storage
  • Manual sync endpoint
  • Account and transaction sync with dedupe
  • Frontend connect/sync/disconnect UI (Settings → Data Sources)

Do NOT implement

  • Plaid, GoCardless, direct bank login
  • Automatic bill payment
  • Background scheduled sync (Phase 6)

Environment Variables

BANK_SYNC_ENABLED=false
TOKEN_ENCRYPTION_KEY=replace-with-long-random-secret
SIMPLEFIN_SYNC_DAYS=90

Rules:

  • BANK_SYNC_ENABLED defaults to false
  • If enabled, TOKEN_ENCRYPTION_KEY is required
  • Missing token key prevents sync startup
  • Manual mode works when sync is disabled

Security

  • Never store bank usernames/passwords
  • Never log setup tokens or access URLs
  • Never return access URLs to frontend
  • Encrypt access URL at rest
  • Decrypt only inside backend sync service
  • Redact provider errors before sending to frontend

Backend API

POST   /api/data-sources/simplefin/connect
POST   /api/data-sources/simplefin/sync
DELETE /api/data-sources/simplefin/disconnect

Connect request:

{ "setupToken": "simplefin setup token or setup URL" }

Service Shape

class SimpleFinSource {
  async connect(input) {}
  async sync(dataSource) {}
  async disconnect(dataSource) {}
  normalizeAccount(rawAccount) {}
  normalizeTransaction(rawTransaction) {}
}

Sync Behavior

  • Load SimpleFIN data source
  • Decrypt access URL
  • Fetch accounts and transactions
  • Upsert financial_accounts
  • Upsert transactions (dedupe by provider_transaction_id)
  • Update last_sync_at
  • Store last_error if sync fails

Frontend

Settings → Data Sources → SimpleFIN section:

  • Enabled/disabled status
  • Setup token input
  • Connect / Sync Now / Disconnect buttons
  • Last sync time and error display
  • Connected accounts list

Acceptance Criteria

  • SimpleFIN optional, disabled by default
  • User can connect via setup token
  • Access URL encrypted at rest
  • Access URL never sent to frontend
  • Manual sync works
  • Accounts and transactions saved locally
  • Synced transactions appear in transaction list
  • User can match synced transactions using Phase 4 matching
  • User can disconnect SimpleFIN
  • App works normally without SimpleFIN

Previous → Phase 4 (#46)
Next → Phase 6 (#48)

## Goal Add optional SimpleFIN Bridge support as the first bank sync provider. SimpleFIN feeds accounts and transactions into the shared data source and transactions system from Phase 2. **Depends on:** Phase 2 (#44 — data_sources, financial_accounts, transactions), Phase 4 (#46 — matching for synced transactions) **Blocks:** Phase 6 **Parent:** #42 **See also:** #41 (original SimpleFIN issue — this supersedes it for implementation) --- ## Scope ### Implement - SimpleFIN provider service (`simplefinSource.js`) - Setup token claim flow - Encrypted access URL storage - Manual sync endpoint - Account and transaction sync with dedupe - Frontend connect/sync/disconnect UI (Settings → Data Sources) ### Do NOT implement - Plaid, GoCardless, direct bank login - Automatic bill payment - Background scheduled sync (Phase 6) --- ## Environment Variables ```env BANK_SYNC_ENABLED=false TOKEN_ENCRYPTION_KEY=replace-with-long-random-secret SIMPLEFIN_SYNC_DAYS=90 ``` Rules: - `BANK_SYNC_ENABLED` defaults to false - If enabled, `TOKEN_ENCRYPTION_KEY` is required - Missing token key prevents sync startup - Manual mode works when sync is disabled --- ## Security - Never store bank usernames/passwords - Never log setup tokens or access URLs - Never return access URLs to frontend - Encrypt access URL at rest - Decrypt only inside backend sync service - Redact provider errors before sending to frontend --- ## Backend API ``` POST /api/data-sources/simplefin/connect POST /api/data-sources/simplefin/sync DELETE /api/data-sources/simplefin/disconnect ``` Connect request: ```json { "setupToken": "simplefin setup token or setup URL" } ``` --- ## Service Shape ```js class SimpleFinSource { async connect(input) {} async sync(dataSource) {} async disconnect(dataSource) {} normalizeAccount(rawAccount) {} normalizeTransaction(rawTransaction) {} } ``` ## Sync Behavior - Load SimpleFIN data source - Decrypt access URL - Fetch accounts and transactions - Upsert financial_accounts - Upsert transactions (dedupe by provider_transaction_id) - Update last_sync_at - Store last_error if sync fails --- ## Frontend Settings → Data Sources → SimpleFIN section: - Enabled/disabled status - Setup token input - Connect / Sync Now / Disconnect buttons - Last sync time and error display - Connected accounts list --- ## Acceptance Criteria - [ ] SimpleFIN optional, disabled by default - [ ] User can connect via setup token - [ ] Access URL encrypted at rest - [ ] Access URL never sent to frontend - [ ] Manual sync works - [ ] Accounts and transactions saved locally - [ ] Synced transactions appear in transaction list - [ ] User can match synced transactions using Phase 4 matching - [ ] User can disconnect SimpleFIN - [ ] App works normally without SimpleFIN --- **Previous → Phase 4 (#46)** **Next → Phase 6 (#48)**
null added the
backend
feature
frontend
priority:medium
labels 2026-05-16 18:18:02 -05:00
null closed this issue 2026-06-03 22:21:05 -05:00
Sign in to join this conversation.
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: null/BillTracker#47
No description provided.