Skip to content

feat(devpass): add weekly premium Reset Passes - #3093

Merged
steebchen merged 20 commits into
mainfrom
feat/devpass-reset-passes
Jul 17, 2026
Merged

steebchen merged 20 commits into
mainfrom
feat/devpass-reset-passes

Conversation

@smakosh

@smakosh smakosh commented Jul 16, 2026 •

Copy link
Copy Markdown
Member

What

Reset Passes — a consumable add-on that instantly restores a DevPass subscriber's weekly premium-model allowance (fresh 7-day window) instead of making them wait out the rolling window or upgrade. A pass lifts the weekly limit only — it grants no extra credits; usage still draws from the monthly allowance.

Tier Weekly premium cap Pass price Included / cycle
Lite $10.44 $9 0
Pro $35.55 $29 1
Max $96.66 $79 2

Pricing rationale: ~82–86% of the weekly cap each pass unlocks — cheaper than the equivalent PAYG credits, while the unlocked spend still draws from the already-granted monthly pool, keeping the pool as the hard cost ceiling. Included passes are non-rollover and consumed before purchased ones. Purchased inventory is tier-bound (per-tier columns): a pass is redeemable only on the tier it was bought for, closing cheap-tier arbitrage; unused passes persist and apply again when back on that tier.

How

  • Shared: DEV_PLAN_RESET_PASS_PRICES, DEV_PLAN_INCLUDED_RESET_PASSES, getIncludedResetPassesRemaining + unit tests.
  • DB: per-tier purchased inventory (devPlanResetPassesLite/Pro/Max) + devPlanIncludedResetPassesUsed (per-cycle counter, cleared on subscribe/upgrade/renewal/plan-end); dev_plan_reset_pass transaction type; generated migration.
  • API:
    • POST /dev-plans/reset-pass/purchase — confirmation-dialog flow: charges the saved payment method via an off-session PaymentIntent (no Stripe Checkout redirect); synchronous atomic fulfilment (transaction row + tier inventory in one DB tx), invoice email, PostHog reset_pass_purchased; card declines return 402.
    • POST /dev-plans/reset-pass/redeem — zeroes premium usage and clears the week; included-first consumption; requires verified email; compare-and-swap on observed premium usage/week-start + inventory guards blocks double-redeem races (verified live with concurrent requests).
    • Status endpoint returns tier-scoped inventory + price; DevPass invoices list shows pass purchases; dev_plan_reset_pass in DevPass revenue/paid filters.
  • Gateway: premium-cap 402 message points at Reset Passes.
  • Dashboard (apps/code): weekly allowance meter redesigned ("$X spent / Resets MMM d / N% used" slim-track layout); Reset Pass card styled as a stamped passport visa extension — stamp slots, redeem animation, MRZ footer, buy-confirmation dialog. Pricing page matrix row + FAQ entry.
  • Fix (apps/ui): Geist Mono registered under --font-geist-mono so the font-mono token resolves — changelog code blocks now render monospace.
  • Content: changelog entry with gpt-image-2 OG art, learn/reset-passes KB page + Reset Passes section in the fair-use doc (all state limit-only semantics), fresh light/dark KB screenshots (reset-passes, dashboard with populated demo data) and an updated /enterprise dashboard showcase pair.

Verification (all driven live)

  • Saved-card purchase: off-session PaymentIntent charged $29 → tier inventory +1 → completed transaction + invoice; decline path returns 402.
  • Tier binding: Pro-bought passes invisible/unredeemable on Lite (400 + status shows 0), redeemable again on Pro.
  • Double-redeem race: 2 passes held, 2 concurrent redeems → exactly 1 pass consumed.
  • Dashboard: dialog → charge → stamp appears; redeem → 'Allowance restored' stamp + meter back to $0.00 spent; disabled states correct.
  • Gateway 402 copy; pnpm build all apps; affected unit suites green.

Follow-ups

  • No analytics event when the gateway premium-cap 402 fires (gateway has no PostHog) — add to size demand.
  • /enterprise showcase: only the dashboard pair was refreshed; playground/image-studio/video-studio/admin/docs pairs untouched.

https://claude.ai/code/session_01DiqhTuu8Gg6nUXFuaRVUH3

Summary by CodeRabbit

  • New Features
    • DevPass users can redeem Reset Passes to instantly restore the weekly premium allowance and restart the 7-day window.
    • DevPass users can purchase additional, tier-specific passes from the dashboard using the saved payment method.
    • Updates apply instantly, showing remaining included/purchased availability.
  • Dashboard
    • Added a Reset Pass card and updated the weekly allowance meter with Reset Pass guidance.
  • Billing
    • Reset Pass purchases now generate invoices, appear in billing history, and use clearer invoice type labels.
  • Documentation
    • Added Reset Pass docs, FAQ, and a changelog entry explaining included vs purchased behavior and examples.

Reset Passes let DevPass subscribers instantly restore their weekly
premium-model allowance instead of waiting for the rolling 7-day window.

- Tier pricing at ~82-86% of the weekly cap each pass unlocks:
  $9 Lite / $29 Pro / $79 Max (DEV_PLAN_RESET_PASS_PRICES).
- Included passes per cycle: 0 Lite / 1 Pro / 2 Max, non-rollover;
  consumed before purchased passes. Purchased passes survive plan
  changes and plan end.
- One-time Stripe Checkout purchase + webhook fulfillment with
  payment-intent dedup, invoice email, and PostHog event.
- Explicit redeem endpoint zeroes premium usage and clears the window;
  atomic counter guards prevent double-redeem races.
- Dashboard: Reset Pass card styled as a stamped passport visa
  extension (stamp slots, redeem animation, MRZ footer), wired into
  the premium meter; billing history shows pass purchases.
- Gateway premium-cap 402 now points at Reset Passes; pricing page
  matrix row + FAQ entry added.

Claude-Session: https://claude.ai/code/session_01DiqhTuu8Gg6nUXFuaRVUH3
@coderabbitai

coderabbitai Bot commented Jul 16, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Changes

Reset Passes add tier-specific pricing and included allowances, persistent purchased inventory, Stripe-backed purchase and atomic redemption APIs, billing-cycle resets, dashboard interactions, gateway guidance, transaction classification, and documentation.

DevPass Reset Passes

