Skip to content

Fix stale PostgREST schema cache breaking subscriptions + snapshot sync#75

Merged
TheAngryRaven merged 2 commits into
BETAfrom
claude/snapshot-sync-billing-fixes
May 28, 2026
Merged

Fix stale PostgREST schema cache breaking subscriptions + snapshot sync#75
TheAngryRaven merged 2 commits into
BETAfrom
claude/snapshot-sync-billing-fixes

Conversation

@TheAngryRaven
Copy link
Copy Markdown
Owner

Summary

Three beta function-test failures — checkout returning a non-2xx, lap snapshots not syncing on sign-in, and the Profile snapshot panel showing Could not find the function public.snapshot_usage ... in the schema cache — all traced to a single root cause: a stale PostgREST schema cache.

The 20260526+ migration batch (subscription_tiers, user_subscriptions, lap_snapshots, account_deletions + their RPCs) was applied to Postgres, but PostgREST kept serving a cached schema that predated it. Because the REST API backs both the client (.rpc()/.from()) and the edge functions' service-role .from() calls, every object in that batch was invisible over REST while existing in the database:

  • create-checkout-sessionfrom('subscription_tiers') cache-miss → null row → 400 Unknown tier (non-2xx)
  • listCloudSnapshotsfrom('lap_snapshots') cache-miss → reconcileSnapshots throws (swallowed to console)
  • snapshot_usage() RPC → cache-miss → the exact "schema cache" error in the panel

stripe-prices kept working precisely because it's pure Stripe API and never touches PostgREST — which is the tell.

Changes

  • 20260530000000_reload_postgrest_schema.sql — issues notify pgrst, 'reload schema'. Runs last in sequence, so a fresh DB reloads after the whole batch is created, and deploying it to an already-migrated DB reloads the existing-but-uncached objects. This is the actual fix.
  • autoSync.ts — document and snapshot reconcile now run in independent try/catch blocks, so a failure in one (missing table, quota rejection) no longer silently skips the other.
  • LapSnapshotsPanel.tsx — the usage meter is now best-effort: if it can't load, the snapshot list stays usable instead of the whole panel blanking to a raw error.
  • CHANGELOG.md — entries under [Unreleased] → Fixed.

Operational note

Editing migrations only affects future applies. To unblock the currently-deployed beta DB immediately (without waiting for this migration to deploy), run once in the SQL editor:

notify pgrst, 'reload schema';

Test plan

  • npm run lint clean
  • npm run typecheck clean
  • npm run test:run — 737 passed
  • After deploy: checkout completes, snapshots sync on sign-in, and the Profile snapshot meter loads
  • Confirm select to_regclass('public.lap_snapshots') is non-null and snapshot_usage() is callable over REST

https://claude.ai/code/session_017wyJik7iHRfxTKeuKFc4Xs


Generated by Claude Code

The 20260526+ migration batch (subscription_tiers, user_subscriptions,
lap_snapshots, account_deletions + RPCs) was applied to Postgres but
PostgREST kept serving a stale schema cache. Since the REST API backs both
the client and the edge functions' service-role queries, those objects were
invisible over REST — breaking checkout (non-2xx), lap-snapshot sync, and the
snapshot usage meter, while Stripe price loading (no PostgREST) still worked.

Add a migration that issues `notify pgrst, 'reload schema'` so the cache
reloads on deploy (and last in sequence on a fresh DB). Also harden two
failure modes the incident exposed: document and snapshot auto-sync now
reconcile independently, and the Profile snapshot panel no longer blanks when
its best-effort usage meter can't load.

https://claude.ai/code/session_017wyJik7iHRfxTKeuKFc4Xs
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 28, 2026

Coverage Summary

Lines: 35.53% (2397/6745) · Statements: 34.58% · Functions: 28.94% · Branches: 36.16%

