plans: yearly discount 17% -> 10% (hobby $97.20 / pro $529.20 / team $2149.20)#7
Merged
Merged
Conversation
…$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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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):hobby_yearlypro_yearlyteam_yearlyEach new price =
monthly_cents * 12 * 0.9. Monthly prices and all limits/features are untouched.Tests
TestYearlyVariants_MirrorMonthlyLimitsstill passes (limits + features unchanged).TestYearlyPrices_DiscountedVsMonthlyTimesTwelvestill passes.TestYearlyDiscountIsExactly10Percentlocks the contract:(yearly / 12) / monthly == 0.9 +/- 0.01for 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_YEARLYenv 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:
Option B — create new plans + rotate env vars:
RAZORPAY_PLAN_ID_HOBBY_YEARLY,RAZORPAY_PLAN_ID_PRO_YEARLY,RAZORPAY_PLAN_ID_TEAM_YEARLYininfra/k8s/secrets.yaml(and the running cluster'sinstant-secrets).Dashboard impact
None — the "Save $X/yr" badge reads
PriceMonthlyfrom the registry, so it auto-updates the moment this lands.Test plan
go test ./plans/... -vgreencommondependency🤖 Generated with Claude Code