Skip to content

ops(plans): clean up existing universal plans (DB rows with no plan_accounts entry) #742

Description

@cristim

Context

PR "fix(plans): eliminate universal plans" closes the API hole that allowed
creating "universal plans" — rows in purchase_plans with no matching row in
plan_accounts. After that PR lands, the API rejects empty target_accounts
on POST /api/plans and the modal Save button stays disabled until the user
picks at least one account.

That PR does NOT touch existing universal plans already in the DB. Those rows
predate the enforcement and need operator-driven cleanup. This issue tracks
the cleanup decision + execution.

Diagnostic

Run the read-only diagnostic to enumerate every universal plan currently in
the DB (count + IDs + names + creation dates + services):

psql "$DB_URL" -f scripts/list_universal_plans.sql

The script's header documents the three cleanup options inline so you can
decide per plan without leaving psql.

Three cleanup options

(a) Delete

Use when the plan is genuinely orphaned — no consumer, no executions, never
used. Safest when the row predates any intentional use.

DELETE FROM purchase_plans WHERE id = '<uuid>';

(b) Fan out

Attach every enabled cloud_account whose provider matches the plan's
services map. Mimics the historical "blank == all provider accounts"
intent; concrete, explicit, and recoverable.

INSERT INTO plan_accounts (plan_id, account_id)
SELECT pp.id, ca.id
FROM purchase_plans pp
CROSS JOIN LATERAL jsonb_each(pp.services) AS svc(k, v)
JOIN cloud_accounts ca ON ca.provider = v->>'provider'
WHERE pp.id = '<uuid>'
ON CONFLICT DO NOTHING;

(c) Manual review

Pull the plan up in the UI, talk to the owner if known, and assign the right
account(s) via the (now-required-Target-Account) New/Edit Plan modal.
Recommended for plans with clear intent the SQL can't infer.

Recommendation

Default to (c) manual review per plan, unless the row is obviously orphaned
(zero executions, owner unreachable) — in which case (a) DELETE is fine. (b)
fan-out is safe but loud (creates a lot of plan_accounts rows in one go);
use it only after confirming the original intent.

Related

  • PR (eliminate-universal-plans): fixes the source so no new universal plans
    can be created.
  • PR fix(plans): include universal plans in Account filter (refs #705) #739 (still open): added a UNION branch to buildListPlansQuery so
    universal plans appeared in the account-filtered list. After eliminate-
    universal-plans merges + this cleanup completes, that branch is dead code.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    effort/mDaysimpact/fewLimited audiencepr-createdA PR has been opened for this issue (dedup guard for the auto-PR loop)pr-mergedThe PR for this issue has been mergedpriority/p2Backlog-worthyseverity/lowMinor harmtriagedItem has been triagedtype/choreMaintenance / non-user-visibleurgency/this-sprintWithin the current sprint

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions