whisper-money/resources/js/components
Víctor Falcón d3ec96b845
fix(onboarding): stop the AI rule-suggestion step from hanging forever (#705)
## Problem

A user reported being stuck forever on the onboarding "Looking for
patterns" step (the "Polishing your suggestions…" spinner). Confirmed in
prod: their `suggestion_runs` row has been stuck in `processing` for a
week, and `failed_jobs` shows `TimeoutExceededException:
GenerateRuleSuggestionsJob has timed out`.

### Root cause

- The user has 4,163 transactions — the largest onboarding dataset (max
with a completed run was 3,481). The Gemini generation exceeded the
job's `$timeout = 120`.
- The worker timeout is raised **outside** the `try/catch` in
`GenerateRuleSuggestions::run()`, so the code that sets `status =
Failed` never ran.
- `GenerateRuleSuggestionsJob` had **no `failed()` handler** (5 other
jobs do), so nothing flipped the run to `Failed`. It stayed
`processing`, `show()` kept returning `processing`, and the client
polled every 3s forever.
- The timeout never reached Sentry, so it was invisible. Only 1 user
affected, but it's a latent bug that recurs on any large account.

## Fix

**Backend** — add `failed()` to `GenerateRuleSuggestionsJob`: mark the
run `Failed` (only if not already terminal) and `report()` the exception
so these surface in Sentry.

**Frontend** (`step-ai-suggestions.tsx`) — belt-and-suspenders so the
client never spins forever even if the worker dies before it can mark
the run:
- `poll()` now guards against transient errors (network blip / expired
session / 5xx) instead of silently dying.
- A client-side deadline (3 min, just beyond the "up to two minutes"
copy) surfaces the existing "couldn't generate" screen with **Try again
/ Skip**.

Not included: raising the timeout / capping the number of groups sent to
Gemini so large accounts *complete* instead of just being able to skip.
Follow-up if we want big accounts to get suggestions.

## Tests

- `tests/Feature/Ai/GenerateRuleSuggestionsJobTest.php` — `failed()`
marks the run `Failed` + reports; doesn't overwrite an already-terminal
run.
-
`resources/js/components/onboarding/step-ai-suggestions-timeout.test.tsx`
— after the deadline the spinner gives way to the failed screen.

Green locally: pint, prettier, eslint, backend + frontend tests.
2026-07-20 18:10:51 +00:00
..
accounts feat(import): persist per-account import configuration on the backend (#698) 2026-07-18 16:10:40 +02:00
automation-rules
…
budgets
…
cashflow
…
categories
…
charts
…
dashboard
…
icons
…
integration-requests
…
labels
…
landing
…
onboarding fix(onboarding): stop the AI rule-suggestion step from hanging forever (#705) 2026-07-20 18:10:51 +00:00
open-banking
…
partials
…
shared
…
subscription
…
transactions feat(import): persist per-account import configuration on the backend (#698) 2026-07-18 16:10:40 +02:00
ui
…
alert-error.tsx
…
app-content.tsx
…
app-logo-icon.tsx
…
app-logo.tsx
…
app-shell.tsx
…
app-sidebar-header.tsx
…
app-sidebar.tsx
…
appearance-tabs.tsx
…
bank-logo.tsx
…
breadcrumbs.tsx
…
delete-user.tsx
…
encryption-key-button.tsx
…
heading-small.tsx
…
heading.tsx
…
icon.tsx
…
input-error.tsx
…
mobile-back-button.tsx
…
nav-footer.tsx
…
nav-main.tsx
…
nav-user.tsx
…
pro-badge.tsx
…
sortable-grid.test.tsx
…
sortable-grid.tsx
…
support-dialog.tsx
…
text-link.tsx
…
two-factor-recovery-codes.tsx
…
two-factor-setup-modal.tsx
…
unlock-message-dialog.tsx
…
user-info.tsx
…
user-menu-content.test.tsx
…
user-menu-content.tsx
…