Skip to content

fix(plans): 404 missing plan and reconcile stale scheduled-purchase Edit (#1403) - #1425

Merged
cristim merged 1 commit into
mainfrom
fix/1403-edit-scheduled-purchase-load
Jul 17, 2026
Merged

cristim merged 1 commit into
mainfrom
fix/1403-edit-scheduled-purchase-load

Conversation

@cristim

@cristim cristim commented Jul 16, 2026

Copy link
Copy Markdown
Member

What

Editing a scheduled (planned) purchase whose backing plan no longer exists showed a generic Failed to load plan details toast and left the orphaned row on screen (closes #1403).

Root cause

The PR #780 fix (the Edit button passes plan_id, not the execution's own id) is intact and verified — getPlan is called with the correct plan FK. The residual cause of the identical error is a scheduled-purchase row that outlived its plan:

  • the plan was deleted (migration 000033 makes purchase_executions.plan_id ON DELETE SET NULL, detaching the execution), or
  • the caller's account scope changed so the plan is no longer accessible.

Clicking Edit then loads GET /plans/{id}, which failed in two places:

  1. Backend — getPlan returned GetPurchasePlan's wrapped config.ErrNotFound raw. The router's IsNotFoundError only matches the api-package *notFoundError sentinel, so a missing plan surfaced as a 500 instead of a 404 (unlike sibling handlers updatePlan / patchPlan / getPlanForPurchaseCreation, which route through mapCreatePlanStorageError). This change routes getPlan through the same helper.

  2. Frontend — editPlan swallowed the failure with a generic toast and never reconciled the list, leaving a dead Edit button. It now returns a success boolean, shows an actionable message on a 404 (This plan is no longer available. It may have been deleted.), and the scheduled-purchase Edit handler refetches the planned-purchases list so the orphaned row is dropped. Other errors (network blip, transient 5xx) keep the generic message since the plan may still exist.

Tests (fail before, pass after — verified by stashing each fix)

  • internal/api: TestHandler_getPlan_NotFound_MapsTo404 — a missing plan maps to a 404 ClientError, not a raw 500.
  • frontend: edit action reconciles the list when the plan is gone (#1403) — asserts the correct plan_id is still used, the actionable 404 message fires, and getPlannedPurchases is refetched to drop the stale row.

Gates

  • go build ./... / go vet ./...: pass
  • go test ./internal/api/...: pass (1724)
  • gocyclo -over 10: clean on changed code
  • golangci-lint run ./... (pinned CI v2.10.1): 0 issues
  • npm test: 2568 passed; npm run build: pass; npm run lint: 0 errors

…dit (#1403)

Editing a scheduled purchase whose plan no longer exists surfaced a generic
"Failed to load plan details" and left the orphaned row on screen.

The PR #780 fix (Edit passes plan_id, not the execution id) is intact and
verified; the residual cause of the identical error is a scheduled-purchase
row that outlived its plan: the plan was deleted (ON DELETE SET NULL detaches
the execution) or the caller's account scope changed. Clicking Edit then loads
GET /plans/{id}, which failed in two ways:

- Backend: getPlan returned GetPurchasePlan's wrapped config.ErrNotFound raw.
  The router's IsNotFoundError only matches the api-package sentinel, so a
  missing plan surfaced as 500 instead of 404 (unlike updatePlan / patchPlan).
  Route it through mapCreatePlanStorageError so it maps to 404.

- Frontend: editPlan swallowed the failure with a generic toast and never
  reconciled the list. It now returns a success boolean, shows an actionable
  message on a 404, and the scheduled-purchase Edit handler refetches the
  planned-purchases list so the orphaned row is dropped.

Regression tests at both layers fail on the pre-fix code and pass after.
@cristim cristim added triaged Item has been triaged priority/p2 Backlog-worthy severity/medium Moderate harm urgency/this-sprint Within the current sprint impact/many Affects most users effort/s Hours type/bug Defect labels Jul 16, 2026
@cristim

cristim commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@cristim
cristim merged commit 9a8a9c7 into main Jul 17, 2026
19 of 20 checks passed
@cristim
cristim deleted the fix/1403-edit-scheduled-purchase-load branch July 17, 2026 05:37
@cristim

cristim commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

Merged to main (all CI green after the tflint-503 outage cleared) closes #1403. Edit scheduled purchase - getPlan now returns 404 (not 500) for a missing plan and the frontend reconciles the stale list; adversarial-reviewed SHIP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/s Hours impact/many Affects most users priority/p2 Backlog-worthy severity/medium Moderate harm triaged Item has been triaged type/bug Defect urgency/this-sprint Within the current sprint

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(plans): Edit scheduled purchase fails with 'Failed to load plan details' (regression after #773/PR #780)

1 participant