Per-file coverage
File Lines Functions Branches
src/components/video-overlays/dataSourceResolver.ts 84.12% 70% 79.41%
src/components/video-overlays/overlayUtils.ts 100% 100% 100%
src/components/video-overlays/registry.ts 100% 100% 100%
src/components/video-overlays/sectorUtils.ts 94.73% 100% 84.37%
src/components/video-overlays/themes.ts 100% 100% 100%
src/components/video-overlays/types.ts 0% 100% 100%
src/hooks/use-mobile.tsx 0% 0% 100%
src/hooks/use-toast.ts 0% 0% 0%
src/hooks/useAuth.ts 100% 100% 100%
src/hooks/useDataLoader.ts 0% 0% 0%
src/hooks/useDocumentHead.ts 0% 0% 0%
src/hooks/useEngineManager.ts 0% 0% 0%
src/hooks/useFileManager.ts 0% 0% 0%
src/hooks/useKartManager.ts 100% 100% 100%
src/hooks/useLapManagement.ts 0% 0% 0%
src/hooks/useLapSnapshots.ts 0% 0% 0%
src/hooks/useNoteManager.ts 0% 0% 0%
src/hooks/useOnlineStatus.ts 0% 0% 0%
src/hooks/usePlayback.ts 0% 0% 0%
src/hooks/useReferenceLap.ts 0% 0% 0%
src/hooks/useSessionData.ts 0% 0% 0%
src/hooks/useSessionMetadata.ts 0% 0% 0%
src/hooks/useSettings.ts 0% 0% 0%
src/hooks/useSetupManager.ts 0% 0% 100%
src/hooks/useStripePrices.ts 0% 0% 0%
src/hooks/useSubscription.ts 0% 0% 0%
src/hooks/useTemplateManager.ts 0% 0% 0%
src/hooks/useTrackEditorForm.ts 0% 0% 0%
src/hooks/useVehicleManager.ts 0% 0% 100%
src/hooks/useVideoSync.ts 0% 0% 0%
src/integrations/lovable/index.ts 0% 0% 0%
src/lib/aimParser.ts 87.96% 100% 69.13%
src/lib/alfanoParser.ts 80.46% 100% 57.48%
src/lib/billing.ts 94.73% 100% 96.29%
src/lib/billingClient.ts 0% 0% 0%
src/lib/ble/test/mockBle.ts 100% 100% 50%
src/lib/ble/battery.ts 93.33% 100% 87.5%
src/lib/ble/connection.ts 0% 0% 0%
src/lib/ble/fileTransfer.ts 90.69% 95% 72.91%
src/lib/ble/format.ts 50% 100% 72.22%
src/lib/ble/index.ts 100% 100% 100%
src/lib/ble/internal.ts 100% 100% 50%
src/lib/ble/settings.ts 93.6% 100% 85.29%
src/lib/ble/trackSync.ts 89.69% 90.9% 70.96%
src/lib/ble/types.ts 100% 100% 100%
src/lib/bleDatalogger.ts 100% 100% 100%
src/lib/brakingZones.ts 97.14% 100% 86.11%
src/lib/browserCompat.ts 0% 0% 0%
src/lib/channels.ts 100% 100% 84.61%
src/lib/chartColors.ts 100% 100% 100%
src/lib/chartUtils.ts 0% 0% 0%
src/lib/courseDetection.ts 99.01% 100% 84.14%
src/lib/datalogParser.ts 18.51% 50% 17.39%
src/lib/db/index.ts 0% 0% 0%
src/lib/db/supabaseAdapter.ts 0% 0% 0%
src/lib/db/types.ts 100% 100% 100%
src/lib/dbUtils.ts 3.12% 0% 0%
src/lib/deviceSettingsSchema.ts 93.33% 100% 96.42%
src/lib/deviceTrackSync.ts 100% 100% 90%
src/lib/doveParser.ts 89.6% 72.72% 73.63%
src/lib/dovexParser.ts 76.56% 76.92% 47.27%
src/lib/emailValidation.ts 100% 100% 100%
src/lib/engineStorage.ts 0% 0% 100%
src/lib/engineUtils.ts 100% 100% 91.66%
src/lib/fieldResolver.ts 100% 100% 83.33%
src/lib/fileStorage.ts 0% 0% 0%
src/lib/garageEvents.ts 100% 100% 100%
src/lib/gforceCalculation.ts 100% 100% 100%
src/lib/graphPrefsStorage.ts 0% 0% 0%
src/lib/kartStorage.ts 0% 0% 0%
src/lib/lapCalculation.ts 96.12% 100% 90.32%
src/lib/lapDelta.ts 98.96% 100% 82.35%
src/lib/lapSnapshot.ts 100% 100% 87.5%
src/lib/lapSnapshotStorage.ts 0% 0% 0%
src/lib/motecParser.ts 4.29% 3.44% 0.69%
src/lib/nmeaParser.ts 85.62% 92.85% 71.22%
src/lib/noteStorage.ts 0% 0% 100%
src/lib/overlayCanvasRenderer.ts 0% 0% 0%
src/lib/parserUtils.ts 100% 100% 98.52%
src/lib/pendingCheckout.ts 58.82% 25% 100%
src/lib/referenceUtils.ts 100% 100% 89.28%
src/lib/setupStorage.ts 0% 0% 0%
src/lib/speedBounds.ts 94.11% 66.66% 89.18%
src/lib/speedEvents.ts 86.56% 100% 76%
src/lib/templateStorage.ts 0% 0% 0%
src/lib/trackStorage.ts 3.33% 0% 0%
src/lib/trackUtils.ts 100% 100% 100%
src/lib/ubxParser.ts 5% 0% 0%
src/lib/utils.ts 100% 100% 100%
src/lib/vboParser.ts 83.2% 100% 60.97%
src/lib/vehicleStorage.ts 0% 0% 0%
src/lib/videoExport.ts 0% 0% 0%
src/lib/videoFileStorage.ts 0% 0% 0%
src/lib/videoStorage.ts 0% 0% 0%
src/lib/weatherService.ts 0% 0% 0%
src/plugins/cloud-sync/accountDeletion.ts 0% 0% 0%
src/plugins/cloud-sync/accountExport.ts 0% 0% 0%
src/plugins/cloud-sync/autoSync.ts 0% 0% 0%
src/plugins/cloud-sync/cloudClient.ts 0% 0% 0%
src/plugins/cloud-sync/CloudFilesSection.tsx 0% 0% 0%
src/plugins/cloud-sync/CloudLogsPanel.tsx 0% 0% 0%
src/plugins/cloud-sync/CloudSyncPanel.tsx 0% 0% 0%
src/plugins/cloud-sync/DataPrivacyPanel.tsx 0% 0% 0%
src/plugins/cloud-sync/DownloadAllCloudLogs.tsx 0% 0% 0%
src/plugins/cloud-sync/exportManifest.ts 100% 100% 100%
src/plugins/cloud-sync/FileDeleteToggle.tsx 0% 0% 0%
src/plugins/cloud-sync/fileSync.ts 68.42% 38.46% 100%
src/plugins/cloud-sync/FileSyncToggle.tsx 0% 0% 0%
src/plugins/cloud-sync/index.ts 0% 0% 0%
src/plugins/cloud-sync/LapSnapshotsPanel.tsx 0% 0% 0%
src/plugins/cloud-sync/merge.ts 90.9% 66.66% 100%
src/plugins/cloud-sync/pendingSync.ts 0% 0% 0%
src/plugins/cloud-sync/profile.ts 0% 0% 0%
src/plugins/cloud-sync/snapshotSync.ts 0% 0% 0%
src/plugins/cloud-sync/snapshotTombstones.ts 0% 0% 0%
src/plugins/cloud-sync/StoragePanel.tsx 0% 0% 0%
src/plugins/cloud-sync/storageTypes.ts 100% 100% 100%
src/plugins/cloud-sync/storeAccessors.ts 0% 0% 0%
src/plugins/cloud-sync/syncEngine.ts 0% 0% 0%
src/plugins/cloud-sync/syncStores.ts 100% 100% 100%
src/plugins/index.ts 0% 0% 0%
src/plugins/mounts.ts 100% 100% 100%
src/plugins/panels.ts 100% 100% 100%
src/plugins/PluginMount.tsx 0% 0% 0%
src/plugins/PluginPanelHost.tsx 0% 0% 0%
src/plugins/registry.ts 100% 100% 100%
src/plugins/storage.ts 32.25% 8.33% 33.33%
src/plugins/types.ts 100% 100% 100%
src/types/racing.ts 100% 100% 100%

The auto-upload of local snapshots is wired through autoSync's reconcile on
app boot / sign-in, but a reconcile that fails (e.g. the schema-cache outage)
is swallowed and never retried in the same session, leaving local snapshots
stuck off the cloud. Have the Lap snapshots panel re-run reconcileSnapshots
when it opens and refresh live on snapshot-store changes, so viewing the panel
uploads any local-only snapshots without an app reload.

https://claude.ai/code/session_017wyJik7iHRfxTKeuKFc4Xs
@TheAngryRaven TheAngryRaven merged commit f61bd3e into BETA May 28, 2026
5 checks passed
@TheAngryRaven TheAngryRaven deleted the claude/snapshot-sync-billing-fixes branch May 28, 2026 02:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants