feat(migrate): provision a covered order onto the running plan - #409
Conversation
W54 covers: when the GitHub account already runs a plan at least the sized one, provision ties the grant to that plan's workspace (the personal one first) and answers redeemed with no checkout. The Studio fee is $0, the quote must equal the Migrate fee, and Polar is not called. A repeat keeps the workspace the grant is tied to. too_small still answers 409 migrate.bundle_state_unsupported until the upgrade flow exists. Needs @contentrain/types 1.47.0 (provision answer without a checkout).
…emed Provision answers are a union now: a checkout answer is never redeemed, so a grant paid in the same moment is refused with 409 migrate.grant_used.
|
t6 review @ 2e55fe1 — ONAY for what was asked; one money question (non-blocking) for t8/ORK Evidence at this head: studio CI Checked, as asked:
Question, not a blocker here: |
Only an active plan that is not scheduled to end covers a Migrate order. Ending, past_due and canceled plans fall to none and pay the normal bundle, as attach already does. The bundle workspace now skips any workspace that still holds a subscription, so a second one is never opened on a plan that is ending; when every owned workspace holds one, provision refuses with billing.subscription_exists.
Provision answers 409 with data.code subscription_exists when every owned workspace already holds a subscription, so Migrate can show the customer the way out without matching localised text.
…esume The 409 subscription_exists answer carries workspace_slug, the personal workspace first, so Migrate can link to that workspace billing page. Only a workspace the caller owns, and only in the S2S answer.
|
ONAY — f439741 (delta d5acb56..f439741, t6 review) Checked at f439741:
Local: unit 2035 passed, integration 487 passed, nuxt 274 passed, eslint and nuxt typecheck clean. |
What (W54 covers)
When the GitHub account already runs a Studio plan at least the sized one,
POST /api/migrate/provisionties the grant to that plan's workspace (the personal one first) and answersstate: 'redeemed'with the workspace and no checkout.migrate.quote_changed); Polar is not called, no checkout saved (tests pin both).too_smallstill answers 409migrate.bundle_state_unsupported(the real upgrade is a separate PR after refund/revoke and the staging E2E).@contentrain/types1.47.0 (union response). A checkout answer is neverredeemed: a grant paid in the same moment is refused with 409migrate.grant_used.coveringWorkspace()inmigrate-account-state.ts.Tests
Provision (covers: bound + redeemed + no Polar, quote, idempotent, re-quote/refusals; same-moment paid),
coveringWorkspace. Unit + integration, eslint, typecheck green; main CI green before push.