fix(cloud-backup): mark dead Google tokens needs-reauth and surface reconnect in the UI (#970)

Nightly cloud-backup syncs kept retrying Google connections whose
refresh token is permanently dead (Google returns 400 invalid_grant;
3 of 12 prod connections are in this state), and the settings card
showed the raw English error string while presenting the account as
connected.

- refreshAccessToken now throws a typed GoogleTokenRefreshError
  carrying status + body, with an isInvalidGrant discriminator.
- performSync catches the invalid_grant case, persists
  status: 'needs_reauth' (+ needs_reauth_at) on the connection JSON in
  extension_data (no migration needed), and returns a needs_reauth
  failure instead of throwing. Transient failures (5xx, network, other
  400s) still throw and stay retried.
- The nightly cron loads connections for due companies and skips
  needs_reauth ones (reported as skipped in the summary) instead of
  retrying the dead token every night. A successful refresh clears a
  stale flag; reconnecting via OAuth writes a fresh connection.
- CloudBackupCard shows a reconnect callout (Swedish-first, sv+en
  strings) wired to the existing connect action, and replaces the raw
  error string on the schedule row with a short reconnect notice.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-07-10 11:04:11 +02:00
committed by GitHub
co-authored by Claude Fable 5
parent b06d73c23e
commit 2be104ba34
11 changed files with 562 additions and 15 deletions
+4
View File
@@ -3743,6 +3743,10 @@
"ext_cloud_backup_name": "Cloud sync",
"ext_cloud_backup_description": "Sync backups to your own cloud storage",
"ext_cloud_backup_long_description": "Connect your Google Drive account and upload a full backup with one click. Accounted creates a ZIP with SIE files, receipts and processing history and uploads it to a dedicated folder in your Drive.",
"ext_cloud_backup_reauth_title": "Google Drive needs to be reconnected",
"ext_cloud_backup_reauth_description": "Access to your Google account has expired or been revoked. Automatic sync is paused until you reconnect the account.",
"ext_cloud_backup_reauth_action": "Reconnect Google Drive",
"ext_cloud_backup_reauth_needed_short": "reconnect required",
"ext_skatteverket_name": "Skatteverket integration",
"ext_skatteverket_description": "Submit the VAT declaration directly to Skatteverket via BankID.",
"ext_skatteverket_long_description": "Connect to Skatteverket with BankID and submit your VAT declaration directly from accounted. Save drafts, validate, lock and sign: without leaving the app.",
+4
View File
@@ -3743,6 +3743,10 @@
"ext_cloud_backup_name": "Molnsynkronisering",
"ext_cloud_backup_description": "Synka säkerhetsbackup till din egen molnlagring",
"ext_cloud_backup_long_description": "Koppla ditt Google Drive-konto och ladda upp en fullständig säkerhetsbackup med ett klick. Accounted skapar en ZIP med SIE-filer, kvitton och behandlingshistorik och laddar upp till en egen mapp i din Drive.",
"ext_cloud_backup_reauth_title": "Google Drive behöver kopplas om",
"ext_cloud_backup_reauth_description": "Åtkomsten till ditt Google-konto har gått ut eller återkallats. Automatisk synkronisering är pausad tills du kopplar om kontot.",
"ext_cloud_backup_reauth_action": "Koppla om Google Drive",
"ext_cloud_backup_reauth_needed_short": "kräver omkoppling",
"ext_skatteverket_name": "Skatteverket Integration",
"ext_skatteverket_description": "Skicka momsdeklaration direkt till Skatteverket via BankID.",
"ext_skatteverket_long_description": "Anslut till Skatteverket med BankID och skicka din momsdeklaration direkt från accounted. Spara utkast, validera, lås och signera: utan att lämna appen.",