* fix(enable-banking): reliable initial backfill, no more silent ~30-day windows (#443)
PSD2 first-sync was a compound bug: the cron runs once daily so users got no
data for up to 24h after activation; the "Sync now" button defaulted to 30
days and set last_synced_at, permanently locking the cron into 7-day
incremental mode and discarding the 90-day backfill window. ASPSPs also
truncate history below requested ranges, but the discrepancy was only logged.
This change:
- Runs the initial backfill inline when the user finishes account selection
(PATCH /accounts), so data is available the moment they finish onboarding.
- Tracks initial_sync_completed_at separately from last_synced_at; the cron
now gates first-sync 90-day window on that, so manual syncs no longer
clobber the backfill path.
- Surfaces the actual returned date range to the UI ("Initial historik: X → Y
(begärde Z)") with a warning when the bank truncated history.
- Defaults manual /sync to 90 days (was 30) — matches user intent.
- AccountPickerDialog uses SpeedLedger's SIE-anchor pattern when an SIE
import covers prior periods (auto-defaults lookback to "day after last SIE
entry"), with Bokio-style PSD2 disclosure on the standard path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(enable-banking): address review feedback on PR #486
Two fixes from review:
1. Memoise the browser Supabase client in AccountPickerDialog. createClient()
in the component body returned a new reference every render, and `supabase`
was in the SIE-fetch effect's dep array — every checkbox tick or parent
re-render re-fired the SIE-imports query.
2. Drop `accounts_data` from the second supabase update inside the activation
backfill. The first update already wrote it; including it here races with
any concurrent writer (e.g. cron firing in the sub-60s window) and would
silently overwrite. Only initial_sync_* metadata + last_synced_at need to
be persisted in the second update.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(enable-banking): check metadata-update error after inline backfill
The second supabase.update() inside the activation backfill block didn't
check its error return. Supabase client methods don't throw on DB errors;
they return { data, error }. If the metadata write failed (network blip,
RLS quirk, etc.), the handler still populated initialSyncSummary and
returned success — UI saw "imported N transactions" while the DB had
initial_sync_completed_at = NULL, causing the cron to schedule another
full 90-day backfill the next morning.
Capture { error } from the metadata update. On failure, surface as
initial_sync_error with a metadata_update_failed: prefix and skip the
initialSyncSummary population. The cron's gate (initial_sync_completed_at
IS NULL) still self-heals on the next run; this just keeps the UI honest
about which path got us there.
New test stub: SupabaseStub.updateErrorByCall lets a test succeed the
first update and fail the second.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>