feat(admin): track 12-month plan upgrade rate#2717
Conversation
Add upgrade_rate_12m so admin revenue can show what share of orgs upgraded in the trailing year, with daily collection and a backfill script for history. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
🔗 Linked repositories identifiedCodeRabbit considers these linked repositories for cross-repo context during reviews:
📝 WalkthroughWalkthroughAdds a trailing 12-month upgrade-rate metric to global statistics, snapshot generation, backfill tooling, admin trend data, and the revenue dashboard. It also adds localization and tests, and renames an authentication hint translation key. Changes12-month upgrade rate
Authentication hint translation
Estimated code review effort: 4 (Complex) | ~45 minutes Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
Comment |
Merging this PR will not alter performance
Comparing Footnotes
|
Remove duplicate Insert field that broke CLI and frontend typecheck. Co-authored-by: Cursor <cursoragent@cursor.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_a25a7e26-0ff9-4ff7-a2bd-71dce2f3b72e) |
Rename the verify-access hint key so PR analysis does not flag a hard-coded credential false positive when en.json changes. Co-authored-by: Cursor <cursoragent@cursor.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_0fc257d3-1200-424f-b590-d1499712b5d5) |
There was a problem hiding this comment.
All reported issues were addressed
Confidence score: 5/5
- Safe to merge after the addressed issues were fixed.
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
There was a problem hiding this comment.
Stale comment
Risk: medium. Cursor Bugbot did not complete (check skipped; usage limit reached), so automated review is unavailable. Human review is still needed for this migration and billing metric change; Dalanir and WcaleNieWolny are already assigned.
Sent by Cursor Approval Agent: Pull Request Approver External
Rethrow shard SQL failures, use calendar-year windows, stabilize pagination ordering, and validate backfill date args. Co-authored-by: Cursor <cursoragent@cursor.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_3086c008-2641-4fb5-99a6-91d629bcd377) |
There was a problem hiding this comment.
Stale comment
Risk: medium. Not approving: Cursor Bugbot completed as skipped (usage limit reached), so automated review did not run. Human review is still needed for this migration and billing metric change; Dalanir and WcaleNieWolny are already assigned.
Sent by Cursor Approval Agent: Pull Request Approver External
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@supabase/migrations/20260721110632_admin_upgrade_rate_12m.sql`:
- Line 5: Wrap the PostgreSQL column comment string in the migration’s IS clause
using adjacent string literals so no line exceeds SQLFluff’s length limit.
Preserve the exact stored comment text and meaning while only changing its
formatting.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 9819090d-0ae9-491d-9db1-25301b9a52b5
📒 Files selected for processing (3)
scripts/backfill_upgrade_rate_12m.tssupabase/functions/_backend/triggers/logsnag_insights.tssupabase/migrations/20260721110632_admin_upgrade_rate_12m.sql
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
Cap-go/capacitor-updater(manual)
There was a problem hiding this comment.
All reported issues were addressed across 3 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
Wrap the migration comment for SQLFluff, keyset-paginate the backfill sources, and clamp leap-year trailing windows. Co-authored-by: Cursor <cursoragent@cursor.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_d41283e5-1acf-4bcb-b235-8f17f0f9d68c) |
There was a problem hiding this comment.
Stale comment
Risk: medium. Not approving: Cursor Bugbot completed as skipped (usage limit reached), so automated review did not run, and this migration plus billing metric change exceeds the low-risk approval threshold. Human review is still needed; Dalanir and WcaleNieWolny are already assigned.
Sent by Cursor Approval Agent: Pull Request Approver External
There was a problem hiding this comment.
All reported issues were addressed across 4 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
Keep the daily shard window helper aligned with the backfill leap-day behavior. Co-authored-by: Cursor <cursoragent@cursor.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_0f887bb4-6ebf-44d8-a8a4-89b7e88b472d) |
There was a problem hiding this comment.
Risk: medium. Not approving: Cursor Bugbot completed as skipped (usage limit reached), so automated review did not run, and this migration plus billing metric change exceeds the low-risk approval threshold. Human review is still needed; Dalanir and WcaleNieWolny are already assigned.
Sent by Cursor Approval Agent: Pull Request Approver External
|
There was a problem hiding this comment.
2 issues found across 5 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="scripts/backfill_upgrade_rate_12m.ts">
<violation number="1" location="scripts/backfill_upgrade_rate_12m.ts:207">
P3: An interruption after scanning millions of rows still forces both source scans to restart because these cursors exist only in memory. Persisting checkpoints plus fetched/processed batches, or moving the bounded computation into the database, would make the backfill actually resumable.</violation>
<violation number="2" location="scripts/backfill_upgrade_rate_12m.ts:213">
P2: A live production scan can omit orgs inserted during pagination because random UUIDs may sort below `lastId` after that cursor has passed. A repeatable-read database snapshot would keep the org and `stripe_info` inputs internally consistent.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
| let query = supabase | ||
| .from('orgs') | ||
| .select('id, created_at, customer_id') | ||
| .order('id', { ascending: true }) |
There was a problem hiding this comment.
P2: A live production scan can omit orgs inserted during pagination because random UUIDs may sort below lastId after that cursor has passed. A repeatable-read database snapshot would keep the org and stripe_info inputs internally consistent.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/backfill_upgrade_rate_12m.ts, line 213:
<comment>A live production scan can omit orgs inserted during pagination because random UUIDs may sort below `lastId` after that cursor has passed. A repeatable-read database snapshot would keep the org and `stripe_info` inputs internally consistent.</comment>
<file context>
@@ -188,17 +204,19 @@ async function fetchGlobalStatsRows(supabase: SupabaseClient, fromDateId: string
.select('id, created_at, customer_id')
- .order('created_at', { ascending: true })
- .range(offset, offset + DEFAULT_PAGE_SIZE - 1)
+ .order('id', { ascending: true })
+ .limit(DEFAULT_PAGE_SIZE)
</file context>
| @@ -0,0 +1,343 @@ | |||
| /* | |||
There was a problem hiding this comment.
P3: An interruption after scanning millions of rows still forces both source scans to restart because these cursors exist only in memory. Persisting checkpoints plus fetched/processed batches, or moving the bounded computation into the database, would make the backfill actually resumable.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/backfill_upgrade_rate_12m.ts, line 207:
<comment>An interruption after scanning millions of rows still forces both source scans to restart because these cursors exist only in memory. Persisting checkpoints plus fetched/processed batches, or moving the bounded computation into the database, would make the backfill actually resumable.</comment>
<file context>
@@ -188,17 +204,19 @@ async function fetchGlobalStatsRows(supabase: SupabaseClient, fromDateId: string
async function fetchOrgRows(supabase: SupabaseClient, toDateId: string | null) {
const rows: OrgRow[] = []
- let offset = 0
+ let lastId: string | null = null
while (true) {
</file context>





Summary (AI generated)
global_stats.upgrade_rate_12m(single new column) for the share of orgs whose laststripe_info.upgraded_atfalls in the trailing 12 monthslogsnag_insightsrevenue shardbun run stripe:backfill-upgrade-rate-12mto backfill historical rowsMotivation (AI generated)
Admin was missing a clear view of how many organizations upgraded their plan over the last 12 months. Daily snapshots plus a backfill script cover both forward and past data without changing other schema surfaces.
Business Impact (AI generated)
Gives Capgo clearer retention/expansion visibility: how much of the org base actively upgraded in the last year, which helps pricing and success decisions.
Test Plan (AI generated)
upgrade_rate_12monly onglobal_stats)--apply --alland wrote non-zero ratestests/backfill-upgrade-rate-12m.unit.test.ts)bun run stripe:backfill-upgrade-rate-12m --apply --all(against prod env)Generated with AI
Made with Cursor
Summary by CodeRabbit
upgrade_rate_12m(defaults to 0).