Skip to content

plans: yearly discount 17% -> 10% (hobby $97.20 / pro $529.20 / team $2149.20)#7

Merged
mastermanas805 merged 1 commit into
masterfrom
feat/yearly-10pct-fresh
May 13, 2026
Merged

plans: yearly discount 17% -> 10% (hobby $97.20 / pro $529.20 / team $2149.20)#7
mastermanas805 merged 1 commit into
masterfrom
feat/yearly-10pct-fresh

Conversation

@mastermanas805
Copy link
Copy Markdown
Member

Summary

P2 (#6) shipped annual pricing at ~17% off monthly. User wants 10% off instead — keeps yearly attractive without leaving margin on the table.

New prices (stored as annual amount in cents in price_monthly_cents, per the existing schema):

Tier Old (cents) New (cents) Old $/yr New $/yr Effective $/mo
hobby_yearly 9000 9720 $90.00 $97.20 $8.10
pro_yearly 49000 52920 $490.00 $529.20 $44.10
team_yearly 199000 214920 $1990.00 $2149.20 $179.10

Each new price = monthly_cents * 12 * 0.9. Monthly prices and all limits/features are untouched.

Tests

  • Existing TestYearlyVariants_MirrorMonthlyLimits still passes (limits + features unchanged).
  • Existing TestYearlyPrices_DiscountedVsMonthlyTimesTwelve still passes.
  • New TestYearlyDiscountIsExactly10Percent locks the contract: (yearly / 12) / monthly == 0.9 +/- 0.01 for hobby/pro/team. Future drift fails loudly.

Result: go test ./plans/... -v -> 22 PASS, 1 SKIP (TestLoad_PlansYAMLFile_MatchesDefaults — plans.yaml file not present locally; pre-existing skip, unrelated).

Operator action required (cannot be automated from this PR)

The RAZORPAY_PLAN_ID_HOBBY_YEARLY / RAZORPAY_PLAN_ID_PRO_YEARLY / RAZORPAY_PLAN_ID_TEAM_YEARLY env vars in the k8s secret still point at Razorpay plans configured with the OLD prices. The dashboard will quote the new prices once this lands, but checkout will charge the old amounts until one of the following is done:

Option A — edit existing plans in Razorpay dashboard:

  • Update the 3 yearly plans to the new prices: $97.20 / $529.20 / $2149.20.
  • No env-var changes needed.

Option B — create new plans + rotate env vars:

  • Create 3 new yearly plans in Razorpay at the new prices.
  • Update RAZORPAY_PLAN_ID_HOBBY_YEARLY, RAZORPAY_PLAN_ID_PRO_YEARLY, RAZORPAY_PLAN_ID_TEAM_YEARLY in infra/k8s/secrets.yaml (and the running cluster's instant-secrets).
  • Old plans can be deactivated once no in-flight subscriptions remain.

Dashboard impact

None — the "Save $X/yr" badge reads PriceMonthly from the registry, so it auto-updates the moment this lands.

Test plan

  • go test ./plans/... -v green
  • Operator picks Option A or B above before announcing the new pricing publicly
  • Verify dashboard "Save $X/yr" math reflects the 10% discount once the consuming repo (api / dashboard) bumps its common dependency

🤖 Generated with Claude Code

…$2149.20)

P2 shipped the yearly variants at ~17% off monthly. User feedback: 17% is
too steep a give-up on annual revenue; standardize on 10% off across all
three tiers to keep yearly attractive without leaving margin on the table.

New prices (annual amount in cents, stored in price_monthly_cents per the
existing schema):

  hobby_yearly:  9000   -> 9720    ($90.00   -> $97.20)
  pro_yearly:   49000   -> 52920   ($490.00  -> $529.20)
  team_yearly: 199000   -> 214920  ($1990.00 -> $2149.20)

Each new price = (monthly * 12 * 0.9), giving an effective monthly rate
of $8.10 / $44.10 / $179.10 respectively.

Tests:
  - existing TestYearlyVariants_MirrorMonthlyLimits still passes (limits +
    features unchanged)
  - existing TestYearlyPrices_DiscountedVsMonthlyTimesTwelve still passes
  - new TestYearlyDiscountIsExactly10Percent locks the contract:
    (yearly / 12) / monthly == 0.9 +/- 0.01 for hobby/pro/team. Future
    price changes that drift the discount fail loudly.

Operator action required (not automatable from this PR): the existing
RAZORPAY_PLAN_ID_HOBBY_YEARLY / _PRO_YEARLY / _TEAM_YEARLY env vars still
point at the OLD prices in the Razorpay dashboard. Operator must EITHER
edit the 3 existing yearly plans in Razorpay to the new prices
($97.20, $529.20, $2149.20) OR create 3 new plans + rotate the env vars
in the k8s secret. Until then, checkout will charge the old amounts even
though the dashboard quotes the new ones.

Dashboard impact: none — the "Save $X/yr" badge reads PriceMonthly from
the registry, so it auto-updates once this lands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mastermanas805 mastermanas805 merged commit 896390a into master May 13, 2026
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.

1 participant