Skip to content

fix(audit-sprint-6a): make the Scale tier sellable - #171

Closed
ejay-dev wants to merge 1 commit into
fix/audit-sprint-4b-plan-catalogfrom
fix/audit-sprint-6a-scale-provisioning-v2
Closed

fix(audit-sprint-6a): make the Scale tier sellable#171
ejay-dev wants to merge 1 commit into
fix/audit-sprint-4b-plan-catalogfrom
fix/audit-sprint-6a-scale-provisioning-v2

Conversation

@ejay-dev

Copy link
Copy Markdown
Owner

Summary

Audit deep-dive found Scale was advertised in marketing at $1,800/mo but unsellable end-to-end. This PR makes the path actually work; the Stripe price ID itself is operator-set (runbook below).

Base branch: fix/audit-sprint-4b-plan-catalog (PR #166). Merge that first.

What was broken

Surface State Fix
org_subscriptions_plan_key_check constraint Allowed only basic|pro|enterprise Migration adds scale
app/onboarding/page.tsx:54-58 PLAN_CHOICES Excluded Scale Adds PLAN_CATALOG.scale between pro and enterprise
.env.example STRIPE_PRICE_SCALE Commented-out "optional comma-separated" — wrong on both counts Uncommented, moved into core STRIPE block, correct "required in prod" note
lib/plans.ts PLAN_CATALOG.scale Already existed No change
STRIPE_PRICE_ENV['scale'] in lib/plans.ts Already pointed at STRIPE_PRICE_SCALE (added in Sprint 4b) No change
scripts/check-env.js productionRequiredKeys Already listed STRIPE_PRICE_SCALE No change
scripts/check-stripe-prices.mjs Already validated STRIPE_PRICE_SCALE No change

So the scaffolding was already there — only the DB CHECK, onboarding picker, and env-example doc lagged behind.

Tests

  • tests/lib/plans.test.ts: expectedPlans was missing 'scale' (so the loop silently skipped scale). Now correct.
  • Adds explicit getBillingPlan('scale') coverage including stripePriceId env resolution (set → use; unset → undefined).
  • Adds getAllBillingPlans assertion that returns all 4 ids.

Validation

  • npm run type-check clean
  • npm run lint 0 errors, 17 warnings (same as 4b base)
  • npx jest 5319/5334 pass (+5 new scale tests on top of 4b's 5314)
  • Migration syntax verified against live constraint definition

Operator runbook for shipping Scale

  1. Create the Scale product + monthly price in Stripe ($1,800 USD)
  2. Add STRIPE_PRICE_SCALE=price_... to Vercel production env
  3. Merge PR fix(audit-sprint-4b): collapse 4 plan catalogs into one (PLAN_CATALOG) #166 (Sprint 4b), then this PR
  4. Apply migration 20260624020_audit_sprint6a_scale_tier_check.sql to prod
  5. Manually flip an existing test org to plan_key='scale' to verify it doesn't bounce off the CHECK constraint
  6. Watch billing-reconcile cron (PR fix(audit-sprint-1): 7 stop-the-bleed fixes from 2026-05-23 E2E audit #162) for any 'scale' drift the first night

🤖 Generated with Claude Code

Audit deep-dive found the Scale tier was advertised in marketing for
$1,800/mo but unsellable end-to-end:

  - org_subscriptions_plan_key_check rejected 'scale' (only allowed
    basic|pro|enterprise)
  - Onboarding plan picker excluded Scale (app/onboarding/page.tsx:54-58)
  - .env.example showed STRIPE_PRICE_SCALE as commented-out optional
    "comma-separated stripe price IDs" — neither true; check-env.js
    already had it in productionRequiredKeys

This PR makes the path actually work end-to-end. The Stripe price ID
itself is operator-set; PR description includes the runbook.

Changes
  - Migration 20260624020 drops + recreates
    org_subscriptions_plan_key_check with 'scale' added. Comment on the
    constraint cross-references the env var.
  - app/onboarding/page.tsx: PLAN_CHOICES adds PLAN_CATALOG.scale
    between pro and enterprise so new orgs see the Scale tier during
    self-serve onboarding.
  - .env.example moves STRIPE_PRICE_SCALE into the core STRIPE — BILLING
    block (uncommented) with the correct "required in prod" note.
  - __tests__/lib/plans.test.ts: expectedPlans was missing 'scale' (the
    assertion silently skipped it); now correct. Adds explicit
    getBillingPlan('scale') coverage with stripePriceId env resolution
    + getAllBillingPlans('scale' included) assertions.

Built on top of fix/audit-sprint-4b-plan-catalog (PR #166) because
getBillingPlan/getAllBillingPlans live there.

Validation
  - tsc -p tsconfig.typecheck.json: clean
  - eslint: 0 errors, 17 warnings (same as 4b base)
  - jest: 5319/5334 pass (+5 from new scale tests on top of 4b's 5314)

Operator runbook for shipping Scale
  1. Create the Scale product + monthly price in Stripe ($1,800 USD).
  2. Add STRIPE_PRICE_SCALE=price_... to the Vercel production env.
  3. Merge this PR (+ #166 first, since 6a depends on it).
  4. Apply migration 20260624020 to prod.
  5. Manually flip an existing test org to plan_key='scale' to verify
     it doesn't bounce off the CHECK constraint.
  6. Watch billing-reconcile cron (PR #162) for any 'scale' drift the
     first night.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented May 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
forma-os Ready Ready Preview, Comment May 23, 2026 3:43pm

Request Review

Copilot AI review requested due to automatic review settings May 23, 2026 15:38
@coderabbitai

coderabbitai Bot commented May 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 89f56e8a-8999-4412-9a77-450dca349771

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/audit-sprint-6a-scale-provisioning-v2

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 614c1e4f0b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/onboarding/page.tsx
const PLAN_CHOICES = [
PLAN_CATALOG.basic,
PLAN_CATALOG.pro,
PLAN_CATALOG.scale,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Update plan validation to accept the newly added scale tier

Adding PLAN_CATALOG.scale to onboarding choices makes users able to select Scale, but step 2 submission still calls validatePlan(planCandidate) in saveOrgDetails, and validatePlan only accepts basic|pro|enterprise (lib/validators/organization.ts PLAN_OPTIONS). In practice, choosing Scale will be rejected as invalid and redirect back with error=1, so the tier remains unsellable through onboarding despite the UI change.

Useful? React with 👍 / 👎.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to make the existing Scale plan tier sellable end-to-end by aligning database constraints, onboarding plan selection, environment documentation, and plan-catalog test coverage with the already-present PLAN_CATALOG.scale and billing helpers.

Changes:

  • Adds scale to the org_subscriptions.plan_key DB CHECK constraint (and documents it via a constraint comment).
  • Exposes Scale in the onboarding plan picker and updates .env.example to document STRIPE_PRICE_SCALE as required in production.
  • Extends lib/plans test coverage to include Scale in expected plan keys and explicitly tests getBillingPlan('scale') + getAllBillingPlans().

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
supabase/migrations/20260624020_audit_sprint6a_scale_tier_check.sql Expands org_subscriptions.plan_key allowlist to include scale and adds constraint documentation.
app/onboarding/page.tsx Adds Scale to onboarding plan choices (but currently conflicts with existing plan validation).
.env.example Documents and uncomments STRIPE_PRICE_SCALE in the core Stripe billing section; removes outdated Scale env guidance.
tests/lib/plans.test.ts Adds Scale coverage for plan catalog assertions and billing helper functions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +10 to +12
-- 2. STRIPE_PRICE_ENV['scale'] = 'STRIPE_PRICE_FOUNDATION'... wait
-- no, that's basic. Scale maps to STRIPE_PRICE_SCALE (lib/plans.ts
-- already correct).
Comment on lines +16 to +18
-- Also tightens documentation: the existing comment on the constraint
-- (added by 20260616_org_subscriptions_plan_key_check.sql) implied the
-- catalog was basic|pro|enterprise. After this migration that's wrong.
Comment thread app/onboarding/page.tsx
Comment on lines +54 to 65
// Audit Sprint 6a (2026-05-23): Scale tier added. Was deliberately
// excluded because the DB CHECK constraint on org_subscriptions
// rejected 'scale'; that's fixed by migration 20260624020. Operator
// must also set STRIPE_PRICE_SCALE in production env for checkout to
// resolve a price ID — productionRequiredKeys in check-env.js already
// guards this.
const PLAN_CHOICES = [
PLAN_CATALOG.basic,
PLAN_CATALOG.pro,
PLAN_CATALOG.scale,
PLAN_CATALOG.enterprise,
];
@ejay-dev
ejay-dev deleted the branch fix/audit-sprint-4b-plan-catalog May 23, 2026 16:52
@ejay-dev ejay-dev closed this May 23, 2026
@ejay-dev

Copy link
Copy Markdown
Owner Author

Reopened after base branch fix/audit-sprint-4b-plan-catalog was merged to main and deleted.

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