Layer / File(s) Summary
Data contracts and pricing
packages/db/..., packages/shared/..., apps/api/src/routes/organization.ts
Adds Reset Pass counters, transaction and audit types, tier pricing, included-pass calculations, migrations, and tests.
API purchase and redemption flow
apps/api/src/routes/dev-plans.ts
Exposes status and invoice data, charges saved payment methods, records purchases, and atomically redeems included or purchased passes.
Billing lifecycle
apps/api/src/stripe.ts
Handles purchase fulfillment, webhook recovery, refunds, and included-pass resets across DevPass lifecycle events.
Dashboard interactions
apps/code/src/app/dashboard/..., apps/ui/src/app/layout.tsx
Adds allowance-meter messaging, Reset Pass stamps, purchase confirmation, redemption behavior, status refreshes, invoice labels, and font-token wiring.
Gateway and transaction handling
apps/gateway/..., apps/api/src/utils/devpass-filter.ts
Updates premium-cap guidance, transaction filters, and rate-limit fixtures for Reset Pass fields.
Pricing and documentation
apps/code/src/app/pricing/page.tsx, apps/code/src/components/Faq.tsx, apps/docs/content/learn/*, apps/ui/src/content/changelog/*
Documents Reset Pass pricing, eligibility, redemption, purchasing, and billing behavior.
Verification workflow
.claude/skills/verify/SKILL.md
Adds local end-to-end verification instructions for the stack and related tooling.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Dashboard
  participant DevPlansAPI
  participant Stripe
  participant Database
  Dashboard->>DevPlansAPI: Request Reset Pass status
  DevPlansAPI->>Database: Read inventory and premium usage
  Database-->>DevPlansAPI: Return pass counts and allowance state
  Dashboard->>DevPlansAPI: Purchase or redeem a Reset Pass
  DevPlansAPI->>Stripe: Charge saved payment method
  DevPlansAPI->>Database: Record purchase or atomically reset usage
  DevPlansAPI-->>Dashboard: Return updated pass inventory
Loading

Possibly related PRs

Suggested reviewers: steebchen

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding weekly premium Reset Passes to DevPass.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/devpass-reset-passes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

smakosh and others added 2 commits July 16, 2026 21:02
- Changelog entry with gpt-image-2 OG image
- Knowledge base page learn/reset-passes with light/dark screenshots
  of the visa-extension card and billing history
- Reset Passes section + cross-link in model-categories fair-use doc

Claude-Session: https://claude.ai/code/session_01DiqhTuu8Gg6nUXFuaRVUH3
@steebchen

Copy link
Copy Markdown
Member

Images automagically compressed by Calibre's image-actions ✨

Compression reduced images by 72%, saving 1.8 MB.

Filename Before After Improvement Visual comparison
apps/ui/public/changelog/devpass-reset-passes.png 2.2 MB 642.6 KB 72.1% View diff
apps/docs/public/learn/reset-passes-dark.png 63.7 KB 17.6 KB 72.3% View diff
apps/docs/public/learn/reset-passes-light.png 62.8 KB 18.9 KB 69.9% View diff
apps/docs/public/learn/reset-passes-billing-light.png 45.1 KB 13.2 KB 70.6% View diff
apps/docs/public/learn/reset-passes-billing-dark.png 45.2 KB 13.4 KB 70.3% View diff

@steebchen

Copy link
Copy Markdown
Member

Images automagically compressed by Calibre's image-actions ✨

Compression reduced images by 8.8%, saving 4.4 KB.

Filename Before After Improvement Visual comparison
apps/docs/public/learn/reset-passes-dark.png 17.6 KB 15.2 KB 13.9% View diff
apps/docs/public/learn/reset-passes-light.png 18.9 KB 17.7 KB 6.4% View diff
apps/docs/public/learn/reset-passes-billing-light.png 13.2 KB 12.5 KB 5.4% View diff

2 images did not require optimisation.

@steebchen

Copy link
Copy Markdown
Member

Images automagically compressed by Calibre's image-actions ✨

Compression reduced images by 6.8%, saving 1.2 KB.

Filename Before After Improvement Visual comparison
apps/docs/public/learn/reset-passes-light.png 17.7 KB 16.5 KB 6.8% View diff

4 images did not require optimisation.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 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 @.claude/skills/verify/SKILL.md:
- Around line 16-25: Update the service startup instructions in SKILL.md to make
the API, DevPass dashboard, and gateway commands run in separate terminal
sessions, explicitly labeling each session. Keep the existing commands and
configuration unchanged while removing the sequential single-shell execution
ambiguity.

In `@apps/api/src/routes/dev-plans.ts`:
- Around line 2887-2908: Update the redeemResetPass handler to independently
require a verified email after the existing authentication check and before
entitlement validation. Reuse the established email-verification guard or user
verification field and return the standard unauthorized/forbidden response when
the email is unverified, while preserving the existing personal-organization and
dev-plan checks.
- Around line 2813-2838: Update the checkout session creation in
handleResetPassCheckout to restrict accepted payment methods to cards,
preventing delayed payment methods from creating sessions that cannot be
fulfilled. Preserve the existing checkout metadata, URLs, pricing, and
fulfillment flow.
- Around line 2910-2975: Update the redeem flow around the organization update
to make the reset conditional on the originally observed premium allowance
state, not only pass inventory. Add compare-and-swap predicates for
personalOrg.devPlanPremiumCreditsUsed and personalOrg.devPlanPremiumWeekStart
alongside the existing pass guards, so only one concurrent request can reset the
same allowance; preserve the existing successful update and error behavior when
no row matches.

In `@packages/db/src/schema.ts`:
- Around line 262-265: Bind purchased Reset Pass inventory to the paid tier
instead of allowing cross-tier redemption: update
packages/db/src/schema.ts:262-265 to represent tier-specific inventory,
regenerate packages/db/migrations/1784223442_graceful_lady_bullseye.sql:1-1
accordingly, retain tier pricing in packages/shared/src/dev-plans.ts:45-49 only
with tier-bound entitlements, encode the entitlement tier in the checkout
contract in apps/api/src/routes/dev-plans.ts:2805-2837, and have the
apps/api/src/stripe.ts:1960-1984 flow validate the charged tier and amount
before incrementing only that tier’s inventory.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e37259e4-db29-428d-aeba-8934230993e8

📥 Commits

Reviewing files that changed from the base of the PR and between 1228622 and e107717.

⛔ Files ignored due to path filters (5)
  • apps/docs/public/learn/reset-passes-billing-dark.png is excluded by !**/*.png
  • apps/docs/public/learn/reset-passes-billing-light.png is excluded by !**/*.png
  • apps/docs/public/learn/reset-passes-dark.png is excluded by !**/*.png
  • apps/docs/public/learn/reset-passes-light.png is excluded by !**/*.png
  • apps/ui/public/changelog/devpass-reset-passes.png is excluded by !**/*.png
📒 Files selected for processing (25)
  • .claude/skills/verify/SKILL.md
  • apps/api/src/routes/dev-plans.ts
  • apps/api/src/routes/organization.ts
  • apps/api/src/stripe.ts
  • apps/api/src/utils/devpass-filter.ts
  • apps/code/src/app/dashboard/(main)/page.tsx
  • apps/code/src/app/dashboard/components/DevPassInvoices.tsx
  • apps/code/src/app/dashboard/components/ResetPassCard.tsx
  • apps/code/src/app/dashboard/components/UsageOverview.tsx
  • apps/code/src/app/pricing/page.tsx
  • apps/code/src/components/Faq.tsx
  • apps/docs/content/learn/index.mdx
  • apps/docs/content/learn/meta.json
  • apps/docs/content/learn/model-categories.mdx
  • apps/docs/content/learn/reset-passes.mdx
  • apps/gateway/src/chat/tools/resolve-provider-context.ts
  • apps/gateway/src/lib/rate-limit.spec.ts
  • apps/ui/src/content/changelog/2026-07-16-devpass-reset-passes.md
  • packages/db/migrations/1784223442_graceful_lady_bullseye.sql
  • packages/db/migrations/meta/1784223442_snapshot.json
  • packages/db/migrations/meta/_journal.json
  • packages/db/src/schema.ts
  • packages/shared/src/dev-plans.spec.ts
  • packages/shared/src/dev-plans.ts
  • packages/shared/src/index.ts

Comment thread .claude/skills/verify/SKILL.md Outdated
Comment thread apps/api/src/routes/dev-plans.ts Outdated
Comment thread apps/api/src/routes/dev-plans.ts
Comment thread apps/api/src/routes/dev-plans.ts
Comment thread packages/db/src/schema.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 @.claude/skills/verify/SKILL.md:
- Around line 12-25: Update the service startup commands in the verification
instructions so the API, DevPass dashboard, and gateway all launch during one
documented verification flow. Since the API and gateway commands are foreground
processes, separate each service into its own terminal block or explicitly
background the processes while preserving their existing ports and environment
variables.

In `@apps/api/src/routes/dev-plans.ts`:
- Around line 2904-2975: Update the atomic UPDATE in the Reset Pass redemption
handler to add a live-row guard that requires the premium allowance to still be
non-full before consuming inventory, using the current database values rather
than the stale personalOrg snapshot. Preserve the existing source-specific
inventory guards and ensure a concurrent redemption that already reset the
window matches zero rows instead of consuming another pass.

In `@apps/api/src/stripe.ts`:
- Line 3792: Update the renewal flow around the organization update and renewal
transaction insert so both database writes execute within a single atomic DB
transaction, ensuring retries cannot observe only the transaction record. Commit
this combined transaction before sending the invoice, and preserve the existing
allowance reset values and invoice behavior.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7df2ce8b-9711-4cb5-9999-ab41f6583dd1

📥 Commits

Reviewing files that changed from the base of the PR and between 1228622 and 4dec122.

📒 Files selected for processing (20)
  • .claude/skills/verify/SKILL.md
  • apps/api/src/routes/dev-plans.ts
  • apps/api/src/routes/organization.ts
  • apps/api/src/stripe.ts
  • apps/api/src/utils/devpass-filter.ts
  • apps/code/src/app/dashboard/(main)/page.tsx
  • apps/code/src/app/dashboard/components/DevPassInvoices.tsx
  • apps/code/src/app/dashboard/components/ResetPassCard.tsx
  • apps/code/src/app/dashboard/components/UsageOverview.tsx
  • apps/code/src/app/pricing/page.tsx
  • apps/code/src/components/Faq.tsx
  • apps/gateway/src/chat/tools/resolve-provider-context.ts
  • apps/gateway/src/lib/rate-limit.spec.ts
  • packages/db/migrations/1784223442_graceful_lady_bullseye.sql
  • packages/db/migrations/meta/1784223442_snapshot.json
  • packages/db/migrations/meta/_journal.json
  • packages/db/src/schema.ts
  • packages/shared/src/dev-plans.spec.ts
  • packages/shared/src/dev-plans.ts
  • packages/shared/src/index.ts

Comment thread .claude/skills/verify/SKILL.md
Comment thread apps/api/src/routes/dev-plans.ts
Comment thread apps/api/src/stripe.ts
smakosh and others added 3 commits July 16, 2026 21:24
Review fixes for PR #3093:

- Redeem: compare-and-swap on the observed premium usage and week start
  so two concurrent redeems can't each burn a pass to reset the same
  allowance (verified live: 2 passes held, 2 concurrent requests, only
  1 consumed)
- Redeem: require a verified email, matching the checkout route
- Checkout: cards only — fulfillment has no async-payment handler, so
  delayed methods would charge without granting the pass
- verify skill: label the three servers as separate terminal sessions

Skipped: tier-bound pass inventory — purchased passes surviving tier
changes is deliberate, documented behavior (changelog/docs/KB); the
cross-tier arbitrage is bounded and gated behind paying the full
higher-tier price, and both the price and tier metadata originate
server-side.

Claude-Session: https://claude.ai/code/session_01DiqhTuu8Gg6nUXFuaRVUH3
Review follow-ups and UX changes for PR #3093:

- Purchased Reset Pass inventory is now tier-bound (per-tier columns,
  regenerated migration): a pass is redeemable only on the tier it was
  bought for, closing cheap-tier arbitrage. Verified live: pro passes
  invisible on lite, redeemable again back on pro.
- Buying a pass now shows a confirmation dialog and charges the saved
  payment method via an off-session PaymentIntent with synchronous,
  atomic fulfilment — no Stripe Checkout redirect. Declines return 402.
- Weekly premium allowance meter redesigned: '$X spent / Resets MMM d'
  on the left, slim track, 'N% used' on the right.
- Copy across the card, dialog, changelog, KB, fair-use doc and FAQ now
  states a pass lifts the weekly limit only — it grants no credits.
- apps/ui: register Geist Mono as --font-geist-mono so the font-mono
  token resolves and changelog code blocks render monospace.
- Fresh KB screenshots (reset-passes with the new meter, dashboard with
  populated demo data) and a new /enterprise dashboard showcase pair.

Claude-Session: https://claude.ai/code/session_01DiqhTuu8Gg6nUXFuaRVUH3
@steebchen

Copy link
Copy Markdown
Member

Images automagically compressed by Calibre's image-actions ✨

Compression reduced images by 66.8%, saving 781.6 KB.

Filename Before After Improvement Visual comparison
apps/docs/public/learn/dashboard-dark.png 272.9 KB 90.0 KB 67.0% View diff
apps/docs/public/learn/dashboard-light.png 274.8 KB 96.1 KB 65.0% View diff
apps/ui/public/screenshots/dashboard-dark.png 127.9 KB 44.1 KB 65.5% View diff
apps/ui/public/screenshots/dashboard-light.png 129.5 KB 45.8 KB 64.6% View diff
apps/docs/public/learn/reset-passes-dark.png 67.5 KB 18.3 KB 72.8% View diff
apps/docs/public/learn/reset-passes-light.png 66.0 KB 19.8 KB 70.0% View diff
apps/docs/public/learn/dashboard-cost-dark.png 57.2 KB 17.3 KB 69.8% View diff
apps/docs/public/learn/dashboard-cost-light.png 56.9 KB 18.1 KB 68.2% View diff
apps/docs/public/learn/dashboard-usage-dark.png 56.4 KB 17.8 KB 68.3% View diff
apps/docs/public/learn/dashboard-usage-light.png 57.8 KB 20.2 KB 65.1% View diff
apps/docs/public/learn/reset-passes-billing-light.png 1.6 KB 495 B 70.6% View diff
apps/docs/public/learn/reset-passes-billing-dark.png 1.6 KB 503 B 70.2% View diff

1 image did not require optimisation.

@steebchen

Copy link
Copy Markdown
Member

Images automagically compressed by Calibre's image-actions ✨

Compression reduced images by 6.4%, saving 13.5 KB.

Filename Before After Improvement Visual comparison
apps/docs/public/learn/dashboard-dark.png 90.0 KB 84.6 KB 6.0% View diff
apps/ui/public/screenshots/dashboard-light.png 45.8 KB 43.5 KB 5.1% View diff
apps/docs/public/learn/dashboard-cost-light.png 18.1 KB 16.1 KB 11.0% View diff
apps/docs/public/learn/reset-passes-light.png 19.8 KB 18.0 KB 9.0% View diff
apps/docs/public/learn/reset-passes-dark.png 18.3 KB 17.4 KB 5.4% View diff
apps/docs/public/learn/dashboard-cost-dark.png 17.3 KB 16.3 KB 5.5% View diff
apps/docs/public/learn/reset-passes-billing-dark.png 503 B 474 B 5.8% View diff
apps/docs/public/learn/reset-passes-billing-light.png 495 B 466 B 5.9% View diff

5 images did not require optimisation.

@steebchen

Copy link
Copy Markdown
Member

Images automagically compressed by Calibre's image-actions ✨

Compression reduced images by 5.9%, saving 3.6 KB.

Filename Before After Improvement Visual comparison
apps/ui/public/screenshots/dashboard-light.png 43.5 KB 41.1 KB 5.4% View diff
apps/docs/public/learn/reset-passes-dark.png 17.4 KB 16.1 KB 7.1% View diff
apps/docs/public/learn/reset-passes-billing-dark.png 474 B 448 B 5.5% View diff

10 images did not require optimisation.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@apps/api/src/routes/dev-plans.ts`:
- Around line 2889-2896: Update the catch block handling “Reset Pass charge
failed” to return HTTP 402 only for recognized Stripe payment-decline error
codes, following the tier-change handler’s existing pattern; rethrow all other
errors so configuration, outage, and programming failures reach the global
handler unchanged.
- Around line 2868-2949: The Reset Pass purchase flow around paymentIntent
creation and the db.transaction must be made retry-safe: persist a unique
purchase token before charging, pass that stable token as Stripe’s idempotency
key, and associate it with the transaction/pass fulfillment. Add recovery for
failures after a successful charge by reconciling the persisted purchase state
on retry or refunding orphaned PaymentIntents, ensuring retries cannot create
duplicate charges or grants.

In `@apps/code/src/app/dashboard/components/UsageOverview.tsx`:
- Around line 95-108: Update the allowance meter’s inner progress element in
UsageOverview to expose progressbar semantics, including an accessible label,
the current clamped value, and explicit minimum and maximum range values.
Preserve the existing visual classes and width styling.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 64088700-9989-493c-ba4a-37f442842b6e

📥 Commits

Reviewing files that changed from the base of the PR and between e17a64a and 3f70284.

⛔ Files ignored due to path filters (12)
  • apps/docs/public/learn/dashboard-cost-dark.png is excluded by !**/*.png
  • apps/docs/public/learn/dashboard-cost-light.png is excluded by !**/*.png
  • apps/docs/public/learn/dashboard-dark.png is excluded by !**/*.png
  • apps/docs/public/learn/dashboard-light.png is excluded by !**/*.png
  • apps/docs/public/learn/dashboard-usage-dark.png is excluded by !**/*.png
  • apps/docs/public/learn/dashboard-usage-light.png is excluded by !**/*.png
  • apps/docs/public/learn/reset-passes-billing-dark.png is excluded by !**/*.png
  • apps/docs/public/learn/reset-passes-billing-light.png is excluded by !**/*.png
  • apps/docs/public/learn/reset-passes-dark.png is excluded by !**/*.png
  • apps/docs/public/learn/reset-passes-light.png is excluded by !**/*.png
  • apps/ui/public/screenshots/dashboard-dark.png is excluded by !**/*.png
  • apps/ui/public/screenshots/dashboard-light.png is excluded by !**/*.png
📒 Files selected for processing (15)
  • apps/api/src/routes/dev-plans.ts
  • apps/api/src/routes/organization.ts
  • apps/api/src/stripe.ts
  • apps/code/src/app/dashboard/components/ResetPassCard.tsx
  • apps/code/src/app/dashboard/components/UsageOverview.tsx
  • apps/code/src/components/Faq.tsx
  • apps/docs/content/learn/model-categories.mdx
  • apps/docs/content/learn/reset-passes.mdx
  • apps/gateway/src/lib/rate-limit.spec.ts
  • apps/ui/src/app/layout.tsx
  • apps/ui/src/content/changelog/2026-07-16-devpass-reset-passes.md
  • packages/db/migrations/1784231994_friendly_phil_sheldon.sql
  • packages/db/migrations/meta/1784231994_snapshot.json
  • packages/db/migrations/meta/_journal.json
  • packages/db/src/schema.ts
💤 Files with no reviewable changes (1)
  • apps/api/src/stripe.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/code/src/components/Faq.tsx
  • apps/docs/content/learn/model-categories.mdx
  • apps/api/src/routes/organization.ts
  • apps/ui/src/content/changelog/2026-07-16-devpass-reset-passes.md

Comment thread apps/api/src/routes/dev-plans.ts Outdated
Comment thread apps/api/src/routes/dev-plans.ts Outdated
Comment thread apps/code/src/app/dashboard/components/UsageOverview.tsx Outdated
Review fixes for PR #3093:

- Purchase fulfilment extracted to fulfillResetPassPurchase and re-run
  from the payment_intent.succeeded webhook as the recovery path, so a
  successful charge can never be lost if the API dies before granting
  the pass. A pg advisory xact lock + payment-intent dedup make the
  synchronous and webhook paths race-safe (exactly one grant per
  charge). Verified live: happy path grants once with the PI recorded.
- Purchase catch now returns 402 only for StripeCardError/card_declined
  (mirroring the tier-change handler) and rethrows everything else.
  Verified live: always-fail test card -> 402 decline message; corrupted
  customer id -> 500 via the global handler, not a fake decline.
- Weekly allowance meter track exposes progressbar semantics (role,
  label, aria-valuenow/min/max); visuals unchanged.

Skipped: persisted purchase-token idempotency keys + orphaned-PI
auto-refunds — webhook redelivery is the repo's established
reconciliation mechanism for every payment flow (top-ups, upgrades,
end-user wallets), and with the recovery branch no succeeded charge
can remain undelivered, so there is no orphan class left to refund.

Claude-Session: https://claude.ai/code/session_01DiqhTuu8Gg6nUXFuaRVUH3

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/api/src/routes/dev-plans.ts (1)

2830-2869: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Require a live subscription before charging. devPlan !== "none" can lag behind Stripe, so this route can still bill the fallback card after the subscription has already ended. Mirror the canceled/incomplete_expired self-heal used elsewhere here, and fail closed instead of swallowing the subscription read error.

🤖 Prompt for 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.

In `@apps/api/src/routes/dev-plans.ts` around lines 2830 - 2869, Update the
payment-method lookup around getStripe().subscriptions.retrieve to require a
live DevPass subscription before charging: detect canceled or incomplete_expired
status, apply the existing canceled/incomplete_expired self-heal used elsewhere,
and stop the request without falling back to the customer card when the
subscription is not active. Do not swallow subscription retrieval errors;
propagate an appropriate failure instead of continuing to charge.

Source: Coding guidelines

🤖 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.

Outside diff comments:
In `@apps/api/src/routes/dev-plans.ts`:
- Around line 2830-2869: Update the payment-method lookup around
getStripe().subscriptions.retrieve to require a live DevPass subscription before
charging: detect canceled or incomplete_expired status, apply the existing
canceled/incomplete_expired self-heal used elsewhere, and stop the request
without falling back to the customer card when the subscription is not active.
Do not swallow subscription retrieval errors; propagate an appropriate failure
instead of continuing to charge.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 05d9a9b9-7a66-4bea-91a5-1c2580c2bf60

📥 Commits

Reviewing files that changed from the base of the PR and between 3f70284 and 51581fb.

📒 Files selected for processing (3)
  • apps/api/src/routes/dev-plans.ts
  • apps/api/src/stripe.ts
  • apps/code/src/app/dashboard/components/UsageOverview.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/code/src/app/dashboard/components/UsageOverview.tsx

smakosh added 4 commits July 17, 2026 16:30
charge.refunded previously ignored dev_plan_reset_pass rows, so a support
refund left the purchased pass usable. Full refunds now remove one
tier-bound pass (clamped at zero when already redeemed) and are excluded
from the full-refund-cancels-subscription branch, which would otherwise
have cancelled the whole DevPass over a pass refund.

Adds 27 edge-case tests covering redeem guards, included-before-purchased
ordering, tier-bound inventory, the CAS redeem race, purchase charging,
declined cards, fulfilment dedup/validation, plan-end lifecycle, refunds,
and the status surface.

Claude-Session: https://claude.ai/code/session_01ALMqWviMXjb4ZA6dXjRcgE
Replaces the visa-stamp passport card with the same slim design language
as the weekly allowance meter: fixed-width stat block, discrete slot strip
at track height, right-aligned actions, tabular numerals, and an inline
'Allowance restored' confirmation instead of the full-card stamp overlay.
Drops the now-unused organizationId prop.

Claude-Session: https://claude.ai/code/session_01ALMqWviMXjb4ZA6dXjRcgE
Retakes the KB and dashboard screenshots for the redesigned Reset Passes
row (light + dark), replaces the broken 40px billing screenshots with real
invoice-history captures, and rewrites the visa-stamp copy in the KB page
and changelog to describe the slot-strip design.

Claude-Session: https://claude.ai/code/session_01ALMqWviMXjb4ZA6dXjRcgE
The stamp animation and visa-extension styling are deliberate DevPass
brand identity, not decoration — restore the stamped card, docs copy, and
changelog wording, and retake the KB screenshots with the stamp design
(the pre-redesign images predated tier-bound stamps and the a11y meter).
Keeps the fixed billing-history screenshots.

Claude-Session: https://claude.ai/code/session_01ALMqWviMXjb4ZA6dXjRcgE

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/api/src/stripe.ts (1)

3244-3310: 🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win

Commit the refund transaction and inventory clawback atomically.

The refund transaction is inserted before the organization's inventory update. If the process crashes between these two writes, a webhook retry will see the existing refund transaction, log "Refund already processed", and return early—permanently failing to claw back the refunded Reset Pass (and similarly failing to deduct credits for top-ups).

Combine the transaction insert and organization update into a single db.transaction(). Additionally, fetch the paymentIntents metadata beforehand to avoid holding the database connection open during the external API call.

🔒️ Proposed fix to ensure atomic refund and clawback execution
-	// Create refund transaction
-	await db.insert(tables.transaction).values({
-		organizationId: originalTransaction.organizationId,
-		type: "credit_refund",
-		amount: refundAmountInDollars.toString(),
-		creditAmount: (-creditRefundAmount).toString(),
-		currency: originalTransaction.currency,
-		status: "completed",
-		stripePaymentIntentId: payment_intent as string,
-		stripeRefundId: latestRefund.id,
-		relatedTransactionId: originalTransaction.id,
-		refundReason: latestRefund.reason ?? null,
-		description: `Credit refund: $${refundAmountInDollars.toFixed(2)} (${(refundRatio * 100).toFixed(1)}% of original purchase)`,
-	});
-
-	// Deduct credits from organization (allow negative) — only for credit_topup
-	// refunds, since dev plan / subscription purchases don't add to credits.
-	if (isCreditTopup && creditRefundAmount !== 0) {
-		await db
-			.update(tables.organization)
-			.set({
-				credits: sql`${tables.organization.credits} - ${creditRefundAmount}`,
-			})
-			.where(eq(tables.organization.id, originalTransaction.organizationId));
-	}
-
-	// A full refund of a Reset Pass claws back one unredeemed pass from the
-	// tier-bound inventory the purchase granted, clamped at zero when the pass
-	// was already redeemed — a refunded purchase must not leave a free pass
-	// behind. The tier comes from the PaymentIntent metadata stamped by the
-	// purchase route.
-	if (originalTransaction.type === "dev_plan_reset_pass" && charge.refunded) {
-		const refundedIntent = await getStripe().paymentIntents.retrieve(
-			payment_intent as string,
-		);
-		const tierValue = refundedIntent.metadata?.devPlan;
-		const tier =
-			tierValue && tierValue in DEV_PLAN_RESET_PASS_PRICES
-				? (tierValue as DevPlanTier)
-				: null;
-		if (!tier) {
-			logger.error(
-				"Refunded Reset Pass has no valid tier in its payment intent metadata",
-				{ paymentIntentId: refundedIntent.id },
-			);
-		} else {
-			const clawback =
-				tier === "lite"
-					? {
-							devPlanResetPassesLite: sql`GREATEST(${tables.organization.devPlanResetPassesLite} - 1, 0)`,
-						}
-					: tier === "pro"
-						? {
-								devPlanResetPassesPro: sql`GREATEST(${tables.organization.devPlanResetPassesPro} - 1, 0)`,
-							}
-						: {
-								devPlanResetPassesMax: sql`GREATEST(${tables.organization.devPlanResetPassesMax} - 1, 0)`,
-							};
-			await db
-				.update(tables.organization)
-				.set(clawback)
-				.where(eq(tables.organization.id, organization.id));
-			logger.info(
-				`Clawed back one ${tier} Reset Pass after full refund for organization ${organization.id}`,
-			);
-		}
-	}
+	// Fetch PaymentIntent metadata for reset pass clawback before the DB transaction
+	// to avoid holding the connection open during Stripe API calls.
+	let clawbackTier: DevPlanTier | null = null;
+	if (originalTransaction.type === "dev_plan_reset_pass" && charge.refunded) {
+		const refundedIntent = await getStripe().paymentIntents.retrieve(
+			payment_intent as string,
+		);
+		const tierValue = refundedIntent.metadata?.devPlan;
+		const tier =
+			tierValue && tierValue in DEV_PLAN_RESET_PASS_PRICES
+				? (tierValue as DevPlanTier)
+				: null;
+		if (!tier) {
+			logger.error(
+				"Refunded Reset Pass has no valid tier in its payment intent metadata",
+				{ paymentIntentId: refundedIntent.id },
+			);
+		} else {
+			clawbackTier = tier;
+		}
+	}
+
+	await db.transaction(async (tx) => {
+		// Create refund transaction
+		await tx.insert(tables.transaction).values({
+			organizationId: originalTransaction.organizationId,
+			type: "credit_refund",
+			amount: refundAmountInDollars.toString(),
+			creditAmount: (-creditRefundAmount).toString(),
+			currency: originalTransaction.currency,
+			status: "completed",
+			stripePaymentIntentId: payment_intent as string,
+			stripeRefundId: latestRefund.id,
+			relatedTransactionId: originalTransaction.id,
+			refundReason: latestRefund.reason ?? null,
+			description: `Credit refund: $${refundAmountInDollars.toFixed(2)} (${(refundRatio * 100).toFixed(1)}% of original purchase)`,
+		});
+
+		// Deduct credits from organization (allow negative) — only for credit_topup
+		// refunds, since dev plan / subscription purchases don't add to credits.
+		if (isCreditTopup && creditRefundAmount !== 0) {
+			await tx
+				.update(tables.organization)
+				.set({
+					credits: sql`${tables.organization.credits} - ${creditRefundAmount}`,
+				})
+				.where(eq(tables.organization.id, originalTransaction.organizationId));
+		}
+
+		// A full refund of a Reset Pass claws back one unredeemed pass from the
+		// tier-bound inventory the purchase granted, clamped at zero when the pass
+		// was already redeemed — a refunded purchase must not leave a free pass
+		// behind.
+		if (clawbackTier) {
+			const clawback =
+				clawbackTier === "lite"
+					? { devPlanResetPassesLite: sql`GREATEST(${tables.organization.devPlanResetPassesLite} - 1, 0)` }
+					: clawbackTier === "pro"
+						? { devPlanResetPassesPro: sql`GREATEST(${tables.organization.devPlanResetPassesPro} - 1, 0)` }
+						: { devPlanResetPassesMax: sql`GREATEST(${tables.organization.devPlanResetPassesMax} - 1, 0)` };
+			await tx
+				.update(tables.organization)
+				.set(clawback)
+				.where(eq(tables.organization.id, organization.id));
+		}
+	});
+
+	if (clawbackTier) {
+		logger.info(
+			`Clawed back one ${clawbackTier} Reset Pass after full refund for organization ${organization.id}`,
+		);
+	}
🤖 Prompt for 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.

In `@apps/api/src/stripe.ts` around lines 3244 - 3310, Wrap the refund transaction
insert and the related organization credit or Reset Pass inventory update in one
db.transaction() so either all writes commit or none do, preserving webhook
retry safety. In the refund handler, retrieve the payment intent metadata before
starting the database transaction, then reuse it in the dev_plan_reset_pass
clawback logic instead of calling getStripe().paymentIntents.retrieve inside the
transaction. Keep the existing tier validation and update behavior unchanged.
🧹 Nitpick comments (2)
apps/api/src/routes/dev-plans-reset-passes.spec.ts (2)

606-633: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Verify full-refund webhook idempotency.

Redeliver the same refund event in this test. Otherwise, a regression could decrement another purchased pass when Stripe retries the webhook.

Proposed test extension
 	await handleChargeRefunded(chargeRefundedEvent("pi_refund_full"));
+	await handleChargeRefunded(chargeRefundedEvent("pi_refund_full"));
 
 	const org = await getOrg();
 	expect(org.devPlanResetPassesPro).toBe(1);
🤖 Prompt for 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.

In `@apps/api/src/routes/dev-plans-reset-passes.spec.ts` around lines 606 - 633,
The full-refund test around handleChargeRefunded lacks a webhook retry
assertion. Invoke handleChargeRefunded again with the same chargeRefundedEvent
after the initial handling, then verify the organization still has one remaining
dev plan reset pass and only one credit_refund row, confirming duplicate
delivery does not reclaim another pass.

337-379: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Add purchase-specific authentication tests.

The redeem tests do not protect the separate purchase endpoint from regressions. Add unauthenticated and unverified-email cases asserting that Stripe is never called.

Proposed tests
 describe("reset pass purchase", () => {
 	let token: string;
 
+	it("rejects unauthenticated requests", async () => {
+		await insertOrg();
+		const res = await purchaseRequest();
+		expect(res.status).toBe(401);
+		expect(stripeMock.paymentIntents.create).not.toHaveBeenCalled();
+	});
+
+	it("rejects users without a verified email", async () => {
+		await insertOrg();
+		await db
+			.update(tables.user)
+			.set({ emailVerified: false })
+			.where(eq(tables.user.id, "test-user-id"));
+
+		const res = await purchaseRequest(token);
+		expect(res.status).toBe(403);
+		expect(stripeMock.paymentIntents.create).not.toHaveBeenCalled();
+	});
+
 	it("rejects purchase without an active dev plan", async () => {

As per coding guidelines, “API endpoints must independently verify authentication, email verification, and permissions rather than relying on UI-only gates or request-body identity fields.”

🤖 Prompt for 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.

In `@apps/api/src/routes/dev-plans-reset-passes.spec.ts` around lines 337 - 379,
Add purchase-specific authentication coverage within the “reset pass purchase”
suite: add unauthenticated and unverified-email requests to the purchase
endpoint, assert each is rejected, and verify stripeMock.paymentIntents.create
is never called. Reuse the existing purchaseRequest and test-user setup helpers
while keeping the current active-plan permission test unchanged.

Source: Coding guidelines

🤖 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.

Outside diff comments:
In `@apps/api/src/stripe.ts`:
- Around line 3244-3310: Wrap the refund transaction insert and the related
organization credit or Reset Pass inventory update in one db.transaction() so
either all writes commit or none do, preserving webhook retry safety. In the
refund handler, retrieve the payment intent metadata before starting the
database transaction, then reuse it in the dev_plan_reset_pass clawback logic
instead of calling getStripe().paymentIntents.retrieve inside the transaction.
Keep the existing tier validation and update behavior unchanged.

---

Nitpick comments:
In `@apps/api/src/routes/dev-plans-reset-passes.spec.ts`:
- Around line 606-633: The full-refund test around handleChargeRefunded lacks a
webhook retry assertion. Invoke handleChargeRefunded again with the same
chargeRefundedEvent after the initial handling, then verify the organization
still has one remaining dev plan reset pass and only one credit_refund row,
confirming duplicate delivery does not reclaim another pass.
- Around line 337-379: Add purchase-specific authentication coverage within the
“reset pass purchase” suite: add unauthenticated and unverified-email requests
to the purchase endpoint, assert each is rejected, and verify
stripeMock.paymentIntents.create is never called. Reuse the existing
purchaseRequest and test-user setup helpers while keeping the current
active-plan permission test unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e9978789-1922-4cfa-b8ff-9969e5a9ad5c

📥 Commits

Reviewing files that changed from the base of the PR and between 51581fb and e7d992c.

⛔ Files ignored due to path filters (6)
  • apps/docs/public/learn/dashboard-dark.png is excluded by !**/*.png
  • apps/docs/public/learn/dashboard-light.png is excluded by !**/*.png
  • apps/docs/public/learn/reset-passes-billing-dark.png is excluded by !**/*.png
  • apps/docs/public/learn/reset-passes-billing-light.png is excluded by !**/*.png
  • apps/docs/public/learn/reset-passes-dark.png is excluded by !**/*.png
  • apps/docs/public/learn/reset-passes-light.png is excluded by !**/*.png
📒 Files selected for processing (2)
  • apps/api/src/routes/dev-plans-reset-passes.spec.ts
  • apps/api/src/stripe.ts

…sses

# Conflicts:
#	apps/api/src/routes/dev-plans.ts
#	packages/db/migrations/meta/_journal.json
@steebchen

Copy link
Copy Markdown
Member

Images automagically compressed by Calibre's image-actions ✨

Compression reduced images by 68.1%, saving 573.6 KB.

Filename Before After Improvement Visual comparison
apps/docs/public/learn/dashboard-dark.png 340.6 KB 101.6 KB 70.2% View diff
apps/docs/public/learn/dashboard-light.png 317.2 KB 113.1 KB 64.4% View diff
apps/docs/public/learn/reset-passes-dark.png 59.8 KB 17.1 KB 71.4% View diff
apps/docs/public/learn/reset-passes-light.png 58.5 KB 17.5 KB 70.0% View diff
apps/docs/public/learn/reset-passes-billing-light.png 33.3 KB 9.8 KB 70.5% View diff
apps/docs/public/learn/reset-passes-billing-dark.png 33.5 KB 10.1 KB 69.8% View diff

6 images did not require optimisation.

@steebchen

Copy link
Copy Markdown
Member

Images automagically compressed by Calibre's image-actions ✨

Compression reduced images by 6.4%, saving 2.9 KB.

Filename Before After Improvement Visual comparison
apps/docs/public/learn/reset-passes-light.png 17.5 KB 16.3 KB 7.1% View diff
apps/docs/public/learn/reset-passes-dark.png 17.1 KB 16.0 KB 6.3% View diff
apps/docs/public/learn/reset-passes-billing-dark.png 10.1 KB 9.6 KB 5.2% View diff

9 images did not require optimisation.

@steebchen

Copy link
Copy Markdown
Member

Images automagically compressed by Calibre's image-actions ✨

Compression reduced images by 5.6%, saving 914 B.

Filename Before After Improvement Visual comparison
apps/docs/public/learn/reset-passes-dark.png 16.0 KB 15.1 KB 5.6% View diff

11 images did not require optimisation.

Swap the monthly credits bar to show spent-of-limit as the primary
figure with remaining as the secondary, matching the weekly premium
meter which leads with amount spent.
@steebchen
steebchen merged commit bee4ae8 into main Jul 17, 2026
22 of 23 checks passed
@steebchen
steebchen deleted the feat/devpass-reset-passes branch July 17, 2026 18:11
pull Bot pushed a commit to soitun/llmgateway that referenced this pull request Jul 18, 2026
## Summary

Reset Pass purchases (theopenco#3093) were the only paid flow with no internal
Discord notification — credits, DevPass/chat plan
subscribe/renew/cancel, and refunds all post to the billing channel, and
a *refunded* Reset Pass already notified via the generic refund handler.
This closes that gap.

- Add `notifyResetPassPurchased` to `apps/api/src/utils/discord.ts`
(email, name, tier, amount — same embed pattern as the other purchase
notifiers, posts to `DISCORD_NOTIFICATION_URL`)
- Call it from `fulfillResetPassPurchase` after the payment-intent
dedupe guard, so the synchronous purchase route and the
`payment_intent.succeeded` recovery webhook can't double-notify
- Resolves the recipient from `organization.billingEmail` + user lookup,
mirroring the refund notification path

## Test plan

- `pnpm exec turbo run build --filter=api` passes
- Notification is best-effort: `sendDiscordNotification` already
swallows webhook failures and skips when `DISCORD_NOTIFICATION_URL` is
unset, so fulfilment is unaffected either way

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Improvements**
* Improved handling of reset pass purchases to ensure completed
transactions are recorded reliably.
* Added more detailed purchase information to internal notifications,
including the purchaser’s email, name, selected tier, and payment
amount.
* Duplicate purchase fulfillment remains prevented, and notification
failures do not interrupt payment processing.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
pull Bot pushed a commit to soitun/llmgateway that referenced this pull request Aug 5, 2026
## Problem

The July traffic report showed revenue concentrating in two places we
under-serve:

1. **The DevPass dashboard is the #1 converting surface** (354 payers
last month), and Reset Passes sold 42 units in month one with zero
targeting — but the agreed follow-up from theopenco#3093 (a real cap-hit
analytics event) never shipped, and the dashboard shows the same
ResetPassCard at 0% and 100% usage. No contextual offer exists at the
moment of highest intent.
2. **Compliance content converts payers at ~5%** (soc2-type-ii: 158
readers → 8 payers) but enterprise leads are flat at 4/month — the post
never presents the enterprise path. Meanwhile the weekly report shows
organic momentum fading, with the proven "[X] alternatives" and Kimi K3
playbooks sitting unshipped.

## What this ships

### DevPass: cap-hit funnel + contextual offer

- **`devpass_premium_cap_rejected`** captured server-side in the gateway
when the weekly premium-cap 402 fires
(`assertDevPlanPremiumCapNotExceeded`), with `devPlan`, `model`,
`msUntilReset`, and org group. This is the follow-up agreed in theopenco#3093:
`devpass_weekly_cap_hit_viewed` only counts users who open the
dashboard, but most cap hits happen inside coding agents that swallow
the 402 — demand was undercounted. Adds a `posthog-node` client to
`apps/gateway` (mirrors `apps/api/src/posthog.ts`; disabled without env,
no hot-path cost).
- **`CapHitResetOfferDialog`** on the DevPass dashboard: a visa-stamp
dialog (border-control stamp, MRZ strip — house DevPass brand) that
appears the moment the weekly premium cap is hit, driven by the existing
5s status poll. It mirrors the server's purchase/redeem gates (never
offers an action the API would 400), stays quiet when the monthly pool
is exhausted (that state belongs to `AllowanceExhaustedCard`), snoozes
per cap-window via cookie, and emits
`devpass_cap_hit_offer_shown/dismissed/clicked`. The CTA scrolls to the
ResetPassCard rather than duplicating the purchase surface.
- **`/ingest` PostHog proxy for `apps/code`** (mirroring apps/ui and
apps/playground) — DevPass dashboard events were ad-blocker-droppable
until now, so July's 500 cap-hit views were an undercount. Expect an
event step-up after deploy.

<img width="1080" alt="Cap-hit Reset Pass offer demo: dialog appears at
100% weekly usage, CTA scrolls to the ResetPassCard, redeem restores the
allowance"
src="https://raw.githubusercontent.com/theopenco/llmgateway/cc22b375431e6148e4889e403c4635327095fc0c/cap-hit-reset-pass-demo.gif"
/>

([MP4
version](https://raw.githubusercontent.com/theopenco/llmgateway/cc22b375431e6148e4889e403c4635327095fc0c/cap-hit-reset-pass-demo.mp4))

### Compliance/enterprise content cluster

- `soc2-type-ii` gains a **provider compliance policies** section (the
theopenco#3339 policy-aware picker, fail-closed requirements, 403-before-egress),
a proper enterprise CTA block, and links into the new cluster.
- Three sibling posts feeding the same funnel: **`llm-data-retention`**,
**`gdpr-compliant-llm-routing`**, and **`llm-compliance-checklist`** —
all fact-checked against
`apps/docs/content/features/{data-retention,compliance}.mdx` and the
routing docs (region example uses a real catalogue mapping,
`aws-bedrock/claude-sonnet-4-6:eu-west-2`).
- New **`BlogCta variant="enterprise"`** (→ `/enterprise#contact` +
`/enterprise/compliance`) used by all three.

