feat(billing): honest yearly overage-lock copy, forms/comments/CDN over the billing window - #413
Merged
Merged
Conversation
…act support' A yearly subscription prices no meter, so its overage toggles are locked. The lock reason read 'not available on your subscription yet — contact support to update it', which support cannot do: Polar invoices metered usage on the subscription's own cycle, so overage on a yearly plan would be billed once a year, not monthly. The lock now carries its own reason (yearly_plan, a period longer than a month) and the usage panel and the overage-settings refusal say what is true: usage resets every month and stops at the plan limit until overage is billed monthly there.
… like the other quotas AI, API and MCP credits already reset on the subscription's anniversary; forms, comments and CDN origin transfer still counted the calendar month. The payment provider invoices overage on the subscription's cycle, so the screen and the invoice could close on different days — and on a yearly plan, whose usage is monthly, the counters must follow the monthly slice too. - the row-counted readers and the two atomic submit functions take a window [from, to); without one they keep the calendar month (free, self-hosted) - migration 046 replaces create_form_submission_if_allowed and create_comment_if_allowed with the same bodies plus two defaulted window parameters; a caller that passes none behaves as before - the CDN keeps one row per UTC day, so its window is whole days: the day the slice opens on is in, the day the next one opens on is out; its origin budget counter is keyed by the window and Retry-After runs to the slice end - the public form/comment/CDN routes resolve the window from a one-minute cache of the payment account (the window itself is computed at each call's time) A subscribed workspace's form/comment/CDN usage alerts re-key from YYYY-MM to the slice start once, so an alert already sent this month can be sent once more.
Member
Author
|
ONAY @ 8a041b8 — ORK review: yearly overage-lock copy + forms/comments/CDN counters aligned to the billing slice (founder approved 2026-10-04). 046 re-creates the two RPCs with defaulted window params (old callers keep calendar month); no grant changes before/after. CI ci+postgres-lineage green; studio-dev local test:ci (unit 2049, integration 488, nuxt 274), contract 162. |
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.
What
Yearly plans only change billing frequency; limits stay the monthly tier limits. This PR makes the Studio side honest about that.
yearly_planreason) instead of the trial/not-in-subscription one.Upgrade notes
046_usage_window_quotas.sqldrops and recreatescreate_form_submission_if_allowed/create_comment_if_allowedwith two defaulted window params. Run it before the new image. The old image still works against the new functions (params default), so rolling back the image alone is safe.NOTIFY pgrstadded: earlier migrations that changed RPC signatures (010, 038) don't use it either, and none in the repo does. Supabase-pair reviewer, please confirm.YYYY-MMto the slice start once, so one extra usage alert may go out in the transition month. CDN window is whole UTC days.Deploy order (migration 046 before the image)
node scripts/migrate-postgres.mjsruns before the new image serves; the app does not migrate at boot (Dockerfile comment, docs/REMOTE_MCP_SUBMISSION.md). Re-runs skip applied files viapublic.schema_migrations.pnpm db:migrate, docs/DEPLOYMENT.md) before the image goes out.maindeploys staging, so on the managed pair 046 applies by itself as part of that deploy.Note for the companion-subscription PR
isYearlyPeriodlabels every unpriced meter on a >35-day period asyearly_plan. Correct today (yearly products price nothing). Once the companion usage subscription mergesbillable_meters, a yearly account missing one meter should readnot_in_subscriptionagain, so the reason picker must key on "subscription prices nothing", not "period is long". Label only, not an enforcement bug.Verification
pnpm test:ci: unit 2049, integration 488, nuxt 274, all greenscripts/migrate-postgres.mjs)pnpm typecheckclean, eslint 0 errors