### Organic pipeline refill

- **`portkey-alternatives`** and **`helicone-alternatives`** listicles —
the two SERP gaps left open after the litellm/openrouter/copilot
listicles proved the pattern. Facts per the verified June-2026
competitor landscape (Portkey→Palo Alto/Prisma AIRS; Helicone→Mintlify
maintenance mode; Langfuse/LangSmith claims re-verified this week).
Internal links added from `/compare/portkey`, the vs-Portkey post,
best-ai-gateways, and both existing listicles' "skip" sections.
- **Kimi K3 spokes**: `kimi-k3-open-weights` (weights shipped Jul 26 on
HF under a custom **"Kimi K3 License"** — not the Modified MIT press
predicted, so the post and pillar deliberately point at the LICENSE file
instead of summarizing terms) and `kimi-k3-api` (the "kimi k3 api"
query; reasoning_effort semantics, cached-input economics, sticky
sessions). Pillar updated: weights-release facts corrected, spokes
interlinked.
- **`/rankings` interlinks** from the `/models` SEO copy and `llms.txt`
(it had no entry there).
- 7 OG images generated in the house circuit-board style with the
composited wordmark.

## Verification

- `pnpm format`, full `pnpm build`, and `dev-plans-reset-passes.spec.ts`
(32/32) pass.
- Demo recorded against the local stack with the real seed org: staged
cap-hit via SQL (millisecond-truncated `dev_plan_premium_week_start` for
the CAS), dialog fired, CTA scrolled to the card, redeem zeroed
`devPlanPremiumCreditsUsed` and consumed the included pass server-side.

## Notes for review / follow-ups

- The census dialog and the new cap-hit dialog can theoretically stack
(both Radix dialogs; census mounts globally, cap-hit on the main
dashboard page). In the wild both firing together should be rare; if we
care, a simple priority gate in `DashboardShell` would fix it.
- The premium-cap 402 still has no machine-readable `code`
distinguishing it from out-of-credits — agents can't react
programmatically. Left out deliberately (error-shape compatibility);
worth its own PR.
- Blog listicles ship FAQ sections but blog posts emit no FAQPage
JSON-LD (model pages do). Separate SEO follow-up.
- dev.to syndication for the new listicles is intentionally not part of
this PR (staggering per the syndication policy).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_018NeUff4XEsqAVuJRZ8KuvS

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added a dashboard offer for eligible users who exhaust weekly premium
usage, including reset-pass redemption and purchase options.
- Added links to live model rankings and expanded enterprise compliance
calls to action.
- Added guidance for Kimi K3, GDPR-compliant routing, LLM compliance,
data retention, and gateway alternatives.

- **Documentation**
- Updated model, compliance, licensing, and comparison content with new
articles, refreshed links, and recommendations.

- **Bug Fixes**
- Improved analytics loading, routing reliability, and shutdown
handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Luca Steeb <contact@luca-steeb.com>
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